diff --git a/develop_test/02_demos_tutorials_workflows/02_user_demos/05_advanced_user_guide/images/Input_ID_name.png b/develop_test/02_demos_tutorials_workflows/02_user_demos/05_advanced_user_guide/images/Input_ID_name.png deleted file mode 100644 index 522387163..000000000 Binary files a/develop_test/02_demos_tutorials_workflows/02_user_demos/05_advanced_user_guide/images/Input_ID_name.png and /dev/null differ diff --git a/develop_test/02_demos_tutorials_workflows/02_user_demos/05_advanced_user_guide/images/data-ingest/D1Ingest-1.gif b/develop_test/02_demos_tutorials_workflows/02_user_demos/05_advanced_user_guide/images/data-ingest/D1Ingest-1.gif deleted file mode 100644 index ee022c53a..000000000 Binary files a/develop_test/02_demos_tutorials_workflows/02_user_demos/05_advanced_user_guide/images/data-ingest/D1Ingest-1.gif and /dev/null differ diff --git a/develop_test/02_demos_tutorials_workflows/02_user_demos/05_advanced_user_guide/images/data-ingest/D1Ingest-9_sm.gif b/develop_test/02_demos_tutorials_workflows/02_user_demos/05_advanced_user_guide/images/data-ingest/D1Ingest-9_sm.gif deleted file mode 100644 index ffc950afa..000000000 Binary files a/develop_test/02_demos_tutorials_workflows/02_user_demos/05_advanced_user_guide/images/data-ingest/D1Ingest-9_sm.gif and /dev/null differ diff --git a/develop_test/02_demos_tutorials_workflows/02_user_demos/05_advanced_user_guide/images/data-ingest/DateTime.gif b/develop_test/02_demos_tutorials_workflows/02_user_demos/05_advanced_user_guide/images/data-ingest/DateTime.gif deleted file mode 100644 index a6c14005b..000000000 Binary files a/develop_test/02_demos_tutorials_workflows/02_user_demos/05_advanced_user_guide/images/data-ingest/DateTime.gif and /dev/null differ diff --git a/develop_test/02_demos_tutorials_workflows/02_user_demos/05_advanced_user_guide/images/data-ingest/Local_loader_sm.gif b/develop_test/02_demos_tutorials_workflows/02_user_demos/05_advanced_user_guide/images/data-ingest/Local_loader_sm.gif deleted file mode 100644 index 33f248ec2..000000000 Binary files a/develop_test/02_demos_tutorials_workflows/02_user_demos/05_advanced_user_guide/images/data-ingest/Local_loader_sm.gif and /dev/null differ diff --git a/develop_test/02_demos_tutorials_workflows/02_user_demos/05_advanced_user_guide/images/data-ingest/Selectize_Input_sm.gif b/develop_test/02_demos_tutorials_workflows/02_user_demos/05_advanced_user_guide/images/data-ingest/Selectize_Input_sm.gif deleted file mode 100644 index e5c0a3786..000000000 Binary files a/develop_test/02_demos_tutorials_workflows/02_user_demos/05_advanced_user_guide/images/data-ingest/Selectize_Input_sm.gif and /dev/null differ diff --git a/develop_test/02_demos_tutorials_workflows/02_user_demos/05_advanced_user_guide/images/data-ingest/local_browse.gif b/develop_test/02_demos_tutorials_workflows/02_user_demos/05_advanced_user_guide/images/data-ingest/local_browse.gif deleted file mode 100644 index 6f2cff7c1..000000000 Binary files a/develop_test/02_demos_tutorials_workflows/02_user_demos/05_advanced_user_guide/images/data-ingest/local_browse.gif and /dev/null differ diff --git a/develop_test/02_demos_tutorials_workflows/02_user_demos/05_advanced_user_guide/images/data-ingest/new_format_record.gif b/develop_test/02_demos_tutorials_workflows/02_user_demos/05_advanced_user_guide/images/data-ingest/new_format_record.gif deleted file mode 100644 index 53e7b0de2..000000000 Binary files a/develop_test/02_demos_tutorials_workflows/02_user_demos/05_advanced_user_guide/images/data-ingest/new_format_record.gif and /dev/null differ diff --git a/develop_test/02_demos_tutorials_workflows/02_user_demos/05_advanced_user_guide/images/example_data.png b/develop_test/02_demos_tutorials_workflows/02_user_demos/05_advanced_user_guide/images/example_data.png deleted file mode 100644 index 7677021d1..000000000 Binary files a/develop_test/02_demos_tutorials_workflows/02_user_demos/05_advanced_user_guide/images/example_data.png and /dev/null differ diff --git a/develop_test/02_demos_tutorials_workflows/02_user_demos/05_advanced_user_guide/images/format_record_1.png b/develop_test/02_demos_tutorials_workflows/02_user_demos/05_advanced_user_guide/images/format_record_1.png deleted file mode 100644 index edea276a9..000000000 Binary files a/develop_test/02_demos_tutorials_workflows/02_user_demos/05_advanced_user_guide/images/format_record_1.png and /dev/null differ diff --git a/develop_test/02_demos_tutorials_workflows/02_user_demos/05_advanced_user_guide/images/format_record_2.png b/develop_test/02_demos_tutorials_workflows/02_user_demos/05_advanced_user_guide/images/format_record_2.png deleted file mode 100644 index f3362db18..000000000 Binary files a/develop_test/02_demos_tutorials_workflows/02_user_demos/05_advanced_user_guide/images/format_record_2.png and /dev/null differ diff --git a/develop_test/03_topical_pages/11_images/bety_main_page.png b/develop_test/03_topical_pages/11_images/bety_main_page.png deleted file mode 100644 index 5b268b414..000000000 Binary files a/develop_test/03_topical_pages/11_images/bety_main_page.png and /dev/null differ diff --git a/develop_test/03_topical_pages/11_images/bety_modeltype_1.png b/develop_test/03_topical_pages/11_images/bety_modeltype_1.png deleted file mode 100644 index cec1a21ff..000000000 Binary files a/develop_test/03_topical_pages/11_images/bety_modeltype_1.png and /dev/null differ diff --git a/develop_test/03_topical_pages/11_images/bety_modeltype_2.png b/develop_test/03_topical_pages/11_images/bety_modeltype_2.png deleted file mode 100644 index fd3fbb516..000000000 Binary files a/develop_test/03_topical_pages/11_images/bety_modeltype_2.png and /dev/null differ diff --git a/develop_test/03_topical_pages/11_images/bety_pft_1.png b/develop_test/03_topical_pages/11_images/bety_pft_1.png deleted file mode 100644 index a5226b4b9..000000000 Binary files a/develop_test/03_topical_pages/11_images/bety_pft_1.png and /dev/null differ diff --git a/develop_test/03_topical_pages/11_images/bety_pft_2.png b/develop_test/03_topical_pages/11_images/bety_pft_2.png deleted file mode 100644 index 705fc5d0b..000000000 Binary files a/develop_test/03_topical_pages/11_images/bety_pft_2.png and /dev/null differ diff --git a/develop_test/03_topical_pages/11_images/bety_pft_3.png b/develop_test/03_topical_pages/11_images/bety_pft_3.png deleted file mode 100644 index b09ce8708..000000000 Binary files a/develop_test/03_topical_pages/11_images/bety_pft_3.png and /dev/null differ diff --git a/develop_test/03_topical_pages/11_images/bety_priors_1.png b/develop_test/03_topical_pages/11_images/bety_priors_1.png deleted file mode 100644 index 0202d4b49..000000000 Binary files a/develop_test/03_topical_pages/11_images/bety_priors_1.png and /dev/null differ diff --git a/develop_test/03_topical_pages/11_images/bety_priors_2.png b/develop_test/03_topical_pages/11_images/bety_priors_2.png deleted file mode 100644 index bef439213..000000000 Binary files a/develop_test/03_topical_pages/11_images/bety_priors_2.png and /dev/null differ diff --git a/develop_test/03_topical_pages/11_images/bety_priors_3.png b/develop_test/03_topical_pages/11_images/bety_priors_3.png deleted file mode 100644 index f9241fe70..000000000 Binary files a/develop_test/03_topical_pages/11_images/bety_priors_3.png and /dev/null differ diff --git a/develop_test/03_topical_pages/11_images/bety_priors_4.png b/develop_test/03_topical_pages/11_images/bety_priors_4.png deleted file mode 100644 index c7a9109ba..000000000 Binary files a/develop_test/03_topical_pages/11_images/bety_priors_4.png and /dev/null differ diff --git a/develop_test/03_topical_pages/11_images/bety_priors_5.png b/develop_test/03_topical_pages/11_images/bety_priors_5.png deleted file mode 100644 index 67f5d8e78..000000000 Binary files a/develop_test/03_topical_pages/11_images/bety_priors_5.png and /dev/null differ diff --git a/develop_test/03_topical_pages/94_docker/pecan-docker.png b/develop_test/03_topical_pages/94_docker/pecan-docker.png deleted file mode 100644 index eb44a8928..000000000 Binary files a/develop_test/03_topical_pages/94_docker/pecan-docker.png and /dev/null differ diff --git a/develop_test/about-the-pecan-book.html b/develop_test/about-the-pecan-book.html deleted file mode 100644 index f108f2d9b..000000000 --- a/develop_test/about-the-pecan-book.html +++ /dev/null @@ -1,811 +0,0 @@ - - - - - - - 3 About the PEcAn Book | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

3 About the PEcAn Book

-

This book serves as documentation for the PEcAn Project. It contains descriptions of topics necessary to inform a beginner and advanced user as well as requisite materials for developers. It does not contain low-level descriptions of functions within PEcAn. Our aim for this documentation is to educate you about the PEcAn software, the possibilities of its usage, and the standards,expectations, and core workflows for developers.

-

This book is organized four main topics:

-

Introduction - Brief explanation of PEcAn, how to obtain the PEcAn VM, and explanation of basic web interface functions.

-

Tutorials/Demos/Workflows - All User and Developer tutorials/demos/workflows to explain how to use and add to PEcAn in different ways.

-

Topical Pages - Explanation of main PEcAn components and how they fit together.

-

Appendix - External documentation and sources of information and a FAQ section.

-
-

3.1 General Feedback/Comments/Suggestions

-

We want your ideas, thoughts, comments, and suggestions! As a community we are committed to creating an inclusive and supportive atmosphere so we all to reach out to us in the following ways:

-

Github: https://github.com/PecanProject/pecan -This is the main hub of communication surrounding PEcAn development. Check out the issues section to see known bugs, upcoming features, and ideas for future development. Feel free to comment on existing issues or open new ones with questions, bug reports, feature requests, and/or ideas.

-

Slack: https://pecanproject.slack.com/ -Slack serves as our day to day mode of communication. To join us in slack you will need to create an account first. This is done in 3 steps:

-
    -
  1. Request an inivitation to join Slack, this will be send by email to address you provided.
  2. -
  3. Check your inbox for an email from Slack with subject “Rob Kooper has invited you to join a Slack workspace”. This email should have a link that you can click to join slack.
  4. -
  5. When you click a webpage will open up that asks you to create an account, once that is done you can login into the slack chatrooms.
  6. -
-

Email: pecanproj[at]gmail.com -If you do not wish your communication with the team to be public, send us an email at the address above and we will get back to you as soon as possible.

-
-
-

3.2 Editing this book

-

The file organization of this documentation can be described simply as follows:

-
    -
  • Each chapter is in its own file (within the corresponding section).
  • -
  • Each group of chapters (i.e. “part” in LaTeX) is in its own directory.
  • -
-

Sections and chapters are rendered (and numbered) in alpha-numerical order of their corresponding file names. -Therefore, each section directory and chapter file name should be prefixed with a two-digit (zero-padded) number. -File and directory names should be as similar as possible to the name of the corresponding chapter or section. -For instance, the file name for this chapter’s source file is 06_reference/10_editing_this_book.Rmd. -This numbering means that if you need to create an additional chapter before an existing one, you will have to renumber all chapters following it.

-

To ensure correct rendering, you should also make sure that each chapter starts with a level 1 heading (# heading). -For instance, this chapter’s source starts with:

- -

Furthermore, to keep the organization consistent, each chapter should have exactly one level 1 heading (i.e. do not combine multiple chapters into a single file). -In other words, do not spread a single chapter across multiple files, and do not put multiple chapters in the same file.

-

Each section directory has a file starting with 00 that contains only the section (or “Part”) title. -This is used to create the greyed-out section headers in the rendered HTML. -For instance, this section has a file called 00_introduction.Rmd which contains only the following:

- -

To cross-reference a different section, use that section’s unique tag (starts with #; appears next to the section heading surrounded in curly braces). -For instance, the following Markdown contains two sections that cross-reference each other:

- -

If no header tag exists for a section you want to cross-reference, you should create one. -We have no strict rules about this, but it’s useful to have tags that give some sense of their parent hierarchy and reference their parent sections (e.g. #models, #models-ed, and #models-ed-xml to refer to a chapter on models, with a subsection on ED and a sub-subsection on ED XML configuration). -If section organization changes, it is fine to move header tags, but avoid altering existing tags as this will break all the links pointing to that tag. -(Note that it is also possible to link to section headings by their exact title. However, this is not recommended because these section titles could change, which would break the links.)

-

When referring to PEcAn packages or specific functions, it is a good idea to link to the rendered package documentation. -For instance, here are links to the models/ed package, the PEcAn.ED2::modify_ed2in function, and the PEcAnRTM package vignette. -If necessary, you can also link directly to specific lines or blocks in the source code on GitHub, like this. -(To get a link to a line, click its line number. To then select a block, shift-click another line number.)

-

To insert figures, use knitr::include_graphics("path/to/figure.png") inside an R code chunk. -For example:

-
```{r}
-knitr::include_graphics("04_advanced_user_guide/images/Input_ID_name.png")
-```
-

Note that image file names are relative to the book_source directory, NOT to the markdown file. -In other words, if myimage.png was in the same directory as this file, I would still have to reference it as 06_reference/myimage.png – I could not just do myimage.png. -The size, caption, and other properties of the rendered image can be controlled via chunk options.

-

For additional information about how bookdown works (including information about its syntax), see the Bookdown free online book.

-
-
-

3.3 How to create your own version of Documentation

-

To create your own version of documentation you’ll need to follow these steps: -These procedures assume you have an github account, you forked pecan, you have cloned pecan locally, and have a TRAVIS account. -1. Create a repository under your github account with the name “pecan-documentation”. Clear it of any files. Set up the repository with Github Pages by going to the settings tab for that repository. -2. Create a personal access token for github: https://help.github.com/en/articles/creating-a-personal-access-token-for-the-command-line and copy it. -3. Create a TRAVIS environment variable called GITHUB_PAT and save the access token you made as a secret variable. -4. Create a branch from your local pecan repository with a name that starts with release/. (ie. Release/vtonydoc) -5. Make whichever changes you would like to the documentation and push it up to your fork.

-

From here TRAVIS will build your documentation. The web version of your documentation will be rendered with the url following the structure: username.github.io/pecan-documentation/pattern_after_release/

- -
-
- - - -
- - -
-
-
- - -
- - - - - - - - - - - - - - - - - diff --git a/develop_test/adding-to-pecan.html b/develop_test/adding-to-pecan.html deleted file mode 100644 index f8fd4d11f..000000000 --- a/develop_test/adding-to-pecan.html +++ /dev/null @@ -1,1462 +0,0 @@ - - - - - - - 19 Adding to PEcAn | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

19 Adding to PEcAn

-
    -
  • Case studies -
  • -
  • Reference (How to edit records in bety) -
      -
    • Models
    • -
    • Species
    • -
    • PFTs
    • -
    • Traits
    • -
    • Inputs
    • -
    • DB files
    • -
    • Variables
    • -
    • Formats
    • -
    • (Link each section to relevant Bety tables)
    • -
  • -
-
-

19.1 Adding An Ecosystem Model

-

Adding a model to PEcAn involves two activities:

-
    -
  1. Updating the PEcAn database to register the model
  2. -
  3. Writing the interface modules between the model and PEcAn
  4. -
-

Note that coupling a model to PEcAn should not require any changes to the model code itself. A key aspect of our design philosophy is that we want it to be easy to add models to the system and we want to using the working version of the code that is used by all other model users, not a special branch (which would rapidly end up out-of-date).

-
-

19.1.1 Using PEcAn Database

-

To run a model within PEcAn requires that the PEcAn database has sufficient information about the model. This includes a MODEL_TYPE designation, the types of inputs the model requires, the location of the model executable, and the plant functional types used by the model.

-

The instructions in this section assume that you will be specifying this information using the BETYdb web-based interface. This can be done either on your local VM (localhost:3280/bety or localhost:6480/bety) or on a server installation of BETYdb. However you interact with BETYdb, we encourage you to set up your PEcAn instance to support database syncs so that these changes can be shared and backed-up across the PEcAn network.

-

-

The figure below summarizes the relevant database tables that need to be updated to add a new model and the primary variables that define each table.

-

-
-
-

19.1.2 Define MODEL_TYPE

-

The first step to adding a model is to create a new MODEL_TYPE, which defines the abstract model class. This MODEL_TYPE is used to specify input requirements, define plant functional types, and keep track of different model versions.

-

The MODEL_TYPE is created by selecting Runs > Model Type and then clicking on New Model Type. The MODEL_TYPE name should be identical to the MODEL package name (see Interface Module below) and is case sensitive.

-

-

-
-
-

19.1.3 MACHINE

-

The PEcAn design acknowledges that the same model executables and input files may exist on multiple computers. Therefore, we need to define the machine that that we are using. If you are running on the VM then the local machine is already defined as pecan. Otherwise, you will need to select Runs > Machines, click New Machine, and enter the URL of your server (e.g. pecan2.bu.edu).

-
-
-

19.1.4 MODEL

-

Next we are going to tell PEcAn where the model executable is. Select Runs > Files, and click ADD. Use the pull down menu to specify the machine you just defined above and fill in the path and name for the executable. For example, if SIPNET is installed at /usr/local/bin/sipnet then the path is /usr/local/bin/ and the file (executable) is sipnet.

-

Now we will create the model record and associate this with the File we just registered. The first time you do this select Runs > Models and click New Model. Specify a descriptive name of the model (which doesn’t have to be the same as MODEL_TYPE), select the MODEL_TYPE from the pull down, and provide a revision identifier for the model (e.g. v3.2.1). Once the record is created select it from the Models table and click EDIT RECORD. Click on “View Related Files” and when the search window appears search for the model executable you just added (if you are unsure which file to choose you can go back to the Files menu and look up the unique ID number). You can then associate this Model record with the File by clicking on the +/- symbol. By contrast, clicking on the name itself will take you to the File record.

-

In the future, if you set up the SAME MODEL VERSION on a different computer you can add that Machine and File to PEcAn and then associate this new File with this same Model record. A single version of a model should only be entered into PEcAn once.

-

If a new version of the model is developed that is derived from the current version you should add this as a new Model record but with the same MODEL_TYPE as the original. Furthermore, you should set the previous version of the model as Parent of this new version.

-
-
-

19.1.5 FORMATS

-

The PEcAn database keep track of all the input files passed to models, as well as any data used in model validation or data assimilation. Before we start to register these files with PEcAn we need to define the format these files will be in. To create a new format see Formats Documentation.

-
-
-

19.1.6 MODEL_TYPE -> Formats

-

For each of the input formats you specify for your model, you will need to edit your MODEL_TYPE record to add an association between the format and the MODEL_TYPE. Go to Runs > Model Type, select your record and click on the Edit button. Next, click on “Edit Associated Formats” and choose the Format you just defined from the pull down menu. If the Input box is checked then all matching Input records will be displayed in the PEcAn site run selection page when you are defining a model run. In other words, the set of model inputs available through the PEcAn web interface is model-specific and dynamically generated from the associations between MODEL_TYPEs and Formats. If you also check the Required box, then the Input will be treated as required and PEcAn will not run the model if that input is not available. Furthermore, on the site selection webpage, PEcAn will filter the available sites and only display pins on the Google Map for sites that have a full set of required inputs (or where those inputs could be generated using PEcAn’s workflows). Similarly, to make a site appear on the Google Map, all you need to do is specify Inputs, as described in the next section, and the point should automatically appear on the map.

-
-
-

19.1.7 INPUTS

-

After a file Format has been created then input files can be registered with the database. Creating Inputs can be found under How to insert new Input data.

-
-
-

19.1.8 Add Plant Functional Types (PFTs)

-

Since many of the PEcAn tools are designed to keep track of parameter uncertainties and assimilate data into models, to use PEcAn with a model it is important to define Plant Functional Types for the sites or regions that you will be running the model.

-

Create a new PFT entry by selecting Data > PFTs and then clicking on New PFT.

-

-

-

Give the PFT a descriptive name (e.g., temperate deciduous). PFTs are MODEL_TYPE specific, so choose your MODEL_TYPE from the pull down menu.

-

-
-

19.1.8.1 Species

-

Within PEcAn there are no predefined PFTs and user can create new PFTs very easily at whatever taxonomic level is most appropriate, from PFTs for individual species up to one PFT for all plants globally. To allow PEcAn to query its trait database for information about a PFT, you will want to associate species with the PFT record by choosing Edit and then “View Related Species”. Species can be searched for by common or scientific name and then added to a PFT using the +/- button.

-
-
-

19.1.8.2 Cultivars

-

You can also define PFTs whose members are cultivars instead of species. This is designed for analyses where you want to want to perform meta-analysis on within-species comparisons (e.g. cultivar evaluation in an agricultural model) but may be useful for other cases when you want to specify different priors for some member of a species. You cannot associate both species and cultivars with the same PFT, but the cultivars in a cultivar PFT may come from different species, potentially including all known cultivars from some of the species, if you wish to and have thought about how to interpret the results.

-

It is not yet possible to add a cultivar PFT through the BETYdb web interface. See this GithHub comment for an example of how to define one manually in PostgreSQL.

-
-
-
-

19.1.9 Adding Priors for Each Variable

-

In addition to adding species, a PFT is defined in PEcAn by the list of variables associated with the PFT. PEcAn takes a fundamentally Bayesian approach to representing model parameters, so variables are not entered as fixed constants but as prior probability distributions.

-

There are a wide variety of priors already defined in the PEcAn database that often range from very diffuse and generic to very informative priors for specific PFTs.

-

These pre-existing prior distributions can be added to a PFT. Navigate to the PFT from Data > PFTs and selecting the edit button in the Actions column for the chosen PFT.

-

-

Click on “View Related Priors” button and search through the list for desired prior distributions. The list can be filtered by adding terms into the search box. Add a prior to the PFT by clicking on the far left button for the desired prior, changing it to an X.

-

-

Save this by scrolling to the bottom of the PFT page and hitting the Update button.

-

-
-

19.1.9.1 Creating new prior distributions

-

A new prior distribution can be created for a pre-existing variable, if a more constrained or specific one is known.

-
    -
  • Select Data > Priors then “New Prior”
  • -
  • In the Citation box, type in or select an existing reference that indicates how the prior was defined. There are a number of unpublished citations in current use that simply state the expert opinion of an individual
  • -
  • Fill the Variable box by typing in part or all of a pre-existing variable’s name and selecting it
  • -
  • The Phylogeny box allows one to specify what taxonomic grouping the prior is defined for, at it is important to note that this is just for reference and doesn’t have to be specified in any standard way nor does it have to be monophyletic (i.e. it can be a functional grouping)
  • -
  • The prior distribution is defined by choosing an option from the drop-down Distribution box, and then specifying values for both Parameter a and Parameter b. The exact meaning of the two parameters depends on the distribution chosen. For example, for the Normal distribution a and b are the mean and standard deviation while for the Uniform they are the minimum and maximum. All parameters are defined based on their standard parameterization in the R language
  • -
  • Specify the prior sample size in N if the prior is based on observed data (independent of data in the PEcAn database)
  • -
  • When this is done, scroll down and hit the Create button
  • -
-

-

The new prior distribution can then be added a PFT as described in the “Adding Priors for Each Variable” section.

-
-
-

19.1.9.2 Creating new variables

-

It is important to note that the priors are defined for the variable name and units as specified in the Variables table. If the variable name or units is different within the model it is the responsibility of write.configs.MODEL function to handle name and unit conversions (see Interface Modules below). This can also include common but nonlinear transformations, such as converting SLA to LMA or changing the reference temperature for respiration rates.

-

To add a new variable, select Data > Variables and click the New Variable button. Fill in the Name field with the desired name for the variable and the units in the Units field. There are additional fields, such as Standard Units, Notes, and Description, that can be filled out if desired. When done, hit the Create button.

-

-

The new variable can be used to create a prior distribution for it as in the “Creating new prior distributions” section.

-
-
-
-

19.1.10 Interface Modules

-
-

19.1.10.1 Setting up the module directory (required)

-

PEcAn assumes that the interface modules are available as an R package in the models directory named after the model in question. The simplest way to get started on that R package is to make a copy the template directory in the pecan/models folder and re-name it to the name of your model. In the code, filenames, and examples below you will want to substitute the word MODEL for the name of your model (note: R is case-sensitive).

-

If you do not want to write the interface modules in R then it is fairly simple to set up the R functions describe below to just call the script you want to run using R’s system command. Scripts that are not R functions should be placed in the inst folder and R can look up the location of these files using the function system.file which takes as arguments the local path of the file within the package folder and the name of the package (typically PEcAn.MODEL). For example

-
-
-
-
-

19.2 Example met conversion wrapper function

-

met2model.MODEL <- function(in.path, in.prefix, outfolder, start_date, end_date){ -myMetScript <- system.file(“inst/met2model.MODEL.sh”, “PEcAn.MODEL”) -system(paste(myMetScript, file.path(in.path, in.prefix), outfolder, start_date, end_date)) -}

-

would execute the following at the Linux command line

-

inst/met2model.MODEL.sh in.path/in.prefix outfolder start_date end_date `

-
-

19.2.0.1 DESCRIPTION

-

Within the module folder open the DESCRIPTION file and change the package name to PEcAn.MODEL. Fill out other fields such as Title, Author, Maintainer, and Date.

-
-
-

19.2.0.2 NAMESPACE

-

Open the NAMESPACE file and change all instances of MODEL to the name of your model. If you are not going to implement one of the optional modules (described below) at this time then you will want to comment those out using the pound sign #. For a complete description of R NAMESPACE files see here. If you create additional functions in your R package that you want to be used make sure you include them in the NAMESPACE as well (internal functions don’t need to be declared)

-
-
-

19.2.0.3 Building the package

-

Once the package is defined you will then need to add it to the PEcAn build scripts. From the root of the pecan directory, go into the scripts folder and open the file build.sh. Within the section of code that includes PACKAGES= add model/MODEL to the list of packages to compile. If, in writing your module, you add any other R packages to the system you will want to make sure those are listed in the DESCRIPTION and in the script scripts/install.dependencies.R. Next, from the root pecan directory open all/DESCRIPTION and add your model package to the Suggests: list.

-

At any point, if you want to check if PEcAn can build your MODEL package successfully, just go to the linux command prompt and run scripts/build.sh. You will need to do this before the system can use these packages.

-
-
-

19.2.0.4 write.config.MODEL (required)

-

This module performs two primary tasks. The first is to take the list of parameter values and model input files that it receives as inputs and write those out in whatever format(s) the MODEL reads (e.g. a settings file). The second is to write out a shell script, jobs.sh, which, when run, will start your model run and convert its output to the PEcAn standard (netCDF with metadata currently equivalent to the MsTMIP standard). Within the MODEL directory take a close look at inst/template.job and the example write.config.MODEL to see an example of how this is done. It is important that this script writes or moves outputs to the correct location so that PEcAn can find them. The example function also shows an example of writing a model-specific settings/config file, also by using a template.

-

You are encouraged to read the section above on defining PFTs before writing write.config.MODEL so that you understand what model parameters PEcAn will be passing you, how they will be named, and what units they will be in. Also note that the (optional) PEcAn input/driver processing scripts are called by separate workflows, so the paths to any required inputs (e.g. meteorology) will already be in the model-specific format by the time write.config.MODEL receives that info.

-
-
-

19.2.0.5 Output Conversions

-

The module model2netcdf.MODEL converts model output into the PEcAn standard (netCDF with metadata currently equivalent to the MsTMIP standard). This function was previously required, but now that the conversion is called within jobs.sh it may be easier for you to convert outputs using other approaches (or to just directly write outputs in the standard).

-

Whether you implement this function or convert outputs some other way, please note that PEcAn expects all outputs to be broken up into ANNUAL files with the year number as the file name (i.e. YEAR.nc), though these files may contain any number of scalars, vectors, matrices, or arrays of model outputs, such as time-series of each output variable at the model’s native timestep.

-

Note: PEcAn reads all variable names from the files themselves so it is possible to add additional variables that are not part of the MsTMIP standard. Similarly, there are no REQUIRED output variables, though time is highly encouraged. We are shortly going establish a canonical list of PEcAn variables so that if users add additional output variables they become part of the standard. We don’t want two different models to call the same output with two different names or different units as this would prohibit the multi-model syntheses and comparisons that PEcAn is designed to facilitate.

-
-
-

19.2.0.6 met2model.MODEL

-

met2model.MODEL(in.path, in.prefix, outfolder, start_date, end_date)

-

Converts meteorology input files from the PEcAn standard (netCDF, CF metadata) to the format required by the model. This file is optional if you want to load all of your met files into the Inputs table as described in How to insert new Input data, which is often the easiest way to get up and running quickly. However, this function is required if you want to benefit from PEcAn’s meteorology workflows and model run cloning. You’ll want to take a close look at [Adding-an-Input-Converter] to see the exact variable names and units that PEcAn will be providing. Also note that PEcAn splits all meteorology up into ANNUAL files, with the year number explicitly included in the file name, and thus what PEcAn will actually be providing is in.path, the input path to the folder where multiple met files may stored, and in.prefix, the start of the filename that precedes the year (i.e. an individual file will be named <in.prefix>.YEAR.nc). It is valid for in.prefix to be blank. The additional REQUIRED arguments to met2model.MODEL are outfolder, the output folder where PEcAn wants you to write your meteorology, and start_date and end_date, the time range the user has asked the meteorology to be processed for.

-
-
-

19.2.0.7 Commit changes

-

Once the MODEL modules are written, you should follow the Using-Git instructions on how to commit your changes to your local git repository, verify that PEcAn compiles using scripts/build.sh, push these changes to Github, and submit a pull request so that your model module is added to the PEcAn system. It is important to note that while we encourage users to make their models open, adding the PEcAn interface module to the Github repository in no way requires that the model code itself be made public. It does, however, allow anyone who already has a copy of the model code to use PEcAn so we strongly encourage that any new model modules be committed to Github.

-
-
-
-

19.3 Adding input data

-
-

19.3.1 Input records in BETY

-

All model input data or data used for model calibration/validation must be registered in the BETY database.

-

Before creating a new Input record, you must make sure that the format type of your data is registered in the database. If you need to make a new format record, see Creating a new format record in BETY.

-
-
-

19.3.2 Create a database file record for the input data

-

An input record contains all the metadata required to identify the data, however, this record does not include the location of the data file. Since the same data may be stored in multiple places, every file has its own dbfile record.

-

From your BETY interface:

-
    -
  • Create a DBFILES entry for the path to the file -
      -
    • From the menu click RUNS then FILES
    • -
    • Click “New File”
    • -
    • Select the machine your file is located at
    • -
    • Fill in the File Path where your file is located (aka folder or directory) NOT including the name of the file itself
    • -
    • Fill in the File Name with the name of the file itself. Note that some types of input records will refer to be ALL the files in a directory and thus File Name can be blank
    • -
    • Click Update
    • -
  • -
-
-
-

19.3.3 Creating a new Input record in BETY

-

From your BETY interface:

-
    -
  • Create an INPUT entry for your data -
      -
    • From the menu click RUNS then INPUTS
    • -
    • Click “New Input”
    • -
    • Select the SITE that this data is associated with the input data set
    • -
    • Other required fields are a unique name for the input, the start and end dates of the data set, and the format of the data. If the data is not in a currently known format you will need to create a NEW FORMAT and possibly a new input converter. Instructions on how to do add a converter can be found here Input conversion. Instructions on how to add a format record can be found here
    • -
    • Parent ID is an optional variable to indicated that one dataset was derived from another.
    • -
    • Click “Create”
    • -
  • -
  • Associate the DBFILE with the INPUT -
      -
    • In the RUNS -> INPUTS table, search and find the input record you just created
    • -
    • Click on the EDIT icon
    • -
    • Select “View related Files”
    • -
    • In the Search window, search for the DBFILE you just created
    • -
  • -
  • Once you have found the DBFILE, click on the “+” icon to add the file
  • -
  • Click on “Update” at the bottom when you are done.
  • -
-
-
-

19.3.4 Adding a new input converter

-

Three Types of data conversions are discussed below: Meteorological data, Vegetation data, and Soil data. Each section provides instructions on how to convert data from their raw formats into a PEcAn standard format, whether it be from a database or if you have raw data in hand.

-

Also, see PEcAn standard formats.

-
-

19.3.4.1 Meterological Data

-
-
19.3.4.1.1 Adding a function to PEcAn to convert a met data source
-

In general, you will need to write a function to download the raw met data and one to convert it to the PEcAn standard.

-

Downloading raw data function are named download.<source>.R. These functions are stored within the PEcAn directory: /modules/data.atmosphere/R.

-

Conversion function from raw to standard are named met2CF.<source>.R. These functions are stored within the PEcAn directory: /modules/data.atmosphere/R.

-

Current Meteorological products that are coupled to PEcAn can be found in our Available Meteorological Drivers page.

-

Note: Unless you are also adding a new model, you will not need to write a script to convert from PEcAn standard to PEcAn models. Those conversion scripts are written when a model is added and can be found within each model’s PEcAn directory.

-

Standards dimesion, names, nad units can be found here: Input Standards

-
-
-
19.3.4.1.2 Adding Single-Site Specific Meteorological Data
-

Perhaps you have meteorological data specific to one site, with a unique format that you would like to add to PEcAn. Your steps would be to: -1. write a script or function to convert your files into the netcdf PEcAn standard -2. insert that file as an input record for your site following these instructions

-
-
-
19.3.4.1.3 Processing Met data outside of the workflow using PEcAn functions
-

Perhaps you would like to obtain data from one of the sources coupled to PEcAn on its own. To do so you can run PEcAn functions on their own.

-
-
19.3.4.1.3.1 Example 1: Processing data from a database
-

Download Amerifluxlbl from Niwot Ridge for the year 2004:

-
raw.file <-PEcAn.data.atmosphere::download.AmerifluxLBL(sitename = "US-NR1", 
-                                             outfolder = ".", 
-                                             start_date = "2004-01-01", 
-                                             end_date = "2004-12-31")
-

Using the information returned as the object raw.file you will then convert the raw files into a standard file.

-

Open a connection with BETY. You may need to change the host name depending on what machine you are hosting BETY. You can find the hostname listed in the machines table of BETY.

-

-bety <- dplyr::src_postgres(dbname   = 'bety', 
-                            host ='localhost', 
-                            user     = "bety", 
-                            password = "bety")
-                            
-con <- bety$con
-

Next you will set up the arguments for the function

-
in.path <- '.'
-in.prefix <- raw.file$dbfile.name
-outfolder <- '.'
-format.id <- 5000000002
-format <- PEcAn.DB::query.format.vars(format.id=format.id,bety = bety)
-lon <- -105.54
-lat <- 40.03
-format$time_zone <- "America/Chicago"
-

Note: The format.id can be pulled from the BETY database if you know the format of the raw data.

-

Once these arguments are defined you can execute the met2CF.csv function

-
PEcAn.data.atmosphere::met2CF.csv(in.path = in.path, 
-                                  in.prefix =in.prefix,
-                                  outfolder = ".", 
-                                  start_date ="2004-01-01",
-                                  end_date = "2004-12-01",
-                                  lat= lat,
-                                  lon = lon,
-                                  format = format) 
-
-
-
19.3.4.1.3.2 Example 2: Processing data from data already in hand
-

If you have Met data already in hand and you would like to convert into the PEcAn standard follow these instructions.

-

Update BETY with file record, format record and input record according to this page How to Insert new Input Data

-

If your data is in a csv format you can use the met2CF.csvfunction to convert your data into a PEcAn standard file.

-

Open a connection with BETY. You may need to change the host name depending on what machine you are hosting BETY. You can find the hostname listed in the machines table of BETY.

-
bety <- dplyr::src_postgres(dbname   = 'bety', 
-                            host ='localhost', 
-                            user     = "bety", 
-                            password = "bety")
-                            
-con <- bety$con
-

Prepare the arguments you need to execute the met2CF.csv function

-
in.path <- 'path/where/the/raw/file/lives'
-in.prefix <- 'prefix_of_the_raw_file'
-outfolder <- 'path/to/where/you/want/to/output/thecsv/'
-format.id <- formatid of the format your created
-format <- PEcAn.DB::query.format.vars(format.id=format.id,bety = bety)
-lon <- longitude of your site
-lat <- latitude of your site
-format$time_zone <- time zone of your site
-start_date <- Start date of your data in "y-m-d"
-end_date <- End date of your data in "y-m-d"
-

Next you can execute the function:

-
PEcAn.data.atmosphere::met2CF.csv(in.path = in.path, 
-                                  in.prefix =in.prefix, 
-                                  outfolder = ".", 
-                                  start_date = start_date,
-                                  end_date = end_date,
-                                  lat= lat,
-                                  lon = lon,
-                                  format = format)
-
-
-
-
-

19.3.4.2 Vegetation Data

-

Vegetation data will be required to parameterize your model. In these examples we will go over how to produce a standard initial condition file.

-

The main function to process cohort data is the ic_process.R function. As of now however, if you require pool data you will run a separate function, pool_ic_list2netcdf.R.

-
-
19.3.4.2.0.1 Example 1: Processing Veg data from data in hand.
-

In the following example we will process vegetation data that you have in hand using PEcAn.

-

First, you’ll need to create a input record in BETY that will have a file record and format record reflecting the location and format of your file. Instructions can be found in our How to Insert new Input Data page.

-

Once you have created an input record you must take note of the input id of your record. An easy way to take note of this is in the URL of the BETY webpage that shows your input record. In this example we use an input record with the id 1000013064 which can be found at this url: https://psql-pecan.bu.edu/bety/inputs/1000013064# . Note that this is the Boston University BETY database. If you are on a different machine, your url will be different.

-

With the input id in hand you can now edit a pecan XML so that the PEcAn function ic_process will know where to look in order to process your data. The inputs section of your pecan XML will look like this. As of now ic_process is set up to work with the ED2 model so we will use ED2 settings and then grab the intermediary Rds data file that is created as the standard PEcAn file. For your Inputs section you will need to input your input id wherever you see the useic flag.

-
<inputs>
-      <css>
-        <source>FFT</source>
-        <output>css</output>
-        <username>pecan</username>
-        <id>1000013064</id>
-        <useic>TRUE</useic>
-        <metadata>
-          <trk>1</trk>
-          <age>70</age>
-          <area>400</area>
-        </metadata>
-      </css>
-      <pss>
-        <source>FFT</source>
-        <output>pss</output>
-        <username>pecan</username>
-        <id>1000013064</id>
-        <useic>TRUE</useic>
-      </pss>
-      <site>
-        <source>FFT</source>
-        <output>site</output>
-        <username>pecan</username>
-        <id>1000013064</id>
-        <useic>TRUE</useic>
-      </site>
-      <met>
-        <source>CRUNCEP</source>
-        <output>ED2</output>
-      </met>
-      <lu>
-        <id>294</id>
-      </lu>
-      <soil>
-        <id>297</id>
-      </soil>
-      <thsum>
-        <id>295</id>
-      </thsum>
-      <veg>
-        <id>296</id>
-      </veg>
-    </inputs>
-

This IC workflow also supports generating ensembles of initial conditions from posterior estimates of DBH. To do this the tags below can be inserted to the pecan.xml:

-
       <css>
-        <source>PalEON</source>
-        <output>css</output>
-        <id>1000015682</id>
-        <useic>TRUE</useic>
-        <ensemble>20</ensemble>
-        <metadata>
-          <area>1256.637</area>
-          <n.patch>3</n.patch>
-        </metadata>
-      </css>
-

Here the id should point to a file that has MCMC samples to generate the ensemble from. The number between the <ensemble> tag defines the number of ensembles requested. The workflow will populate the settings list run$inputs tag with ensemble member information. E.g.:

-
  <inputs>
-   <css>
-    <path1>...</path1>
-    <path2>...</path2>
-    <path3>...</path3>
-    ...
-    <pathN>...</pathN>
-   </css>
-   <pss>
-    <path>
-     <path1>...</path1>
-     <path2>...</path2>
-     <path3>...</path3>
-      ...
-     <pathN>...</pathN>
-    </path>
-   </pss>
-   <site>
-    <path>
-     <path1>...</path1>
-     <path2>...</path2>
-     <path3>...</path3>
-      ...
-     <pathN>...</pathN>
-    </path>
-   </site>
-   <met>...</met>
-   <lu>...</lu>
-   <soil>...</soil>
-   <thsum>...</thsum>
-   <veg>...</veg>
-  </inputs>
-

Once you edit your PEcAn.xml you can than create a settings object using PEcAn functions. Your pecan.xml must be in your working directory.

-
settings <- PEcAn.settings::read.settings("pecan.xml")
-settings <- PEcAn.settings::prepare.settings(settings, force=FALSE)
-

You can then execute the ic_process function to convert data into a standard Rds file:

-
input <- settings$run$inputs
-dir <- "."
-ic_process(settings, input, dir, overwrite = FALSE)
-

Note that the argument dir is set to the current directory. You will find the final ED2 file there. More importantly though you will find the .Rds file within the same directory.

-
-
-
19.3.4.2.0.2 Example 3 Pool Initial Condition files
-

If you have pool vegetation data, you’ll need the pool_ic_list2netcdf.R function to convert the pool data into PEcAn -standard.

-

The function stands alone and requires that you provide a named list of netcdf dimensions and values, and a named list of variables and values. Names and units need to match the standard_vars.csv table found here.

-
#Create a list object with necessary dimensions for your site
-input<-list()
-dims<- list(lat=-115,lon=45, time= 1)
-variables<- list(SoilResp=8,TotLivBiom=295)
-input$dims <- dims
-input$vals <- variables
-

Once this is done, set outdir to where you’d like the file to write out to and a siteid. Siteid in this can be used as an file name identifier. Once part of the automated workflow siteid will reflect the site id within the BET db.

-
outdir  <- "."
-siteid <- 772
-pool_ic_list2netcdf(input = input, outdir = outdir, siteid = siteid)
-

You should now have a netcdf file with initial conditions.

-
-
-
-

19.3.4.3 Soil Data

-
-
19.3.4.3.0.1 Example 1: Converting Data in hand
-

Local data that has the correct names and units can easily be written out in PEcAn standard using the function soil2netcdf.

-
soil.data <- list(volume_fraction_of_sand_in_soil = c(0.3,0.4,0.5),
-                  volume_fraction_of_clay_in_soil = c(0.3,0.3,0.3),
-                  soil_depth = c(0.2,0.5,1.0))
-                         
-soil2netcdf(soil.data,"soil.nc")
-

At the moment this file would need to be inserted into Inputs manually. By default, this function also calls soil_params, which will estimate a number of hydraulic and thermal parameters from texture. Be aware that at the moment not all model couplers are yet set up to read this file and/or convert it to model-specific formats.

-
-
-
19.3.4.3.0.2 Example 2: Converting PalEON data
-

In addition to location-specific soil data, PEcAn can extract soil texture information from the PalEON regional soil product, which itself is a subset of the MsTMIP Unified North American Soil Map. If this product is installed on your machine, the appropriate step in the do_conversions workflow is enabled by adding the following tag under <inputs> in your pecan.xml

- -

In the future we aim to extend this extraction to a wider range of soil products.

-
-
-
19.3.4.3.0.3 Example 3: Extracting soil properties from gSSURGO database
-

In addition to location-specific soil data, PEcAn can extract soil texture information from the gSSURGO data product. This product needs no installation and it extract soil proeprties for the lower 48 states in U.S. In order to let the pecan know that you’re planning to use gSSURGO, you can the following XML tag under input in your pecan xml file.

- -
-
-
-
-
-

19.4 Pecan Data Ingest via Web Interface

-

This tutorial explains the process of ingesting data into PEcAn via our Data-Ingest Application. In order to ingest data, the users must first select data that they wish to upload. Then, they enter metadata to help PEcAn parse and load the data into the main PEcAn workflow.

-
-

19.4.1 Loading Data

-
-

19.4.1.1 Selecting Ingest Method

-

The Data-Ingest application is capable of loading data from the DataONE data federation and from the user’s local machine. The first step in the workflow is therefore to select an upload method. The application defaults to uploading from DataONE. To upload data from a local device, simply select the radio button titled Local Files.

-
-
-

19.4.1.2 DataONE Upload Example

-


-

-
-The DataONE download feature allows the user to download data at a given doi or DataONE specific package id. To do so, enter the doi or identifier in the Import From DataONE field and select download. The download process may take a couple of minutes to run depending on the number of files in the dataONE package. This may be a convenient option if the user does not wish to download files directly to their local machine. Once the files have been successfully downloaded from DataONE, they are displayed in a table. Before proceeding to the next step, the user can select a file to ingest by clicking on the corresponding row in the data table. -

-
-
-
-

19.4.2 Local Upload Example

-


-To upload local files, the user should first select the Local Files button. From there, the user can upload files from their local machines by selecting Browse or by dragging and dropping files into the text box. The files will begin uploading automatically. From there, the user should select a file to ingest and then select the Next Step button. -
-After this step, the workflow is identical for both methods. However, please note that if it becomes necessary to switch from loading data via DataONE to uploading local files after the first step, please restart the application. -

-

-
- -### 2. Creating an Input Record -Creating an input record requires some basic metadata about the file that is being ingested. Each entry field is briefly explained below. -

-
    -
  • Site: To link the selected file with a site, the user can scroll or type to search all the sites in PEcAn. See Example: -
    - -
  • -
  • Parent: To link the selected file with another dataset, type to search existing datasets in the Parent field.

  • -
  • Name: this field should be autofilled by selecting a file in step 1.

  • -
  • Format: If the selected file has an existing format name, the user can search and select in the Format field. If the selected file’s format is not already in pecan, the user can create a new format by selecting Create New Format. Once this new format is created, it will automatically populate the Format box and the Current Mimetype box (See Section 3).

  • -
  • Mimetype: If the format already exists, select an existing mimetype.

  • -
  • Start and End Date and Time: Inputs can be entered manually or by using the user interface. See example

  • -
-


-

-
    -
  • Notes: Describe the data that is being uploaded. Please include any citations or references.
  • -
-
-
-

19.4.3 3. Creating a format record

-

If it is necessary to add a new format to PEcAn, the user should fill out the form attached to the Create New Format button. The inputs to this form are described below:

-
    -
  • Mimetype: type to search existing mimetypes. If the mimetype is not in that list, please click on the link Create New Mimetype and create a new mimetype via the BETY website.

  • -
  • New Format Name: Add the name of the new format. Please exclude spaces from the name. Instead please use underscores "_".

  • -
  • Header: If there is space before the first line of data in the dataset, please select Yes

  • -
  • Skip: The number of lines in the header that should be skipped before the data.

  • -
  • Please enter notes that describe the format.

  • -
-

Example: -
- -### 4. Formats_Variables Record -The final step in the ingest process is to register a formats-variables record. This record links pecan variables with variables from the selected data.

-
    -
  • Variable: PEcAn variable that is equivalent to variable in selected file.

  • -
  • Name: The variable name in the imported data need only be specified if it differs from the BETY variable name.

  • -
  • Unit: Should be in a format parseable by the udunits library and need only be secified if the units of the data in the file differ from the BETY standard.

  • -
  • Storage Type: Storage type need only be specified if the variable is stored in a format other than would be expected (e.g. if numeric values are stored as quoted character strings). Additionally, storage_type stores POSIX codes that are used to store any time variables (e.g. a column with a 4-digit year would be %Y).

  • -
  • Column Number: Vector of integers that list the column numbers associated with variables in a dataset. Required for text files that lack headers. -
    -

  • -
-

Finally, the path to the ingest data is displayed in the Select Files box.

-
-
-
-

19.5 Creating a new format

-
-

19.5.1 Formats in BETY

-

The PEcAn database keeps track of all the input files passed to models, as well as any data used in model validation or data assimilation. Before we start to register these files with PEcAn we need to define the format these files will be in.

-

The main goal is to take all the meta-data we have about a data file and create a record of it that pecan can use as a guide when parsing the data file.

-

This information is stored in a Format record in the bety database. Make sure to read through the current Formats before deciding to make a new one.

-
-
-

19.5.2 Creating a new format in BETY

-

If the Format you are looking for is not available, you will need to create a new record. Before entering information into the database, you need to be able to answer the following questions about your data:

-
    -
  • What is the file MIME type? -
      -
    • We have a suit of functions for loading in data in open formats such as CSV, txt, netCDF, etc.
    • -
    • PEcAn has partnered with the NCSA BrownDog project to create a service that can read and convert as many data formats as possible. If your file type is less common or a proprietary type, you can use the BrownDog DAP to convert it to a format that can be used with PEcAn.
    • -
    • If BrownDog cannot convert your data, you will need to contact us about writing a data specific load function.
    • -
  • -
  • What variables does the file contain? -
      -
    • What are the variables named?
    • -
    • What are the variable units?
    • -
    • How do the variable names and units in the data map to PEcAn variables in the BETY database? See below for an example. It is most likely that you will NOT need to add variables to BETY. However, identifying the appropriate variables matches in the database may require some work. We are always available to help answer your questions.
    • -
  • -
  • Is there a timestamp on the data? -
      -
    • What are the units of time?
    • -
  • -
-

Here is an example using a fake dataset:

-
-example_data -

example_data

-
-

This data started out as an excel document, but was saved as a CSV file.

-

To create a Formats record for this data, in the web interface of BETY, select Runs > Formats and click New Format.

-

You will need to fill out the following fields:

-
    -
  • MIME type: File type (you can search for other formats in the text field)
  • -
  • Name: The name of your format (this can be whatever you want)
  • -
  • Header: Boolean that denotes whether or not your data contains a header as the first line of the data. (1 = TRUE, 0 = FALSE)
  • -
  • Skip: The number of lines above the data that should be skipped. For example, metadata that should not be included when reading in the data or blank spaces.
  • -
  • Notes: Any additional information about the data such as sources and citations.
  • -
-

Here is the Formats record for the example data:

-
-format_record_1 -

format_record_1

-
-

When you have finished this section, hit Create. The final record will be displayed on the screen.

-
-

19.5.2.1 Formats -> Variables

-

After a Format entry has been created, you are encouraged to edit the entry to add relationships between the file’s variables and the Variables table in PEcAn. Not only do these relationships provide meta-data describing the file format, but they also allow PEcAn to search and (for some MIME types) read files.

-

To enter this data, select Edit Record and on the edit screen select View Related Variable.

-

Here is the record for the example data after adding related variables:

-
-format_record_2 -

format_record_2

-
-
-
19.5.2.1.1 Name and Unit
-

For each variable in the file you will want at a minimum to specify the NAME of the variable within your file and match that to the equivalent Variable in the pulldown.

-

Make sure to search for your variables under Data > Variables before suggesting that we create a new variable record. This may not always be a straightforward process.

-

For example bety contains a record for Net Primary Productivity:

-
-var_record -

var_record

-
-

This record does not have the same variable name or the same units as NPP in the example data. -You may have to do some reading to confirm that they are the same variable. -In this case -- Both the data and the record are for Net Primary Productivity (the notes section provides additional resources for interpreting the variable.) -- The units of the data can be converted to those of the vairiable record (this can be checked by running udunits2::ud.are.convertible("g C m-2 yr-1", "Mg C ha-1 yr-1"))

-

Differences between the data and the variable record can be accounted for in the data Formats record.

-
    -
  • Under Variable, select the variable as it is recorded in bety.
  • -
  • Under Name, write the name the variable has in your data file.
  • -
  • Under Unit, write the units the variable has in your data file.
  • -
-

NOTE: All units must be written in a udunits compliant format. To check that your units can be read by udunits, in R, load the udunits2 package and run udunits2::is.parseable("g C m-2 yr-1")

-

If the name or the units are the same, you can leave the Name and Unit fields blank. This is can be seen with the variable LAI.

-
-
-
19.5.2.1.2 Storage Type
-

Storage Type only needs to be specified if the variable is stored in a format other than what would be expected (e.g. if numeric values are stored as quoted character strings).

-

One such example is time variables.

-

PEcAn converts all dates into POSIX format using R functions such as strptime. These functions require that the user specify the format in which the date is written.

-

The default is "%Y-%m-%d %H:%M:%S" which would look like "2017-01-01 00:00:00"

-

A list of date formats can be found in the R documentation for the function strptime

-

Below are some commonly used codes:

- ---- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
%dDay of the month as decimal number (01–31).
%DDate format such as %m/%d/%y.
%HHours as decimal number (00–23).
%mMonth as decimal number (01–12).
%MMinute as decimal number (00–59).
%SSecond as integer (00–61), allowing for up to two leap-seconds (but POSIX-compliant implementations will ignore leap seconds).
%TEquivalent to %H:%M:%S.
%yYear without century (00–99). On input, values 00 to 68 are prefixed by 20 and 69 to 99 by 19 – that is the behaviour specified by the 2004 and 2008 POSIX standards, but they do also say ‘it is expected that in a future version the default century inferred from a 2-digit year will change’.
%YYear with century.
-
-
-
19.5.2.1.3 Column Number
-

If your data is in text format with variables in a standard order then you can specify the Column Number for the variable. This is required for text files that lack headers.

-
-
-
-

19.5.2.2 Retrieving Format Information

-

To acquire Format information from a Format record, use the R function query.format.vars

-
-
19.5.2.2.1 Inputs
-
    -
  • bety: connection to BETY
  • -
  • input.id=NA and/or format.id=NA: Input or Format record ID from BETY -
      -
    • At least one must be specified. Defaults to format.id if both provided.
    • -
  • -
  • var.ids=NA: optional vector of variable IDs. If provided, limits results to these variables.
  • -
-
-
-
19.5.2.2.2 Output
-
    -
  • R list object containing many things. Fill this in.
  • -
-
-
-
-
-
-

19.6 Creating a new benchmark reference run

-

The purpose of the reference run record in BETY is to store all the settings from a run that are necessary in exactly recreating it.

-

The pecan.xml file is the home of absolutely all the settings for a particular run in pecan. However, much of the information in the pecan.xml file is server and user specific and more importantly, the pecan.xml files are stored on individual servers and may not be available to the public.

-

When a run that is performed using pecan is registered as a reference run, the settings that were used to make that run are made available to all users through the database.

-

All completed runs are not automatically registered as reference runs. To register a run, navigate to the benchmarking section of the workflow visualizations Shiny app.

-
-
-

19.7 Editing records

-
    -
  • Models
  • -
  • Species
  • -
  • PFTs
  • -
  • Traits
  • -
  • Inputs
  • -
  • DB files
  • -
  • Variables
  • -
  • Formats
  • -
  • (Link each section to relevant Bety tables)
  • -
- -
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - - diff --git a/develop_test/appendix-testthat.html b/develop_test/appendix-testthat.html deleted file mode 100644 index deb2c3e4e..000000000 --- a/develop_test/appendix-testthat.html +++ /dev/null @@ -1,884 +0,0 @@ - - - - - - - 31 Testing with the testthat package | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

31 Testing with the testthat package

-

Tests are found in <package>/tests/testthat/ (for example, base/utils/inst/tests/)

-

See attached file and -http://r-pkgs.had.co.nz/tests.html -for details on how to use the testthat package.

-
-

31.1 List of Expectations

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FullAbbreviation
expect_that(x, is_true())expect_true(x)
expect_that(x, is_false())expect_false(x)
expect_that(x, is_a(y))expect_is(x, y)
expect_that(x, equals(y))expect_equal(x, y)
expect_that(x, is_equivalent_to(y))expect_equivalent(x, y)
expect_that(x, is_identical_to(y))expect_identical(x, y)
expect_that(x, matches(y))expect_matches(x, y)
expect_that(x, prints_text(y))expect_output(x, y)
expect_that(x, shows_message(y))expect_message(x, y)
expect_that(x, gives_warning(y))expect_warning(x, y)
expect_that(x, throws_error(y))expect_error(x, y)
-
- -
-

31.3 Data for tests

-

Many of PEcAn’s functions require inputs that are provided as data. -These can be in the data or the inst/extdata folders of a package. -Data that are not package specific should be placed in the PEcAn.all (base/all) or -PEcAn.utils (base/utils) packages.

-

Some useful conventions:

-
-
-

31.4 Settings

-
    -
  • A generic settings can be found in the PEcAn.all package
  • -
- -
    -
  • database settings can be specified, and tests run only if a connection is available
  • -
-

We currently use the following database to run tests against; tests that require access to a database should check db.exists() and be skipped if it returns FALSE to avoid failed tests on systems that do not have the database installed.

- -
    -
  • instructions for installing this are available on the VM creation -wiki
  • -
  • examples can be found in the PEcAn.DB package (base/db/tests/testthat/).

  • -
  • Model specific settings can go in the model-specific module, for -example:

  • -
- -
    -
  • test-specific settings: -
      -
    • settings text can be specified inline:

      -
      settings.text <- "
      -  <pecan>
      -    <nocheck>nope</nocheck> ## allows bypass of checks in the read.settings functions
      -    <pfts>
      -      <pft>
      -        <name>ebifarm.pavi</name>
      -        <outdir>test/</outdir>
      -      </pft>
      -    </pfts>
      -    <outdir>test/</outdir>
      -    <database>
      -      <userid>bety</userid>
      -      <passwd>bety</passwd>
      -      <location>localhost</location>
      -      <name>bety</name>
      -    </database>
      -  </pecan>"
      -settings <- read.settings(settings.text)
    • -
    • values in settings can be updated:

      -
    • -
  • -
-
-
-

31.5 Helper functions for unit tests

-
    -
  • PEcAn.utils::tryl returns FALSE if function gives error
  • -
  • PEcAn.utils::temp.settings creates temporary settings file
  • -
  • PEcAn.DB::db.exists returns TRUE if connection to database is available
  • -
- -
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - - diff --git a/develop_test/available-meteorological-drivers.html b/develop_test/available-meteorological-drivers.html deleted file mode 100644 index 5785a12ff..000000000 --- a/develop_test/available-meteorological-drivers.html +++ /dev/null @@ -1,885 +0,0 @@ - - - - - - - 14 Available Meteorological Drivers | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

14 Available Meteorological Drivers

-
-

14.1 Ameriflux

-

Scale: site

-

Resolution: 30 or 60 min

-

Availability: varies by site http:\/\/ameriflux.lbl.gov\/data\/data-availability\/

-

Notes: Old ORNL server, use is deprecated

-
-
-

14.2 AmerifluxLBL

-

Scale: site

-

Resolution: 30 or 60 min

-

Availability: varies by site http:\/\/ameriflux.lbl.gov\/data\/data-availability\/

-

Notes: new Lawrence Berkeley Lab server

-
-
-

14.3 Fluxnet2015

-

Scale: site

-

Resolution: 30 or 60 min

-

Availability: varies by site http://fluxnet.fluxdata.org/sites/site-list-and-pages

-

Notes: Fluxnet 2015 synthesis product. Does not cover all FLUXNET sites

-
-
-

14.4 NARR

-

Scale: North America

-

Resolution: 3 hr, approx. 32km \(Lambert conical projection\)

-

Availability: 1979-present

-
-
-

14.5 CRUNCEP

-

Scale: global

-

Resolution: 6hr, 0.5 degree

-

Availability: 1901-2010

-
-
-

14.6 CMIP5

-

Scale: varies by model

-

Resolution: 3 hr

-

Availability: 2006-2100

-

Currently only GFDL available. Different scenerios and ensemble members can be set via Advanced Edit.

-
-
-

14.7 NLDAS

-

Scale: Lower 48 + buffer,

-

Resolution: 1 hour, .125 degree

-

Availability: 1980-present

-
-
-

14.8 GLDAS

-

Scale: Global

-

Resolution: 3hr, 1 degree

-

Availability: 1948-2010

-
-
-

14.9 PalEON

-

Scale: -100 to -60 W Lon, 35 to 50 N Latitude \(US northern hardwoods + buffer\)

-

Resolution: 6hr, 0.5 degree

-

Availability: 850-2010

-
-
-

14.10 FluxnetLaThuile

-

Scale: site

-

Resolution: 30 or 60 min

-

Availability: varies by site http:\/\/www.fluxdata.org\/DataInfo\/Dataset%20Doc%20Lib\/SynthDataSummary.aspx

-

Notes: 2007 synthesis. Fluxnet2015 supercedes this for sites that have been updated

-
-
-

14.11 Geostreams

-

Scale: site

-

Resolution: varies

-

Availability: varies by site

-

Notes: This is a protocol, not a single archive. The PEcAn functions currently default to querying [https://terraref.ncsa.illinois.edu/clowder/api/geostreams], which requires login and contains data from only two sites (Urbana IL and Maricopa AZ). However the interface can be used with any server that supports the Geostreams API.

-
-
-

14.12 ERA5

-

Scale: Global

-

Resolution: 3 hrs and 31 km

-

Availability: 1950-present

-

Notes:

-

It’s important to know that the raw ERA5 tiles needs to be downloaded and registered in the database first. Inside the inst folder in the data.atmosphere package there are R files for downloading and registering files in the BETY. However, it assumes that you have registered and setup your API requirements. Check out how to setup your API [here] (https://confluence.ecmwf.int/display/CKB/How+to+download+ERA5#HowtodownloadERA5-3-DownloadERA5datathroughtheCDSAPI). -In the inst folder you can find two files (ERA5_db_register.R and ERA5_USA_download.R). If you setup your ecmwf account as it’s explained in the link above, ERA5_USA_download.R will help you to download all the tiles with all the variables required for pecan extract.nc.ERA5 function to generate pecan standard met files. Besides installing the required packages for this file, it should work from top to bottom with no problem. After downloading the tiles, there is simple script in ERA5_db_register.R which helps you register your tiles in the bety. met.process later on uses that entery to find the required tiles for extracting met data for your sites. There are important points about this file. 1- Make sure you don’t change the site id in the script (which is the same the ParentSite in ERA5 registeration xml file). 2- Make sure the start and end date in that script matches the downloaded tiles. Set your ERA5.files.path to where you downloaded the tiles and then the rest of the script should be working fine.

- -
-
-

14.13 Download GFDL

-

The Downlad.GFDL function assimilates 3 hour frequency CMIP5 outputs generated by multiple GFDL models. GFDL developed several distinct modeling streams on the timescale of CMIP5 and AR5. These models include CM3, ESM2M and ESM2G with a spatial resolution of 2 degrees latitude by 2.5 degrees longitude. Each model has future outputs for the AR5 Representative Concentration Pathways ranging from 2006-2100.

-
-
-

14.14 CM3

-

GFDL’s CMIP5 experiments with CM3 included many of the integrations found in the long-term CMIP5 experimental design. The focus of this physical climate model is on the role of aerosols, aerosol-cloud interactions, and atmospheric chemistry in climate variability and climate change.

-
-
-

14.15 ESM2M & ESM2G

-

Two new models representing ocean physics with alternative numerical frameworks to explore the implications of some of the fundamental assumptions embedded in these models. Both ESM2M and ESM2G utilize a more advanced land model, LM3, than was available in ESM2.1 including a variety of enhancements (Milly et al., in prep). GFDL’s CMIP5 experiments with Earth System Models included many of the integrations found in the long-term CMIP5 experimental design. The ESMs, by design, close the carbon cycle and are used to study the impact of climate change on ecosystems, ecosystem changes on climate and human activities on ecosystems.

-

For more information please navigate here

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/develop_test/basic-web-workflow.html b/develop_test/basic-web-workflow.html deleted file mode 100644 index 17ffd7fcd..000000000 --- a/develop_test/basic-web-workflow.html +++ /dev/null @@ -1,930 +0,0 @@ - - - - - - - 6 Basic Web workflow | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

6 Basic Web workflow

-

This chapter describes the major steps of the PEcAn web-based workflow, which are as follows:

- -

We recommend that all new users begin with [PEcAn Hands-On Demo 01: Basic Run]. The documentation below assumes you are already familiar with how to navigate to PEcAn’s interactive web interface for running models.

-
-

6.1 Site and model selection

-

This page is used to select the model to run and the site at which you would like to run that model.

-

NOTE: If this page does not load for you, it may be related to a known Google Maps API key issue. See issue #1269 for a possible solution.

-
-

6.1.1 Selecting a model

-
    -
  1. On the Select Host webpage use the Host pull-down menu to select the server you want to run on. PEcAn is designed to allow models to be run both locally and on remote high-performance computing (HPC) resources (i.e. clusters). We recommend that users start with local runs. More information about connecting your PEcAn instance to a cluster can be found on the Remote execution with PEcAn page.

  2. -
  3. Next, select the model you want to run under the Model pull-down menu. The list of models currently supported by PEcAn, along with information about these models, is available on the PEcAn Models page.

    -
      -
    1. If a PEcAn-supported model is not listed, this is most likely because the model has not been installed on the server. The PEcAn team does not have permissions to redistribute all of the models that are coupled to it, so you will have to install some PEcAn-compatible models yourself. Please consult the PEcAn model listing for information about obtaining and installing different models. Once the model is installed and you have added the location of the model executable to Bety (see Adding An Ecosystem Model), your model should appear on the PEcAn Select Host page after your refresh the page.

    2. -
    3. If you would like to add a new model to PEcAn please consult our guide for Adding an Ecosystem Model and contact the PEcAn team for assistance.

    4. -
  4. -
  5. If selecting your model causes your site to disappear from the Google Map, that means the site exists but there are no drivers for that model-site combination registered in the database.

    -
      -
    1. Click the “Conversion” checkbox. If your site reappears, that means PEcAn should be able to automatically generate the required inputs for this site by converting from existing input files in other formats.

    2. -
    3. If the site still does not reappear, that means there are required input files for that model-site combination that PEcAn cannot autogenerate. This may be because the model has unique input requirements or because it has not yet been fully coupled to the PEcAn input processing workflow. Go to the troubleshooting section under Selecting a site for more information on diagnosing what drivers are missing.

    4. -
  6. -
-
-
-

6.1.2 Selecting a site

-
-
-

6.1.3 Site Groups

-
    -
  1. PEcAn provides the option of organizing sites into groups to make them easier to find and easier to run as a group. We have pre-loaded a number of common research networks (e.g., FLUXNET, LTER, NEON), but you are free to create new site groups through Bety.

  2. -
  3. If you are searching for a site that is not part of an existing site group, or you are unsure which site group it belongs to, select “All Sites” to see all sites in Bety. Note that this may take a while to render.

  4. -
-
-
-

6.1.4 Using existing sites

-
    -
  1. Find the site on the map The simplest way of determining if a site exists in PEcAn is through the Google Map interface of the web-based workflow. You’ll want to make sure that the “Site Group” is set to “All Sites” and the “Model” is set to “All Models”.

  2. -
  3. Find the site in BETY If the site is not on the map, it may still be in Bety but with insufficient geographic information. To locate the site in Bety, first login to your local version of the BETY database. If using the VM, navigate to localhost:6480/bety and login with username bety and password illinois. Then, navigate to Data > Sites and use the “Search” box to search for your site. If you do find your site, click “Edit” and add geographic information so that the site will show up on the map. Also, note that the site ID number shows up in the URL for the “Show” or “Edit” pages. This ID is often useful to know, for example when editing a PEcAn settings file by hand. If you did not find you site, follow the instructions below to add a site.

  4. -
-
-
-

6.1.5 Adding a new site

-

(TODO: Move most of this out)

-
    -
  1. Log into Bety as described above.

  2. -
  3. Pick a citation for your site Each site requires an associated “citation” that must be added before the site itself is added. First, navigate to “Data > Citations” and use the “Search” box to see if the relevant citation already exists. If it does, click the check mark under “Actions” to proceed to site creation.

  4. -
-
    -
  • To create a new citation, click the New Citation button, fill in the fields, and then click “Create”. The “field URL” should contain the web address that takes you to this publication on the publisher’s website. The “PDF” field should be the full web address to a PDF for this citation.

  • -
  • Note that our definition of a citation is flexible, and a citation need not be a peer-reviewed publication. Most of the fields in “New Citation” can be left blank, but we recommend at least adding a descriptive title, such as “EBI Farm Field Data” and a relevant contact person as the “Author”.

  • -
-
    -
  1. Once the Citation is created or selected this should automatically take you to the Sites page and list any Sites already associated with this citation. To create a new site click the New Site button.

  2. -
  3. When creating a new site, the most important fields are the Site name and coordinates (latitude and longitude). The coordinates can be entered by hand or by clicking on the site location on the Google Map interface. All other information is optional, but can be useful for searching and indexing purposes.

  4. -
  5. When you are done click Create. At this point, once the PEcAn site-level page is refreshed, the site should automatically appear.

  6. -
-
-
-

6.1.6 Troubleshooting

-
-

6.1.6.1 My site shows up when I don’t have any model selected, but disappears once I select the model I want to run

-

Selecting a model will cause PEcAn to filter the available sites based on whether they possess the required Inputs for a given model (e.g. meteorology). To check what Inputs are missing for a site point your browser to the pecan/checksite.php webpage (e.g. localhost:6480/pecan/checksite.php). This page looks virtually identical to the site selection page, except that it has a Check button instead of Prev and Next. If you select a Machine, Model, and Site and then click Check the page should return a list of what Inputs are missing (listing both the name and the Format ID number). Don’t forget that its possible for PEcAn to have required Inputs in its database, but just not have them for the Machine where you want to run.

-

To see more about what Inputs a given model can accept, and which of those are required, take a look at the MODEL_TYPE table entry in the database (e.g. go to localhost:6480/bety; Select Runs > Model Type; and then click on the model you want to run).

-

For information about loading missing Inputs into the database visit Input records in BETY, and also read the rest of the pages under this section, which will provide important information about the specific classes of Inputs (e.g. meteorology, vegetation, etc).

-

Finally, we are continually developing and refining workflows and standards for processing Input data in a model-agnostic way. The details about what Inputs can be processed automatically are discussed input-by-input in the sections below. For those looking to dive into the code or troubleshoot further, these conversions are ultimately handled under the PEcAn.workflow::do_conversions workflow module.

-
-
-
-
-

6.2 Model configuration

-

This page is used for basic model configuration, including when your model will run and what input data it will use.

-
-

6.2.1 Choosing meteorology

-

Once a Machine, Model, and Site have been selected, PEcAn will take you to the Input selection page. From this page you will select what Plant Functional Type (PFT) you want to run at a site, the start and end dates of the run, and various Input selections. The most common of these across all models is the need to specify meteorological forcing data. The exact name of the menu item for meteorology will vary by model because all of the Input requirements are generated individually for each model based on the MODEL_TYPE table. In general there are 3 possible cases for meteorology

-
    -
  • PEcAn already has driver files in its database
  • -
  • PEcAn does not have drivers, but can generate them from publicly available data
  • -
  • You need (or want) to upload your own drivers
  • -
-

The first two cases will appear automatically in the the pull down menu. For meteorological files that already exist you will see the date range that’s available. By contrast, met that can be generated will appear as “Use ”, where is the origin of the data (e.g. “Use Ameriflux” will use the micromet from an Ameriflux eddy covariance tower, if one is present at the site).

-

If you want to upload your own met data this can be done in three ways.

-
    -
  1. The default way to add met data is to incorporate it into the overall meteorological processing workflow. This is preferred if you are working with a common meteorological data product that is not yet in PEcAn’s workflow. This case can be divided into two special cases:

    -
      -
    1. Data is in a common MIME-type that PEcAn already has a converter for (e.g. CSV). In this case you’ll want to create a new Format record for the meta-data so that the existing converter can process this data. See documentation for [Creating a new Format record in BETY] for more details.

    2. -
    3. Data is in a more complicated format or interactive database, but large/useful enough to warrent a custom conversion function. Details on creating custom met conversions is in the [Input Conversion], though at this stage you would also be strongly encouraged to contact the PEcAn development team.

    4. -
  2. -
  3. The second-best way is to upload data in PEcAn’s standard meteorological format (netCDF files, CF metadata). See [Input Conversion] for details about variables and units. From this standard, PEcAn can then convert the file to the model-specific format required by the model you have chosen. This approach is preferred for a rare or one-off meterological file format, because PEcAn will also be able to convert the file into the format required by any other model as well.

  4. -
  5. The last option for adding met data is to add it in a model-specific format, which is often easiest if you’ve already been running your model at a site and are just switching to using PEcAn.

  6. -
-
-
-

6.2.2 Met workflow

-

In a nutshell, the PEcAn met workflow is designed to reduce the problem of converting n possible met inputs into m possible model formats, which requires n x m conversion functions as well as numerous custom functions for downscaling, gap filling, etc. Instead, PEcAn works with a single met standard, and thus requires n conversion functions, one for converting each data source into the PEcAn standard, and then m conversion functions for converting from that standard to what an individual model requires. For a new model joining the PEcAn system the burden in particularly low – writing one conversion function provides access to n inputs. Similarly, PEcAn performs all other operations/manipulations (extracting a site, downscaling, gap filling, etc) within the PEcAn standard, which means these operations only need be implemented once.

-

Consider a generic met data product named MET for simplicity. PEcAn will use a function, download.MET, to pull data for the selected year from a public data source (e.g. Ameriflux, North American Regional Reanalysis, etc). Next, PEcAn will use a function, met2CF.MET, to convert the data into the PEcAn standard. If the data is already at the site scale it will then gapfill the data. If the data is a regional or global data product, PEcAn will then permute the data to allow easier site-level extraction, then it will extract data for the requested site and data range. Modules to address the temporal and spatial downscaling of meteorological data products, as well as their uncertainties, are in development but not yet part of the operational workflow. All of these functions are located within the data.atmosphere module.

-

Once data is in the standard format and processed, it will be converted to the model-specific format using a met2model.MODEL function (located in that MODEL’s module).

-

More detailed information on how PEcAn processes inputs can be found on our [Input Conversion] page.

-
-
-

6.2.3 Troubleshooting meteorological conversions

-

At the current moment, most of the issues below address possible errors that the Ameriflux meteorology workflow might report

-
-

6.2.3.1 Could not do gapfill … The following variables have NA’s

-

This error message means that there were gaps in the downloaded data, for whatever variables that were listed, which were larger than the current algorithm could fill. Particularly common is missing radiation or PAR data, as Ameriflux frequently converts nighttime data to NULL, and work is in progress to detect this based on solar geometry. Also common are incomplete years (first or last year of tower operations).

-
-
-

6.2.3.2 Could not get information about . Is this an Ameriflux site?

-

This message occurs when PEcAn believes that a site is part of Ameriflux (because it was listed on the Ameriflux or FLUXNET webpage and has a US-* site code), but no data is present on the Ameriflux server. The most common reasons for this is that you have selected a site that has not submitted data to Ameriflux yet (or that data hasn’t been processed yet), or you have selected a year that’s outside the tower’s operational period. Visit Ameriflux and FLUXNET for lists of available site years.

-
-
-

6.2.3.3 Could not download data for for the year

-

This is similar to the previous error, but in this case PEcAn did find data for the site listed, but just not for the year requested. This can usually be fixed by just altering the years of the run to match those with available data.

-
-
-

6.2.3.4 I could not find the requested var (or dimvar) in the file!

-

PEcAn could not find a required variable within the downloaded file. Most likely this is due to that variable not being measured at this site. The most common cause of failure is the absence of atmospheric pressure data (PRESS), but since most models have a low sensitivity to this variable we are working on methods to estimate this from other sources.

-
-
-
-
-

6.3 Selecting Plant Functional Types (PFTs) and other parameter groupings.

-
-

6.3.1 Using existing PFTs

-

PEcAn does not automatically know what vegetation types are present at your study site so you need to select the PFT.

-

Some models, such as ED2 and LINKAGES, support competition among multiple PFTs and thus you are encouraged to highlight multiple choices. Other models, such as SIPNET and DALEC, only support one PFT at a site.

-

Many models also have parameters that control non-vegetation processes (e.g. soil biogeochemistry and hydrology). PEcAn allows users to assign these parameters to functional groups as well (e.g. a soils PFT)

-
-
-

6.3.2 Creating new PFTs

-

To modify or add a new Plant Functional Type (PFT), or to change a PFT’s priors, navigate -on the grey menu bar to Data > PFTs

-
    -
  1. To add a new pft, click “new PFT” at the top and enter a name and description. (hint: -we’re trying to name PFTs based on model.biome.pft, ED2 is the default model if one -isn’t specified)

  2. -
  3. To add new species to a PFT click on [+] View Related Species and type the species, -genus, or family you are looking for into the Search box. Click on the + to add.

  4. -
  5. To remove a species from a PFT, click on [+] View Related Species and click on the X -of the species you want to remove from the PFT.

  6. -
  7. To remove a prior, click [-] View Related Prior and click on the X of the variable who’s -prior you want to remove. This will cause the parameter to be excluded from all -analyses (meta-analysis, sensitivity analysis, etc) and revert to its default value.

  8. -
  9. To add a prior, choose one from the white box of priors on the right to choose.

  10. -
  11. To view the specification of a prior, or to add a new prior, click BETY-DB > Priors and -enter the information on the variable, distribution name, distribution parameters, etc. N -is the sample size underlying the prior specification (0 is ok for uninformative priors).

  12. -
  13. You can also got to Data > Variables in order to use the search function to find an -existing variable (or create a new one). Please try not to create new variables -unnecessarily (e.g. changes of variable name or units to what your model uses is handled -internally, so you want to find the trait with the correct MEANING).

  14. -
-

Additional information on adding PFTs, Species, and Priors can be found in Adding An [Ecosystem Model].

-
-
-

6.3.3 Choosing initial vegetation

-

On the Input Selection webpage, in addition to selecting PFTs, start & end dates, and meteorology, many models also require some way of specifying the initial conditions for the vegetation, which may range from setting the aboveground biomass and LAI up to detailed inventory-like data on species composition and stand structure.

-

At the moment, PEcAn has three cases for initial conditions:

-
    -
  1. If files already exist in the database, they can simply be selected from the menu. For ED2, there are 3 different veg files (site, pss, css) and it is important that you select a complete set, not mix and match.

  2. -
  3. If files don’t exist they can be uploaded following the instructions in Create a database file record for the input data.

  4. -
  5. Automated vegetation initial condition workflow

  6. -
-

As with meteorology, PEcAn is working to develop a model-agnostic workflow for converting various sources of vegetation data to common standards, developing common processing tools, and then writing out to model-specific formats. This process is in a much early stage than the meteorology workflow, as we are still researching what the options are for standard formats, but ultimately aims to be much more broad in scope, considering not just plot inventory data but also historical documentation, paleoecological proxies, satellite remote sensing (e.g. LANDSAT), airborne hyperspectral imagery, and active remote sensing (Lidar, Radar).

-

At the moment, what is functional is a prototype workflow that works for inventory-based vegetation data. This data can come from either files that have been registered with the BETY Inputs and Formats tables or can be queried from the USFS Forest Inventory and Analysis (FIA). For more information visit Section 13.1.2.2 Vegetation Data

-
-
-

6.3.4 US FIA

-

This tool works with an internal copy of the FIA that is uploaded to a postGRES database along side BETY, however for space reasons this database does not ship with the PEcAn VM. To turn this feature on:

-
    -
  1. Download and Install the FIA database. Instructions in Installing data for PEcAn
  2. -
  3. For web-base runs, specify the database settings in the config.php
  4. -
  5. For R-based runs, specify the database settings in the THE PEcAn XML
  6. -
-

More detailed information on how PEcAn processes inputs can be found on our [Input Conversion]page.

-
-
-

6.3.5 Spin up

-

A number of ecosystem models are typically initialized by spinning up to steady state. At the moment PEcAn doesn’t handle spin up automatically (e.g. looping met, checking for stability), but there are various ways to achieve a spin-up within the system.

-

Option 1: If there are model-specific settings in a model’s settings/config file, then that file can be accessed by clicking on the Edit model config check box. If this box is selected then PEcAn will pause the site run workflow after it has generated your model config file, but before it runs the model, and give you an opportunity to edit the file by hand, allowing you to change any model-specific spin up settings (e.g met recycling, spin up length)

-

Option 2: Set start_year very early and set the met drivers to be a long time series (e.g. PalEON, something custom uploaded to Inputs)

-

Option 3: In the MODEL_TYPE table, add your model’s restart format as an optional input, modify the model specific write.config function to use that restart, and then load a previous spin-up to the Inputs table

-

Beyond these options, we hope to eventually develop more general, model-agnostic tools for spin up. In particular, we have started to explore the accelerated spin-up and semi-analytical techniques being developed by Yiqi Luo’s lab

-
-
-

6.3.6 Selecting a soils product

-

Many models have requirements for soils information, which may include: site-specific soil texture and depth information; soil biogeochemical initial conditions (e.g. soil carbon and nitrogen pools); soil moisture initial conditions; and soil thermal initial conditions.

-

As with Choosing initial vegetation, we eventually hope to develop data standards, soils workflows, and spin-up tools, but at the moment this workflow is in the early stages of development. Model requirements need to be met byCreating a new Input record in BETY into the database or using files that have already been uploaded. Similar to met, we recommend that this file be in the PEcAn-standard netCDF described below, but model-specific files can also be registered.

-
-
-

6.3.7 Soil texture, depth, and physical parameters

-

A PEcAn-standard netCDF file format exists for soil texture, depth, and physical parameters, using PEcAn standard names that are largely a direct extention of the CF standard.

-

The easiest way to create this file is with the PEcAn R function soil2netcdf as described in the Soil Data section of the Advanced Users Guide.

-

A table of standard names and units can be listed using PEcAn.data.land::soil.units() with no arguments.

-

More detailed information on how PEcAn processes inputs can be found on our [Input Conversion] page.

-
-
-

6.3.8 Other model inputs

-

Finally, any other model-specific inputs (e.g. N deposition, land use history, etc), should be met by Creating a new Input record in BETY or using files that have already been uploaded.

- -
-
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - - diff --git a/develop_test/contributor-covenant-code-of-conduct.html b/develop_test/contributor-covenant-code-of-conduct.html deleted file mode 100644 index a21f2c8fd..000000000 --- a/develop_test/contributor-covenant-code-of-conduct.html +++ /dev/null @@ -1,753 +0,0 @@ - - - - - - - 2 Contributor Covenant Code of Conduct | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

2 Contributor Covenant Code of Conduct

-

Our Pledge

-

In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.

-

Our Standards

-

Examples of behavior that contributes to creating a positive environment include:

-
    -
  • Using welcoming and inclusive language
  • -
  • Being respectful of differing viewpoints and experiences
  • -
  • Gracefully accepting constructive criticism
  • -
  • Focusing on what is best for the community
  • -
  • Showing empathy towards other community members
  • -
-

Examples of unacceptable behavior by participants include:

-
    -
  • The use of sexualized language or imagery and unwelcome sexual attention or advances
  • -
  • Trolling, insulting/derogatory comments, and personal or political attacks
  • -
  • Public or private harassment
  • -
  • Publishing others’ private information, such as a physical or electronic address, without explicit permission
  • -
  • Other conduct which could reasonably be considered inappropriate in a professional setting
  • -
-

Our Responsibilities

-

Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.

-

Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.

-

Scope

-

This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.

-

Enforcement

-

Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at pecanproj[at]gmail.com. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.

-

Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project’s leadership.

-

Attribution

-

This Code of Conduct is adapted from the Contributor Covenant version 1.4, available at http://contributor-covenant.org/version/1/4.

- -
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - - diff --git a/develop_test/data-assimilation-with-dart.html b/develop_test/data-assimilation-with-dart.html deleted file mode 100644 index c8207b6d8..000000000 --- a/develop_test/data-assimilation-with-dart.html +++ /dev/null @@ -1,801 +0,0 @@ - - - - - - - 26 Data assimilation with DART | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

26 Data assimilation with DART

-

In addition to the state assimilation routines found in the assim.sequential module, another approach for state data assimilation in PEcAn is through the DART workflow created by the DARES group in NCAR.

-

This section gives a straight-forward explanation how to implement DART, focused on the technical aspects of the implementation. If there are any questions, feel free to send @Viskari an email (tt.viskari@gmail.com) or contacting DART support as they are quite awesome in helping people with problems. Also, if there are any suggestions on how to improve the wiki, please let me know.

-

Running with current folders in PEcAn

-

Currently the DART folders in PEcAn are that you can simply copy the structure there over a downloaded DART workflow and it should replace/add relevant files and folders. The most important step after that is to check and change the run paths in the following files: -Path_name files in the work folders -T_ED2IN file, as it indicates where the run results be written. -advance_model.csh, as it indicates where to copy files from/to.

-

Second thing is setting the state vector size. This is explained in more detail below, but essentially this is governed by the variable model_size in model_mod.f90. In addition to this, it should be changed in utils/F2R.f90 and R2F.f90 programs, which are responsible for reading and writing state variable information for the different ensembles. This also will be expanded below. Finally, the new state vector size should be updated for any other executable that runs it.

-

Third thing needed are the initial condition and observation sequence files. They will always follow the same format and are explained in more detail below.

-

Finally the ensemble size, which is the easiest to change. In the work subfolder, there is a file named input.nml. Simply changing the ensemble size there will set it for the run itself. Also remember that initial conditions file should have the equal amount of state vectors as there are ensemble members.

-

Adjusting the workflow

-

The central file for the actual workflow is advance_model.csh. It is a script DART calls to determine how the state vector changes between the two observation times and is essentially the only file one needs to change when changing state models or observations operators. The file itself should be commented to give a good idea of the flow, but beneath is a crude order of events. -1. Create a temporary folder to run the model in and copy/link required files in to it. -2. Read in the state vector values and times from DART. Here it is important to note that the values will be in binary format, which need to be read in by a Fortran program. In my system, there is a program called F2R which reads in the binary values and writes out in ascii form the state vector values as well as which ED2 history files it needs to copy based on the time stamps. -3. Run the observation operator, which writes the state vector state in to the history files and adjusts them if necessary. -4. Run the program. -5. Read the new state vector values from output files. -6. Convert the state vector values to the binary. In my system, this is done by the program R2F.

-

Initial conditions file

-

The initial conditions file, commonly named filter_ics although you can set it to something else in input.nml, is relatively simple in structure. It has one sequence repeating over the number of ensemble members. -First line contains two times: Seconds and days. Just use one of them in this situation, but it has to match the starting time given in input.nml. -After that each line should contain a value from the state vector in the order you want to treat them. -R functions filter_ics.R and B_filter_ics.R in the R folder give good examples of how to create these.

-

Observations files

-

The file which contains the observations is commonly known as obs_seq.out, although again the name of the file can be changed in input.nml. The structure of the file is relatively straight-forward and the R function ObsSeq.R in the R subfolder has the write structure for this. Instead of writing it out here, I want to focus on a few really important details in this file. -Each observations will have a time, a value, an uncertainty, a location and a kind. The first four are self-explanatory, but the kind is really important, but also unfortunately really easy to misunderstand. In this file, the kind does not refer to a unit or a type of observation, but which member of the state vector is this observation of. So if the kind was, for example, 5, it would mean that it was of the fifth member of the state vector. However, if the kind value is positive, the system assumes that there is some sort of an operator change in comparing the observation and state vector value which is specified in a subprogram in model_mod.f90.

-

So for an direct identity comparison between the observation and the state vector value, the kind needs to be negative number of the state vector component. Thus, again if the observation is of the fifth state vector value, the kind should be set as -5. Thus it is recommendable that the state vector values have already been altered to be comparable with the observations.

-

As for location, there are many ways to set in DART and the method needs to be chosen when compiling the code by giving the program which of the location mods it is to use. In our examples we used a 1-dimensional location vector with scaled values between 0 and 1. For future it makes sense to switch to a 2 dimensional long- and lat-scale, but for the time being the location does not impact the system a lot. The main impact will be if the covariances will be localized, as that will be decided on their locations.

-

State variable vector in DART

-

Creating/adjusting a state variable vector in DART is relatively straight-forward. Below are listed the steps to specify a state variable vector in DART.

-

I. For each specific model, there should be an own folder within the DART root models folder. In this folder there is a model_mod.f90, which contains the model specific subroutines necessary for a DART run.

-

At the beginning of this file there should be the following line:

-

integer, parameter :: model_size = [number]

-

The number here should be the number of variables in the vector. So for example if there were three state variables, then the line should look like this:

-

integer, parameter :: model_size = 3

-

This number should also be changed to match with any of the other executables called during the run as indicated by the list above.

-
    -
  1. In the DART root, there should be a folder named obs_kind, which contains a file called DEFAULT_obs_kind_mod.F90. It is important to note that all changes should be done to this file instead of obs_kind_mod.f90, as during compilation DART creates obs_kind_mod.f90 from DEFAULT_obs_kind_mod.F90. -This program file contains all the defined observation types used by DART and numbers them for easier reference later. Different types are classified according to observation instrument or relevant observation phenomenon. Adding a new type only requires finding an unused number and starting a new identifying line with the following:
  2. -
-

integer, parameter, public :: & -KIND_…

-

Note that the observation kind should always be easy to understand, so avoid using unnecessary acronyms. For example, when adding an observation type for Leaf Area Index, it would look like below:

-

integer, parameter, public :: & -KIND_LEAF_AREA_INDEX = [number]

-
    -
  1. In the DART root, there should be a folder named obs_def, which contains several files starting with obs_def_. There files contain the different available observation kinds classified either according to observation instrument or observable system. Each file starts with the line
  2. -
-

! BEGIN DART PREPROCESS KIND LIST

-

And end with line

-

! END DART PREPROCESS KIND LIST

-

The lines between these two should contain

-

! The desired observation reference, the observation type, COMMON_CODE.

-

For example, for observations relating to phenology, I have created a file called obs_def_phen_mod.f90. In this file I define the Leaf Area Index observations in the following way.

-

! BEGIN DART PREPROCESS KIND LIST -! LAI, TYPE_LEAF_AREA_INDEX, COMMON_CODE -! END DART PREPROCESS KIND LIST

-

Note that the exclamation marks are necessary for the file.

-
    -
  1. In the model specific folder, in the work subfolder there is a namelist file input.nml. This contains all the run specific information for DART. In it, there is a subtitle &preprocess, under which there is a line
  2. -
-

input_files = ‘….’

-

This input_files sections must be set to refer to the obs_def file created in step III. The input files can contain references to multiple obs_def files if necessary.

-

As an example, the reference to the obs_def_phen_mod.f90 would look like -input_files = ‘../../../obs_def/obs_def_phen_mod.f90’

-

V. Finally, as an optional step, the different values in state vector can be typed. In model_mod, referred to in step I, there is a subroutine get_state_meta_data. In it, there is an input variable index_in, which refers to the vector component. So for instance for the second component of the vector index_in would be 2. If this is done, the variable kind has to be also included at the beginning of the model_mod.f90 file, at the section which begins

-

use obs_kind_mod, only ::

-

The location of the variable can be set, but for a 0-dimensional model we are discussing here, this is not necessary.

-

Here, though, it is possible to set the variable types by including the following line

-

if(index_in .eq. [number]) var_type = [One of the variable kinds set in step II]

-
    -
  1. If the length of the state vector is changed, it is important that the script ran with DART produces a vector of that length. Change appropriately if necessary.
  2. -
-

After these steps, DART should be able to run with the state vector of interest.

- -
- - - -
- -
-
-
- - -
-
- - - - - - - - - - - - - - - - diff --git a/develop_test/database-sync.html b/develop_test/database-sync.html deleted file mode 100644 index 68f2c656d..000000000 --- a/develop_test/database-sync.html +++ /dev/null @@ -1,912 +0,0 @@ - - - - - - - 16 Database synchronization | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

16 Database synchronization

-

The database synchronization consists of 2 parts: -- Getting the data from the remote servers to your server -- Sharing your data with everybody else

-
-

16.1 How does it work?

-

Each server that runs the BETY database will have a unique machine_id and a sequence of ID’s associated. Whenever the user creates a new row in BETY it will receive an ID in the sequence. This allows us to uniquely identify where a row came from. This is information is crucial for the code that works with the synchronization since we can now copy those rows that have an ID in the sequence specified. If you have not asked for a unique ID your ID will be 99.

-

The synchronization code itself is split into two parts, loading data with the load.bety.sh script and exporting data using dump.bety.sh. If you do not plan to share data, you only need to use load.bety.sh to update your database.

-
-
-

16.2 Set up

-

Requests for new machine ID’s is currently handled manually. To request a machine ID contact Rob Kooper . In the examples below this ID is referred to as ‘my siteid’.

-

To setup the database to use this ID you need to call load.bety in ‘CREATE’ mode (replacing with the ID if your site)

-
sudo -u postgres {$PECAN}/scripts/load.bety.sh -c -u -m <my siteid> 
-

WARNING: At the moment running CREATE deletes all current records in the database. If you are running from the VM this includes both all runs you have done and all information that the database is prepopulated with (e.g. input and model records). Remote records can be fetched (see below), but local records will be lost (we’re working on improving this!)

-
-
-

16.3 Fetch latest data

-

When logged into the machine you can fetch the latest data using the load.bety.sh script. The script will check what site you want to get the data for and will remove all data in the database associated with that id. It will then reinsert all the data from the remote database.

-

The script is configured using environment variables. The following variables are recognized: -- DATABASE: the database where the script should write the results. The default is bety. -- OWNER: the owner of the database (if it is to be created). The default is bety. -- PG_OPT: additional options to be added to psql (default is nothing). -- MYSITE: the (numerical) ID of your site. If you have not requested an ID, use 99; this is used for all sites that do not want to share their data (i.e. VM). 99 is in fact the default. -- REMOTESITE: the ID of the site you want to fetch the data from. The default is 0 (EBI). -- CREATE: If ‘YES’, this indicates that the existing database (bety, or the one specified by DATABASE) should be removed. Set to YES (in caps) to remove the database. THIS WILL REMOVE ALL DATA in DATABASE. The default is NO. -- KEEPTMP: indicates whether the downloaded file should be preserved. Set to YES (in caps) to keep downloaded files; the default is NO. -- USERS: determines if default users should be created. Set to YES (in caps) to create default users with default passwords. The default is NO.

-

All of these variables can be specified as command line arguments as well, to see the options use -h.

-
load.bety.sh -h
-./scripts/load.bety.sh [-c YES|NO] [-d database] [-h] [-m my siteid] [-o owner] [-p psql options] [-r remote siteid] [-t YES|NO] [-u YES|NO]
- -c create database, THIS WILL ERASE THE CURRENT DATABASE, default is NO
- -d database, default is bety
- -h this help page
- -m site id, default is 99 (VM)
- -o owner of the database, default is bety
- -p additional psql command line options, default is empty
- -r remote site id, default is 0 (EBI)
- -t keep temp folder, default is NO
- -u create carya users, this will create some default users
-
-dump.bety.sh -h
-./scripts/dump.bety.sh [-a YES|NO] [-d database] [-h] [-l 0,1,2,3,4] [-m my siteid] [-o folder] [-p psql options] [-u YES|NO]
- -a use anonymous user, default is YES
- -d database, default is bety
- -h this help page
- -l level of data that can be dumped, default is 3
- -m site id, default is 99 (VM)
- -o output folder where dumped data is written, default is dump
- -p additional psql command line options, default is -U bety
- -u should unchecked data be dumped, default is NO
-
-
-

16.4 Sharing data

-

Sharing your data requires a few steps. First, before entering any data, you will need to request an ID from the PEcAn developers. Simply open an issue at github and we will generate an ID for you. If possible, add the URL of your data host.

-

You will now need to synchronize the database again and use your ID. For example if you are given ID=42 you can use the following command: MYID=42 REMOTEID=0 ./scripts/load.bety.sh. This will load the EBI database and set the ID’s such that any data you insert will have the right ID.

-

To share your data you can now run the dump.bey.sh. The script is configured using environment variables, the following variables are recognized: -- DATABASE: the database where the script should write the results. The default is bety. -- PG_OPT: additional options to be added to psql (default is nothing). -- MYSITE: the ID of your site. If you have not requested an ID, use 99, which is used for all sites that do not want to share their data (i.e. VM). 99 is the default. -- LEVEL: the minimum access-protection level of the data to be dumped (0=private, 1=restricted, 2=internal collaborators, 3=external collaborators, 4=public). The default level for exported data is level 3. -- note that currently only the traits and yields tables have restrictions on sharing. If you share data, records from other (meta-data) tables will be shared. If you wish to extend the access_level to other tables please submit a feature request. -- UNCHECKED: specifies whether unchecked traits and yields be dumped. Set to YES (all caps) to dump unchecked data. The default is NO. -- ANONYMOUS: specifies whether all users be anonymized. Set to YES (all caps) to keep the original users (INCLUDING PASSWORD) in the dump file. The default is NO. -- OUTPUT: the location of where on disk to write the result file. The default is ${PWD}/dump.

-

NOTE: If you want your dumps to be accessible to other PEcAn servers you need to perform the following additional steps

-
    -
  1. Open pecan/scripts/load.bety.sh
  2. -
  3. In the DUMPURL section of the code add a new record indicating where you are dumping your data. Below is the example for SITE number 1 (Boston University)
  4. -
-
 elif [ "${REMOTESITE}" == "1" ]; then
- DUMPURL="http://psql-pecan.bu.edu/sync/dump/bety.tar.gz"
-
    -
  1. Check your Apache settings to make sure this location is public
  2. -
  3. Commit this code and submit a Pull Request
  4. -
  5. From the URL in the Pull Request, PEcAn administrators will update the machines table, the status map, and notify other users to update their cron jobs (see Automation below)
  6. -
-

Plans to simplify this process are in the works

-
-
-

16.5 Automation

-

Below is an example of a script to synchronize PEcAn database instances across the network.

-

db.sync.sh

-
#!/bin/bash 
-## make sure psql is in PATH
-export PATH=/usr/pgsql-9.3/bin/:$PATH 
-## move to export directory
-cd /fs/data3/sync 
-## Dump Data
-MYSITE=1 /home/dietze/pecan/scripts/dump.bety.sh 
-## Load Data from other sites
-MYSITE=1 REMOTESITE=2 /home/dietze/pecan/scripts/load.bety.sh 
-MYSITE=1 REMOTESITE=5 /home/dietze/pecan/scripts/load.bety.sh 
-MYSITE=1 REMOTESITE=0 /home/dietze/pecan/scripts/load.bety.sh 
-## Timestamp sync log
-echo $(date +%c) >> /home/dietze/db.sync.log
-

Typically such a script is set up to run as a cron job. Make sure to schedule this job (crontab -e) as the user that has database privileges (typically postgres). The example below is a cron table that runs the sync every hour at 12 min after the hour.

-
MAILTO=user@yourUniversity.edu
-12 * * * * /home/dietze/db.sync.sh
-
-
-

16.6 Database maintentance

-

All databases need maintenance performed on them. Depending upon the database type this can happen automatically, or it needs to be run through a scheduler or manually. The BETYdb database is Postgresql and it needs to be reindexed and vacuumed on a regular basis. Reindexing introduces efficiencies back into the database by reorganizing the indexes. Vacuuming the database frees up resources to the database by rearranging and compacting the database. Both of these operations are necessary and safe. As always if there’s a concern, a backup of the database should be made ahead of time. While running the reindexing and vacuuming commands, users will notice a slowdown at times. Therefore it’s better to run these maintenance tasks during off hours.

-
-

16.6.1 Reindexing the database

-

As mentioned above, reindexing allows the database to become more efficient. Over time as data gets updated and deleted, the indexes become less efficient. This has a negative inpact on executed statements. Reindexing makes the indexes efficient again (at least for a while) allowing faster statement execution and reducing the overall load on the database.

-

The reindex.bety.sh script is provided to simplify reindexing the database.

-
reindex.bety.sh -h
-./reindex.bety.sh [-c datalog] [-d database] [-h] [-i table names] [-p psql options] [-q] [-s] [-t tablename]
- -c catalog, database catalog name used to search for tables, default is bety
- -d database, default is bety
- -h this help page
- -i table names, list of space-separated table names to skip over when reindexing
- -p additional psql command line options, default is -U bety
- -q the reindexing should be quiet
- -s reindex the database after reindexing the tables (this should be done sparingly)
- -t tablename, the name of the one table to reindex
-

If the database is small enough it’s reasonable to reindex the entire database at one time. To do this manually run or schedule the REINDEX statement. For example:

-
reindex.bety.sh -s
-

For larger databases it may be desireable to reindex entire tables at a time. An efficient way to do this is to reindex the larger tables and then the entire database. For example:

-
reindex.bety.sh -t traits; reindex.bety.sh -t yields;
-reindex.bety.sh -s
-

For very large databases it may be desirable to reindex one or more individual indexes before reindexing tables and the databases. In this case running specific psql commands to reindex those specific indexes, followed by reindexing the table is a possible approach. For example:

-
psql -U bety -c "REINDEX INDEX index_yields_on_citation_id; REINDEX INDEX index_yields_on_cultivar_id;"
-reindex.bety.sh -t yields;
-

Splitting up the indexing commands over time allows the database to operate efficiently with minimal impact on users. One approach is to schedule the reindexing of large, complex tables at a spcific off-time during the week, followed by a general reindexing and excluding those large tables on a weekend night.

-

Please refere to the Automation section above for information on using cron to schedule reindexing commands.

-
-
-

16.6.2 Vacuuming the database

-

Vacuuming the BETYdb Postgresql database reduces the amount of resources it uses and introduces its own efficiencies.

-

Over time, modified and deleted records leave ‘holes’ in the storage of the database. This is a common feature for most databases. Each database has its own way of handing this, in Postgresql it’s the VACUUM command. The VACUUM command performs two main operations: cleaning up tables to make memory use more efficient, and analyze tables for optimum statement execution. The use of the keyword ANALYZE indicates the second operation should take place.

-

The vacuum.bety.sh script is provided to simplify vacuuming the database.

-
vacuum.bety.db -h
-./vacuum.bety.sh [-c datalog] [-d database] [-f] [-h] [-i table names] [-n] [-p psql options] [-q] [-s] [-t tablename] [-z]
- -c catalog, database catalog name used to search for tables, default is bety
- -d database, default is bety
- -f perform a full vacuum to return resources to the system. Specify rarely, if ever
- -h this help page
- -i table names, list of space-separated table names to skip over when vacuuming
- -n only vacuum the tables and do not analyze, default is to first vacuum and then analyze
- -p additional psql command line options, default is -U bety
- -q the export should be quiet
- -s skip vacuuming the database after vacuuming the tables
- -t tablename, the name of the one table to vacuum
- -z only perform analyze, do not perform a regular vacuum, overrides -n and -f, sets -s
-

For small databases with light loads it may be possible to set aside a time for a complete vacuum. During this time, commands executed against the database might fail (a temporary condition as the database gets cleaned up). The following commands can be used to perform all the vaccum operations in one go.

-
vacuum.bety.sh -f
-

Generally it’s not desireable to have down time. If the system running the database doesn’t need resources that the database is using returned to it, a FULL vacuum can be avoided. This is the default behavior of the script

-
vacuum.bety.sh
-

In larger databases, vacuuming the entire database can take a long time causing a negative impact on users. This means that individual tables need to be vacuumed. How often a vacuum needs to be performed is dependent upon a table’s activity. The more frequently updates and deletes occur on a table, the more frequent the vaccum should be. For large tables it may be desireable to separate the table cleanup from the analysis. An example for completely vacuuming and analyzing a table is:

-
psql -U bety -c "VACUUM traits; VACUUM ANALYZE traits;"
-

Similar to indexes, vacuuming the most active tables followed by general database vacuuming and vacuum analyze may be a desireable approach.

-

Also note that it isn’t necessary to run VACUUM ANALYZE for each vacuum performed. Separating the commands and performing a VACUUM ANALYZE after several regular vacuums may be sufficient, with less load on the database.

-

If the BETYdb database is running on a system with limited resources, or with resources that have become limited, the VACCUM command can return resources to the system from the database. The normal vacuuming process releases resources back to the database for reuse, but not to the system; generally this isn’t a problem. Postgresql has a VACUUM keyword FULL that returns resources back to the system. Requesting a FULL vacuum will lock the table being vacuumed while it is being re-written preventing any statements from being executed against it. If performing VECUUM FULL against the entire database, only the table being actively worked on is locked.

-

To minimize the impact a VACUUM FULL has on users, it’s best to perform a normal vacuum before a FULL vacuum. If this approach is taken, there sould be a minimal time gap between the normal VACUUM and the VACUUM FULL commands. A normal vacuum allows changes to be made thus requiring the full vacuum to handle those changes, extending it’s run time. Reducing the time between the two commands lessens the work VACUUM FULL needs to do.

-
psql -U bety -c "VACUUM yields; VACUUM FULL yields; VACUUM ANALYZE yields;"
-

Give its impact, it’s typically not desireable to perform a VACUUM FULL after every normal vacuum; it should be done on an “as needed” basis or infrequently.

-
-
-
-

16.7 Troubleshooting

-

There are several possibilities if a scheduled cron job apepars to be running but isn’t producing the expected results. The following are suggestions on what to try to resolve the issue.

-
-

16.7.1 Username and password

-

The user that scheduled a cron job may not have access permissions to the database. This can be easily confirmed by running the command line from the cron job while logged in as the user that scheduled the job. An error message will be shown if the user doesn’t have permissions.

-

To resolve this, be sure to include a valid database user (not a BETYdb user) with their credentials on the command in crontab.

-
-
-

16.7.2 db_hba.conf file

-

Iit’s possible that the machine hosting the docker image of the database doesn’t have permissions to access the database. This may due to the cron job running on a machine that is not the docker instance of the database.

-

It may be necessary to look at the loga on the hosting machine to determine if database access permissions are causing a problem. Logs are stored in different locations depending upon the Operating System of the host and upon other environmental factors. This document doesn’t provide information on where to find the logs.

-

To begin, it’s best to look at the contents of the relevent database configuration file. The following command will display the contents of the db_hba.conf file.

-
psql -U postgres -qAt -c "show hba_file" | xargs grep -v -E '^[[:space:]]*#'
-

This command should return a series of text lines. For each row except those begining with ‘local’, the fourth item describes the machines that can access the database. In some cases an IP mask is specified in the fifth that further restricts the machines that have access. The special work ‘all’ in the fourth column grants permissions to all machines. The last column on each line contains the authentication option for the machine(s) specified in the fourth column (with a possible fifth column IP mask modifier).

-

Ensure that the host machine is listed under the fourth column (machine addresse range, or ‘all’), is also included in the IP mask if one was specified, and finally that any authentication option are not set to ‘reject’. If the host machine is not included the db_hba.conf file will need to be updated to allow access.

-
-
-
-

16.8 Network Status Map

-

https://pecan2.bu.edu/pecan/status.php

-

Nodes: red = down, yellow = out-of-date schema, green = good

-

Edges: red = fail, yellow = out-of-date sync, green = good

-
-
-

16.9 Tasks

-

Following is a list of tasks we plan on working on to improve these scripts: -- pecanproject/bety#368 allow site-specific customization of information and UI elements including title, contacts, logo, color scheme.

- -
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - - diff --git a/develop_test/database.html b/develop_test/database.html deleted file mode 100644 index d14f19a9b..000000000 --- a/develop_test/database.html +++ /dev/null @@ -1,755 +0,0 @@ - - - - - - - 21 BETY Database Administration | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

21 BETY Database Administration

-

This section provides additional details about the BETY database used by PEcAn. It will discuss best practices for setting up the BETY database, how to backup the database and how to restore the database.

-
-

21.1 Best practices

-

When using the BETY database in non testing mode, it is best not to use the default users. This is accomplished when running the initialize of the database. When the database is initally created the database will be created with some default users (best known is the carya user) as well as the guestuser that can be used in the BETY web application. To disable these users you will either need to disable the users from the web interface, or you can reinitialize the database and remove the -u flag from the command line (the -u flag will create the default users). To disable the guestuser as well you can remove the -g flag from the command line, or disable the account from BETY.

-

The default installation of BETY and PEcAn will assume there is a database called bety with a default username and password. The default installation will setup the database account to not have any superuser abilities. It is also best to limit access to the postgres database from trusted hosts, either by using firewalls, or configuring postgresql to only accept connections from a limited set of hosts.

-
-
-

21.2 Backup of BETY database

-

It is good practice to make sure you backup the BETY database. Just creating a copy of the files on disk is not enough to ensure you have a valid backup. Most likely if you do this you will end up with a corrupted backup of the database.

-

To backup the database you can use the pg_dump command, which will make sure the database id backed up in a consistent state. You can run sudo -u postgres pg_dump -d bety -Z 9 -f bety.sql.gz, this will create a compressed file that can be used to resotore the database.

-

In the PEcAn distribution in scripts folder there is a script called backup.bety.sh. This script will create the backup of the database. It will create multiple backups allowing you to restore the database from one of these copies. The database will be backed up to one of the following files: -- bety-d-X, daily backup, where X is the day of the month. -- bety-w-X, weekly backup, where X is the week number in the year -- bety-m-X, montly backup, where X is the month of the year -- bety-y-X, yearly backup, where X is the actual year. -Using this scheme, we can restore the database using any of the files generated.

-

It is recommeneded to run this script using a cronjob at midnight such that you have a daily backup of the database and do not have to remember to create these backups. When running this script (either cron or by hand) make sure to place the backups on a different machine than the machine that holds the database in case of a larger system failure.

-
-
-

21.3 Restore of BETY database

-

Hopefully this section will never need to be used. Following are 5 steps that have been used to restore the database. Before you start it is worth it to read up online a bit on restoring the database as well as join the slack channel and ask any of the people there for help.

-
    -
  1. stop apache (BETY/PEcAn web apps) service httpd stop or service apache2 stop
  2. -
  3. backup database (you know just incase) pg_dump -d bety > baddb.sql
  4. -
  5. drop database sudo -u postgres psql -c 'drop database bety'
  6. -
  7. create database sudo -u postgres psql -c 'create database bety with owner bety'
  8. -
  9. load database (assuming dump is called bety.sql.gz) zcat bety.sql.gz | grep -v search_path | sudo -u postgres psql -d bety
  10. -
  11. start apache again service httpd start or service apache2 start
  12. -
-

If during step 5 there is a lot of errors, it is helpful to add -v ON_ERROR_STOP=1 to the end of the command. This will stop the restore at the first error and will help with debugging the issue.

- -
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - - diff --git a/develop_test/developer-devtools.html b/develop_test/developer-devtools.html deleted file mode 100644 index ae75073e0..000000000 --- a/develop_test/developer-devtools.html +++ /dev/null @@ -1,760 +0,0 @@ - - - - - - - 32 devtools package | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

32 devtools package

-

Provides functions to simplify development

-

Documentation: -The R devtools package

- -

other tips for devtools (from the documentation):

-
    -
  • Adding the following to your ~/.Rprofile will load devtools when -running R in interactive mode:
  • -
- -
    -
  • Adding the following to your .Rpackages will allow devtools to recognize package by folder name, rather than directory path
  • -
- -

Now, devtools can take pkg as an argument instead of /path/to/pkg/, -e.g. so you can use build("pkg") instead of build("/path/to/pkg/")

- -
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - - diff --git a/develop_test/developer-guide.html b/develop_test/developer-guide.html deleted file mode 100644 index 678a9d804..000000000 --- a/develop_test/developer-guide.html +++ /dev/null @@ -1,1630 +0,0 @@ - - - - - - - 8 Developer guide | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

8 Developer guide

- - -
-

8.1 Updating PEcAn Code and Bety Database

-

Release notes for all releases can be found here.

-

This page will only list any steps you have to do to upgrade an existing system. When updating PEcAn it is highly encouraged to update BETY. You can find instructions on how to do this, as well on how to update the database in the Updating BETYdb gitbook page.

-
-

8.1.1 Updating PEcAn

-

The latest version of PEcAn code can be obtained from the PEcAn repository on GitHub:

- -

The PEcAn build system is based on GNU Make. -The simplest way to install is to run make from inside the PEcAn directory. -This will update the documentation for all packages and install them, as well as all required dependencies.

-

For more control, the following make commands are available:

-
    -
  • make document – Use devtools::document to update the documentation for all package. -Under the hood, this uses the roxygen2 documentation system.

  • -
  • make install – Install all packages and their dependnencies using devtools::install. -By default, this only installs packages that have had their code changed and any dependent packages.

  • -
  • make check – Perform a rigorous check of packages using devtools::check

  • -
  • make test – Run all unit tests (based on testthat package) for all packages, using devtools::test

  • -
  • make clean – Remove the make build cache, which is used to track which packages have changed. -Cache files are stored in the .doc, .install, .check, and .test subdirectories in the PEcAn main directory. -Running make clean will force the next invocation of make commands to operate on all PEcAn packages, regardless of changes.

  • -
-

The following are some additional make tricks that may be useful:

-
    -
  • Install, check, document, or test a specific package – make .<cmd>/<pkg-dir>; e.g. make .install/utils or make .check/modules/rtm

  • -
  • Force make to run, even if package has not changed – make -B <command>

  • -
  • Run make commands in parallel – make -j<ncores>; e.g. make -j4 install to install packages using four parallel processes. Note that packages containing compiled code (e.g. PEcAn.RTM, PEcAn.BASGRA) might fail when j is greater than 1, because of limitations in the way R calls make internally while compiling them. See GitHub issue 1976 for more details.

  • -
-

All instructions for the make build system are contained in the Makefile in the PEcAn root directory. -For full documentation on make, see the man pages by running man make from a terminal.

- -
-
-
-

8.2 Git and GitHub Workflow

-

Using Git

- -
-

8.2.1 Using Git

-

This document describes the steps required to download PEcAn, make changes to code, and submit your changes.

-
    -
  • If you are new to GitHub or to PEcAn, start with the one-time set-up instructions under Before any work is done. Also see the excellent tutorials and references in the Git) section right below this list and at the bootom in References.
  • -
  • To make trivial changes, see [Quick and Easy].
  • -
  • To make a few changes to the code, start with the [Basic Workflow].
  • -
  • To make substantial changes and/or if plan to contribute over time see [Recommended Workflow: A new branch for each change].
  • -
-
-

8.2.1.1 Git

-

Git is a free & open source, distributed version control system designed -to handle everything from small to very large projects with speed and -efficiency. Every Git clone is a full-fledged repository with complete -history and full revision tracking capabilities, not dependent on -network access or a central server. Branching and merging are fast and -easy to do.

-

A good place to start is the GitHub 5 minute illustrated tutorial. -In addition, there are three fun tutorials for learning git:

- -

URLs In the rest of the document will use specific URL’s to clone the code. -There a few URL’s you can use to clone a project, using https, ssh and -git. You can use either https or git to clone a repository and write to -it. The git protocol is read-only. -This document describes the steps required to download PEcAn, make changes to code, and submit your changes.

-

If during above process you want to work on something else, commit all -your code, create a new branch, and work on new branch.

-
-
-

8.2.1.2 PEcAn Project and Github

- -

These instructions apply to other repositories too.

-
-
-

8.2.1.3 PEcAn Project Branches

-

We follow branch organization laid out on this page.

-

In short, there are three main branches you must be aware of:

-
    -
  • develop - Main Branch containing the latest code. This is the main branch you will make changes to.
  • -
  • master - Branch containing the latest stable code. DO NOT MAKE CHANGES TO THIS BRANCH.
  • -
  • release/vX.X.X - Named branches containing code specific to a release. Only make changes to this branch if you are fixing a bug on a release branch.
  • -
-
-
-

8.2.1.4 Milestones, Issues, Tasks

-

The Milestones, issues, and tasks can be used to organize specific features or research projects. In general, there is a heirarchy:

-
    -
  • milestones (Big picture, “Epic”): contains many issues, organized by release.
  • -
  • issues (Specific features / bugs, “Story”): may contain a list of tasks; represent
  • -
  • task list (to do list, “Tasks”): list of steps required to close an issue, e.g.:
  • -
-
- -CM# - -ESM2M - -ESM2G -
-rcp26 - - -r1i1p1 - -r1i1p1 -
-rcp45 - -r1i1p1, r3i1p1,r5i1p1 - -r1i1p1 - -r1i1p1 -
-rcp60 - - -r1i1p1 - -r1i1p1 -
-rcp85 - -r1i1p1 - -r1i1p1 - -r1i1p1 -
- - - - - - - - - - - -
* first do this
* then this
* completed when x and y
-
-
-

8.2.1.5 Editing files on GitHub

-

The easiest approach is to use GitHub’s browser based workflow. This is useful when your change is a few lines, if you are editing a wiki, or if the edit is trivial (and won’t break the code). The GitHub documentation is here but it is simple: finding the page or file you want to edit, click “edit” and then the GitHub web application will automatically forking and branch, then allow you to submit a pull request. However, it should be noted that unless you are a member of the PEcAn project that the “edit” button will not be active and you’ll want to follow the workflow described below for forking and then submitting a pull request.

-
-
- -
-

8.2.3 Useful Git tools

-
-

8.2.3.1 GitHub Desktop

-

The easiest way to get working with GitHub is by installing the GitHub -client. For instructions for your specific OS and download of the -GitHub client, see https://help.github.com/articles/set-up-git. -This will help you set up an SSH key to push code back to GitHub. To -check out a project you do not need to have an ssh key and you can use -the https or git url to check out the code.

-
-
-

8.2.3.2 Git + Rstudio

-

Rstudio is nicely integrated with many development tools, including git and GitHub. -It is quite easy to check out source code from within the Rstudio program or browser. -The Rstudio documentation includes useful overviews of version control -and R package development.

-

Once you have git installed on your computer (see the Rstudio version control documentation for instructions), you can use the following steps to install the PEcAn source code in Rstudio.

-
-
-
-

8.2.4 Advanced

-
-

8.2.4.1 Fixing a release Branch

-

If you would like to make changes to a release branch, you must follow a different workflow, as the release branch will not contain the latest code on develop and must remain seperate.

-
    -
  1. Fetch upstream remote branches
  2. -
-

git fetch upstream

-
    -
  1. Checkout the correct release branch
  2. -
-

git checkout -b release/vX.Y.Z

-
    -
  1. Compile Code with make
  2. -
-

make

-
    -
  1. Make changes and commit them
  2. -
-

git add <changed_file.R> -git commit -m "Describe changes"

-
    -
  1. Compile and make roxygen changes -make -make document

  2. -
  3. Commit and push any files that were changed by make document

  4. -
  5. Make a pull request. It is essential that you compare your pull request to the remote release branch, NOT the develop branch.

  6. -
-
-
-

8.2.4.2 Tags

-

Git supports two types of tags: lightweight and annotated. For more information see the Tagging Chapter in the Git documentation.

-

Lightweight tags are useful, but here we discuss the annotated tags that are used for marking stable versions, major releases, and versions associated with published results.

-

The basic command is git tag. The -a flag means ‘annotated’ and -m is used before a message. Here is an example:

-

git tag -a v0.6 -m "stable version with foo and bar features, used in the foobar publication by Bob"

-

Adding a tag to the a remote repository must be done explicitly with a push, e.g.

-

git push v0.6

-

To use a tagged version, just checkout:

-

git checkout v0.6

-

To tag an earlier commit, just append the commit SHA to the command, e.g.

-

git tag -a v0.99 -m "last version before 1.0" 9fceb02

-
-
-
-

8.2.5 References

-
-

8.2.5.1 Git Documentation

- -
-
-

8.2.5.2 GitHub Documentation

-

When in doubt, the first step is to click the “Help” button at the top of the page.

- - -
-
-
-

8.2.6 GitHub use with PEcAn

-

In this section, development topics are introduced and discussed. PEcAn code lives within the If you are looking for an issue to work on, take a look through issues labled “good first issue”. To get started you will want to review

-

We use GitHub to track development.

-

To learn about GitHub, it is worth taking some time to read through the FAQ. When in doubt, the first step is to click the “Help” button at the top of the page.

-
    -
  • To address specific people, use a github feature called @mentions e.g. write @dlebauer, @robkooper, @mdietze, or @serbinsh … in the issue to alert the user as described in the GitHub documentation on notifications
  • -
-
-

8.2.6.1 Bugs, Issues, Features, etc.

-
-
-

8.2.6.2 Reporting a bug

-
    -
  1. (For developers) work through debugging.
  2. -
  3. Once you have identified a problem, that you can not resolve, you can write a bug report
  4. -
  5. Write a bug report
  6. -
  7. submit the bug report
  8. -
  9. If you do find the answer, explain the resolution (in the issue) and close the issue
  10. -
-
-
-

8.2.6.3 Required content

-

Note:

-
    -
  • a bug is only a bug if it is reproducible
  • -
  • clear bug reports save time
  • -
-
    -
  1. Clear, specific title
  2. -
  3. Description -
  4. -
-
    -
  • What you did
  • -
  • What you expected to happen
  • -
  • What actually happened
  • -
  • What does work, under what conditions does it fail?
  • -
  • Reproduction steps - minimum steps required to reproduce the bug
  • -
-
    -
  1. additional materials that could help identify the cause:
  2. -
-
    -
  • screen shots
  • -
  • stack traces, logs, scripts, output
  • -
  • specific code and data / settings / configuration files required to reproduce the bug
  • -
  • environment (operating system, browser, hardware)
  • -
-
-
-

8.2.6.4 Requesting a feature

-

(from The Pragmatic Programmer, available as -ebook -through UI libraries, hardcopy on David’s bookshelf)
-

-
    -
  • focus on “user stories”, e.g. specific use cases
  • -
  • Be as specific as possible,

  • -
  • Here is an example:

  • -
-
    -
  1. Bob is at www.mysite.edu/maps
  2. -
  3. map of the the region (based on user location, e.g. US, Asia, etc)
  4. -
  5. option to “use current location” is provided, if clicked, map zooms in to, e.g. state or county level
  6. -
  7. for site run: -
      -
    1. option to select existing site or specify point by lat/lon
    2. -
    3. option to specify a bounding box and grid resolution in -either lat/lon or polar stereographic.
    4. -
  8. -
  9. asked to specify start and end times in terms of year, month, day, hour, minute. Time is recorded in UTC not local time, this should be indicated.
  10. -
-
-
-

8.2.6.5 Closing an issue

-
    -
  1. Definition of “Done”
  2. -
-
    -
  • test
  • -
  • documentation
  • -
-
    -
  1. when issue is resolved:
  2. -
-
    -
  • status is changed to “resolved”
  • -
  • assignee is changed to original author
  • -
-
    -
  1. if original author agrees that issue has been resolved
  2. -
-
    -
  • original author changes status to “closed”
  • -
-
    -
  1. except for trivial issues, issues are only closed by the author
  2. -
-
-
-

8.2.6.6 When to submit an issue?

-

Ideally, non-trivial code changes will be linked to an issue and a commit.

-

This requires creating issues for each task, making small commits, and referencing the issue within your commit message. Issues can be created on GitHub. These issues can be linked to commits by adding text such as fixes gh-5).

-

Rationale: This workflow is a small upfront investment that reduces error and time spent re-creating and debugging errors. Associating issues and commits, makes it easier to identify why a change was made, and potential bugs that could arise when the code is changed. In addition, knowing which issue you are working on clarifies the scope and objectives of your current task.

- -
-
-
-
-

8.3 Coding Practices

- -
-

8.3.1 Coding Style

-

Consistent coding style improves readability and reduces errors in -shared code.

-

Unless otherwise noted, PEcAn follows the Tidyverse style guide, so please familiarize yourself with it before contributing. -In addition, note the following:

-
    -
  • Document all functions using roxygen2. -See Roxygen2 for more details.
  • -
  • Put your name on things. -Any function that you create or make a meaningful contribution to should have your name listed after the author tag in the function documentation. -It is also often a good idea to add your name to extended comments describing particularly complex or strange code.
  • -
  • Write unit tests with testthat. -Tests are a complement to documentation - they define what a function is (and is not) expected to do. -Not all functions necessarily need unit tests, but the more tests we have, the more confident we can be that changes don’t break existing code. -Whenever you discover and fix a bug, it is a good idea to write a unit test that makes sure the same bug won’t happen again. -See Unit_Testing for instructions, and Advanced R: Tests.
  • -
  • Do not use abbreviations. -Always write out TRUE and FALSE (i.e. do not use T or F). -Do not rely on partial argument matching – write out all arguments in full.
  • -
  • Avoid dots in function names. -R’s S3 methods system uses dots to denote object methods (e.g. print.matrix is the print method for objects of class matrix), which can cause confusion. -Use underscores instead (e.g. do_analysis instead of do.analysis). -(NOTE that many old PEcAn functions violate this convention. The plan is to deprecate those in PEcAn 2.0. See GitHub issue #392).
  • -
  • Use informative file names with consistent extensions. -Standard file extensions are .R for R scripts, .rds for individual objects (via saveRDS function), and .RData (note: capital D!) for multiple objects (via the save function). -For function source code, prefer multiple files with fewer functions in each to large files with lots of files (though it may be a good idea to group closely related functions in a single file). -File names should match, or at least closely reflect, their files (e.g. function do_analysis should be defined in a file called do_analysis.R). -Do not use spaces in file names – use dashes (-) or underscores (_).
  • -
  • For using external packages, add the package to Imports: and call the corresponding function with package::function. -Do not use @importFrom package function or, worse yet, @import package. -(The exception is infix operators like magrittr::%>% or ggplot2::%+%, which can be imported via roxygen2 documentation like @importFrom magrittr %>%). -Do not add packages to Depends. -In general, try to avoid adding new dependencies (especially ones that depend on system libraries) unless they are necessary or already widely used in PEcAn (e.g. GDAL, NetCDF, XML, JAGS, dplyr). -For a more thorough and nuanced discussion, see the package dependencies appendix.
  • -
- -
-
-

8.3.2 Logging

-

During development we often add many print statements to check to see how the code is doing, what is happening, what intermediate results there are etc. When done with the development it would be nice to turn this additional code off, but have the ability to quickly turn it back on if we discover a problem. This is where logging comes into play. Logging allows us to use “rules” to say what information should be shown. For example when I am working on the code to create graphs, I do not have to see any debugging information about the SQL command being sent, however trying to figure out what goes wrong during a SQL statement it would be nice to show the SQL statements without adding any additional code.

-

PEcAn provides a set of logger.* functions that should be used in place of base R’s stop, warn, print, and similar functions. The logger functions make it easier to print to a system log file, and to control the level of output produced by PEcAn.

-
    -
  • The file test.logger.R provides descriptive examples
  • -
  • This query provides an current overview of functions that use logging
  • -
  • Logger functions and their corresponding levels (in order of increasing level):
  • -
  • logger.debug ("DEBUG") – Low-level diagnostic messages that are hidden by default. Good examples of this are expanded file paths and raw results from database queries or other analyses.
  • -
  • logger.info ("INFO") – Informational messages that regular users may want to see, but which do not indicate anything unexpected. Good examples of this are progress updates updates for long-running processes, or brief summaries of queries or analyses.
  • -
  • logger.warn ("WARN") – Warning messages about issues that may lead to unexpected but valid results. Good examples of this are interactions between arguments that lead to some arguments being ignored or removal of missing or extreme values.
  • -
  • logger.error ("ERROR") – Error messages from which PEcAn has some capacity to recover. Unless you have a very good reason, we recommend avoiding this in favor of either logger.severe to actually stop execution or logger.warn to more explicitly indicate that the problem is not fatal.
  • -
  • logger.severe – Catastrophic errors that warrant immediate termination of the workflow. This is the only function that actually stops R’s execution (via stop).
  • -
  • The logger.setLevel function sets the level at which a message will be printed. For instance, logger.setLevel("WARN") will suppress logger.info and logger.debug messages, but will print logger.warn and logger.error messages. logger.setLevel("OFF") suppresses all logger messages.
  • -
  • To print all messages to console, use logger.setUseConsole(TRUE)
  • -
- -
-
-

8.3.3 Package Data

-
-

8.3.3.1 Summary:

-

Files with the following extensions will be read by R as data:

-
    -
  • plain R code in .R and .r files are sourced using source()
  • -
  • text tables in .tab, .txt, .csv files are read using read() -** objects in R image files: .RData, .rda are loaded using load()
  • -
  • capitalization matters
  • -
  • all objects in foo.RData are loaded into environment
  • -
  • pro: easiset way to store objects in R format
  • -
  • con: format is application (R) specific
  • -
-

Details are in ?data, which is mostly a copy of Data section of -Writing R -Extensions.

-
-
-

8.3.3.2 Accessing data

-

Data in the [data] directory will be accessed in the following ways,

-
    -
  • efficient way: (especially for large data sets) using the data -function:
  • -
- -
    -
  • easy way: by adding the following line to the package DESCRIPTION: -note: this should be used with caution or it can cause difficulty as discussed in redmine issue #1118
  • -
- -

From the R help page:

-

Currently, a limited number of data formats can be accessed using the data function by placing one of the following filetypes in a packages’ data directory: -* files ending .R or .r are source()d in, with the R working -directory changed temporarily to the directory containing the respective -file. (data ensures that the utils package is attached, in case it -had been run via utils::data.) -* files ending .RData or .rda are load()ed. -* files ending .tab, .txt or .TXT are read using read.table(..., header = TRUE), and hence result in a data frame. -* files ending .csv or .CSV are read using read.table(..., header = TRUE, sep = ';'), and also result in a data frame.

-

If your data does not fall in those 4 categories, or you can use the -system.file function to get access to the data:

- -

The arguments are folder, filename(s) and then package. It will return -the fully qualified path name to a file in a package, in this case it -points to the trait data. This is almost the same as the data function, -however we can now use any function to read the file, such as read.csv -instead of read.csv2 which seems to be the default of data. This also -allows us to store arbitrary files in the data folder, such as the the -bug file and load it when we need it.

-
-
8.3.3.2.1 Examples of data in PEcAn packages
-
    -
  • outputs: [/modules/uncertainties/data/output.RData]
  • -
  • parameter samples [/modules/uncertainties/data/samples.RData]
  • -
- -
-
-
-
-

8.3.4 Documenting functions using roxygen2

-

This is the standard method for documenting R functions in PEcAn. -For detailed instructions, see one of the following resources:

- -

Below is a complete template for a Roxygen documentation block. -Note that roxygen lines start with #':

- -

Here is a complete example from the PEcAn.utils::days_in_year() function:

- -

To update documentation throughout PEcAn, run make document in the PEcAn root directory. -Make sure you do this before opening a pull request – -PEcAn’s automated testing (Travis) will check if any documentation is out of date and will throw an error like the following if it is:

-
These files were changed by the build process:
-{...}
- -
-
-
-

8.4 Testing

-

PEcAn uses two different kinds of testing – unit tests and integration tests.

-
-

8.4.1 Unit testing

-

Unit tests are short (<1 minute runtime) tests of functionality of specific functions. -Ideally, every function should have at least one unit test associated with it.

-

A unit test should be written for each of the following situations:

-
    -
  1. Each bug should get a regression test.
  2. -
-
    -
  • The first step in handling a bug is to write code that reproduces the error
  • -
  • This code becomes the test
  • -
  • most important when error could re-appear
  • -
  • essential when error silently produces invalid results
  • -
-
    -
  1. Every time a (non-trivial) function is created or edited
  2. -
-
    -
  • Write tests that indicate how the function should perform -
      -
    • example: expect_equal(sum(1,1), 2) indicates that the sum -function should take the sum of its arguments
    • -
  • -
  • Write tests for cases under which the function should throw an -error
  • -
  • example: expect_error(sum("foo"))
  • -
  • better : expect_error(sum("foo"), "invalid 'type' (character)")
  • -
-
    -
  1. Any functionality that you would like to protect over the long term. Functionality that is not tested is more likely to be lost. -PEcAn uses the testthat package for unit testing. -A general overview of is provided in the “Testing” chapter of Hadley Wickham’s book “R packages”. -Another useful resource is the testthat package documentation website. -See also our testthat appendix. -Below is a lightning introduction to unit testing with testthat.
  2. -
-

Each package’s unit tests live in .R scripts in the folder <package>/tests/testthat. -In addition, a testthat-enabled package has a file called <packagename>/tests/testthat.R with the following contents:

- -

Tests should be placed in <packagename>/tests/testthat/test-<sourcefilename>.R, and look like the following:

- -
-
-

8.4.2 Integration testing

-

Integration tests consist of running the PEcAn workflow in full. -One way to do integration tests is to manually run workflows for a given version of PEcAn, either through the web interface or by manually creating a pecan.xml file. -Such manual tests are an important part of checking PEcAn functionality.

-

Alternatively, the base/workflow/inst/batch_run.R script can be used to quickly run a series of user-specified integration tests without having to create a bunch of XML files. -This script is powered by the PEcAn.workflow::create_execute_test_xml() function, -which takes as input information about the model, meteorology driver, site ID, run dates, and others, -uses these to construct a PEcAn XML file, -and then uses the system() command to run a workflow with that XML.

-

If run without arguments, batch_run.R will try to run the model configurations specified in the base/workflow/inst/default_tests.csv file. -This file contains a CSV table with the following columns:

-
    -
  • model – The name of the model (models.model_name column in BETY)
  • -
  • revision – The version of the model (models.revision column in BETY)
  • -
  • met – The name of the meteorology driver source
  • -
  • site_id – The numeric site ID for the model run (sites.site_id)
  • -
  • pft – The name of the plant functional type to run. If NA, the script will use the first PFT associated with the model.
  • -
  • start_date, end_date – The start and end dates for the model run, respectively. These should be formatted according to ISO standard (YYYY-MM-DD, e.g. 2010-03-16)
  • -
  • sensitivity – Whether or not to run the sensitivity analysis. TRUE means run it, FALSE means do not.
  • -
  • ensemble_size – The number of ensemble members to run. Set this to 1 to do a single run at the trait median.
  • -
  • comment – An string providing some user-friendly information about the run.
  • -
-

The batch_run.R script will run a workflow for every row in the input table, sequentially (for now; eventually, it will try to run them in parallel), -and at the end of each workflow, will perform some basic checks, including whether or not the workflow finished and if the model produced any output. -These results are summarized in a CSV table (by default, a file called test_result_table.csv), with all of the columns as the input test CSV plus the following:

-
    -
  • outdir – Absolute path to the workflow directory.
  • -
  • workflow_complete – Whether or not the PEcAn workflow completed. Note that this is a relatively low bar – PEcAn workflows can complete without having run the model or finished some other steps.
  • -
  • has_jobsh – Whether or not PEcAn was able to write the model’s job.sh script. This is a good indication of whether or not the model’s write.configs step was successful, and may be useful for separating model configuration errors from model execution errors.
  • -
  • model_output_raw – Whether or not the model produced any output files at all. This is just a check to see of the <workflow>/out directory is empty or not. Note that some models may produce logfiles or similar artifacts as soon as they are executed, whether or not they ran even a single timestep, so this is not an indication of model success.
  • -
  • model_output_processed – Whether or not PEcAn was able to post-process any model output. This test just sees if there are any files of the form YYYY.nc (e.g. 1992.nc) in the <workflow>/out directory.
  • -
-

Right now, these checks are not particularly robust or comprehensive, but they should be sufficient for catching common errors. -Development of more, better tests is ongoing.

-

The batch_run.R script can take the following command-line arguments:

-
    -
  • --help – Prints a help message about the script’s arguments
  • -
  • --dbfiles=<path> – The path to the PEcAn dbfiles folder. The default value is ~/output/dbfiles, based on the file structure of the PEcAn VM. Note that for this and all other paths, if a relative path is given, it is assumed to be relative to the current working directory, i.e. the directory from which the script was called.
  • -
  • --table=<path> – Path to an alternate test table. The default is the base/workflow/inst/default_tests.csv file. See preceding paragraph for a description of the format.
  • -
  • --userid=<id> – The numeric user ID for registering the workflow. The default value is 99000000002, corresponding to the guest user on the PEcAn VM.
  • -
  • --outdir=<path> – Path to a directory (which will be created if it doesn’t exist) for storing the PEcAn workflow outputs. Default is batch_test_output (in the current working directory).
  • -
  • --pecandir=<path> – Path to the PEcAn source code root directory. Default is the current working directory.
  • -
  • --outfile=<path> – Full path (including file name) of the CSV file summarizing the results of the runs. Default is test_result_table.csv. The format of the output
  • -
-
-
-

8.4.3 Continuous Integration

-

Every time anyone commits a change to the PEcAn code, the act of pushing to GitHub triggers an automated build and test of the full PEcAn codebase, and all pull requests must report a successful CI build before they will be merged. This will sometimes feel like a burden when the build breaks on an issue that looks trivial, but anything that breaks the build is important enough to fix. It’s much better to find errors early and fix them before they get incorporated into the released PEcAn code.

-

At this writing PEcAn’s CI builds primarily use Travis CI and the rest of this section assumes a Travis build, but as of May 2020 we also have an experimental GitHub Actions build, and if we switch completely to GitHub Actions then this guide will need to be rewritten.

-

All our Travis builds run on the same version of Linux (currently Ubuntu 16.04, xenial) using four different versions of R in parallel: the two most recent previous releases, current release, and nightly builds of the R development branch. In most cases the build should pass on all four versions, but only the current release (R:release) is truly mandatory. We aim to fix errors found on R:release before merging, errors found on R:devel before the next R release, and errors found on older releases as developer time and forward compatibility allow.

-

Each build starts by launching a separate clean virtual machine for each R version and performs roughly the following actions on all of them:

-
    -
  • Installs binary system dependencies needed by PEcAn (NetCDF and HDF5 libraries, JAGS, udunits, etc).
  • -
  • Installs all the R packages that are declared as dependencies in any PEcAn package, as computed by scripts/generate_dependencies.R.
  • -
  • Clones the PEcAn repository from GitHub, and checks out the branch to be tested.
  • -
  • Retrieves any cached files available from previous Travis builds. -
      -
    • The main thing in the cache is previously-installed dependency R packages, to avoid recompiling them every time.
    • -
    • If the cache becomes stale or is preventing a package update needed by the build (e.g. to get a new version that contains a needed bug fix), delete the cache through the Travis web interface and it will be reconstructed on the next build.
    • -
    • Because PEcAn has so many dependencies, builds with no cache will spend most of their time recompiling packages and will probably run out of time before the tests complete. You can fix this by using scripts/travis/cache_buildup.sh and scripts/travis/prime_travis_cache.sh to build up the cache incrementally through one or more custom builds, each of which installs some dependencies and then uploads a freshened cache without running any tests. Once all dependencies have been cached, restart the standard full build.
    • -
  • -
  • Initializes a skeleton version of the PEcAn database (BeTY) containing a few public records to be used by the test runs.
  • -
  • Installs all the PEcAn packages, recompiling documentation and installing dependencies as needed.
  • -
  • Runs package unit tests (the same ones you run locally with make test or devtools::test(pkgname)). -
      -
    • As discussed in Unit testing, these tests should run quickly and test individual components in relative isolation.
    • -
    • Any test that calls the skip_on_ci function will be skipped. This is useful for tests that need to run for a very long time (e.g. large data product downloads) or require resources that aren’t available on Travis (e.g. specific models), but be sure to run these tests locally before pushing your code!
    • -
  • -
  • Runs R package checks (the same ones you run locally with make check or devtools::check(pkgname)), skipping tests and documentation rebuild because we just did those in the previous steps. -
      -
    • Any ERROR in the check output will stop the build immediately.
    • -
    • If there are no ERRORs, any WARNINGs or NOTEs are compared against a stored historic check result in <package>/tests/Rcheck_reference.log. If the package has no stored reference result, all WARNINGs and NOTEs are considered newly added and reported as build failures.
    • -
    • If all messages from the current built were also present in the reference result, the check passes. If any messages are newly added, a build failure is reported.
    • -
    • Each line of the check log is considered a separate message, and the test requires exact matching, so a change from Undocumented arguments in documentation object 'foo': 'x' to Undocumented arguments in documentation object 'foo': 'x', 'y' will be counted as a new warning… and you should fix both of them while you’re at it!
    • -
    • The idea here is to enforce good coding practice and catch likely errors in all new code while recognizing that we have a lot of legacy code whose warnings need to be fixed as we have time rather than all at once.
    • -
    • As we fix historic warnings, we will revoke their grandfathered status by removing them from the stored check results, so that they will break the build if they reappear.
    • -
    • If your PR reports a failure in pre-existing code that you think ought to be grandfathered, please fix it as part of your PR anyway. It’s frustrating to see tests complain about code you didn’t touch, but the failures all need to be cleaned up eventually and it’s likely easier to fix the error than to figure out how to re-ignore it.
    • -
  • -
  • Runs a simple PEcAn workflow from beginning to end (three years of SIPNET at Niwot Ridge using stored weather data, meta-analysis on fixed effects only, sensitivity analysis on NPP), and verifies that the models complete successfully.
  • -
  • Checks whether any version-controlled files have been changed by the build and testing process, and marks a build failure if they have. -
      -
    • If your build fails at this step, the most common cause is that you forgot to Roxygenize before committing.
    • -
    • This step will also detect newly added files, e.g. tests improperly writing to the current working directory rather than tempdir() and then failing to clean up after themselves.
    • -
  • -
-

If any of these steps reports an error, the build is marked as “broken” and stops before the next step. If they all pass, the Travis CI bot marks the build as successful and tells the GitHub bot that it’s OK to allow your changes to be merged… but the final decision belongs to the human reviewing your code and they might still ask you for other changes!

-

After a successful build, Travis performs two post-build steps:

-
    -
  • Compiles the PEcAn documentation book (book_source) and the tutorials (documentation/tutorials) and uploads them to the PEcAn website. -
      -
    • This is only done for commits to the master or develop branch, so changes to in-progress pull requests never change the live documentation until after they are merged.
    • -
  • -
  • Packs up selected build artifacts into a cache file and uploads it to the Travis servers for use on the next build.
  • -
-

The post-build steps are allowed to fail without breaking the build. If you made documentation changes but don’t see them deployed, or if your build seems to be reinstalling packages that ought to be cached, inspect the Travis logs of the previous supposedly-successful build to see if their uploads succeeded.

-

All of the above descriptions apply to the build Travis generates when you push to the main PecanProject/pecan repository, either by directly pushing to a branch or by opening a pull request. If you like, you can also enable Travis builds from your own PEcAn fork. This can be useful for several reasons:

-
    -
  • It lets your test whether your changes worked before you open a pull request.
  • -
  • It often lets you get faster test results: The PEcAn project uses Travis CI’s free tier, which only allows a few simultaneous build jobs per repository. If many people are pushing code at the same time, your build might wait in line for a long time at PecanProject/pecan but start immediately at yourname/pecan.
  • -
  • If you will be editing the documentation a lot and want to see rendered previews of your in-progress work (instead of waiting until it is merged into develop), you can clone the pecan-documentation repository to your own GitHub account and let Travis update it for you.
  • -
- -
-
-
-

8.5 Download and Compile PEcAn

-

Set R_LIBS_USER

-

CRAN Reference

- -
-

8.5.1 Download, compile and install PEcAn from GitHub

- -

For more information on the capabilities of the PEcAn Makefile, check out our section on Updating PEcAn.

-

Following will run a small script to setup some hooks to prevent people from using the pecan demo user account to check in any code.

- -
-
-

8.5.2 PEcAn Testrun

-

Do the run, this assumes you have installed the BETY database, sites tar file and SIPNET.

- -

NB: pecan.xml is configured for the virtual machine, you will need to change the field from ‘/home/carya/’ to wherever you installed your ‘sites’, usually $HOME

- -
-
-
-

8.6 Directory structure

-
-

8.6.1 Overview of PEcAn repository as of PEcAn 1.5.3

- -
pecan/
- +- base/          # Core functions
-    +- all         # Dummy package to load all PEcAn R packages
-    +- db          # Modules for querying the database
-    +- logger      # Report warnings without killing workflows
-    +- qaqc        # Model skill testing and integration testing
-    +- remote      # Communicate with and execute models on local and remote hosts
-    +- settings    # Functions to read and manipulate PEcAn settings files
-    +- utils       # Misc. utility functions
-    +- visualization # Advanced PEcAn visualization module
-    +- workflow    # functions to coordinate analysis steps
- +- book_source/   # Main documentation and developer's guide
- +- CHANGELOG.md   # Running log of changes in each version of PEcAn
- +- docker/        # Experimental replacement for PEcAn virtual machine
- +- documentation  # index_vm.html, references, other misc.
- +- models/        # Wrappers to run models within PEcAn
-    +- ed/         # Wrapper scripts for running ED within PEcAn
-    +- sipnet/     # Wrapper scripts for running SIPNET within PEcAn
-    +- ...         # Wrapper scripts for running [...] within PEcAn
-    +- template/   # Sample wrappers to copy and modify when adding a new model
- +- modules        # Core modules
-    +- allometry
-    +- data.atmosphere
-    +- data.hydrology
-    +- data.land
-    +- meta.analysis
-    +- priors
-    +- rtm
-    +- uncertainty
-    +- ...
- +- scripts        # R and Shell scripts for use with PEcAn
- +- shiny/         # Interactive visualization of model results
- +- tests/         # Settings files for host-specific integration tests
- +- web            # Main PEcAn website files
-
-
-

8.6.2 Generic R package structure:

-

see the R development wiki for more information on writing code and adding data.

-
 +- DESCRIPTION    # short description of the PEcAn library
- +- R/             # location of R source code
- +- man/           # Documentation (automatically compiled by Roxygen)
- +- inst/          # files to be installed with package that aren't R functions
-    +- extdata/    # misc. data files (in misc. formats)
- +- data/          # data used in testing and examples (saved as *.RData or *.rda files)
- +- NAMESPACE      # declaration of package imports and exports (automatically compiled by Roxygen)
- +- tests/         # PEcAn testing scripts
-   +- testthat/    # nearly all tests should use the testthat framework and live here
- -
-
-
- - - -
- - -
-
- - - - - - - - - - - - - - - - - - - - - diff --git a/develop_test/docker-index.html b/develop_test/docker-index.html deleted file mode 100644 index 88c843002..000000000 --- a/develop_test/docker-index.html +++ /dev/null @@ -1,2274 +0,0 @@ - - - - - - - 24 Docker | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

24 Docker

-

This chapter describes the PEcAn Docker container infrastructure. -It contains the following sections:

- - -
-

24.1 Introduction to Docker?

- -
-

24.1.1 What is Docker?

-

For a quick and accessible introduction to Docker, we suggest this YouTube video: Learn Docker in 12 Minutes.

-

For more comprehensive Docker documentation, we refer you to the Docker documentation website.

-

For a useful analogy for Docker containerization, we refer you to the webcomic xkcd.

-

Docker is a technology for encapsulating software in “containers”, somewhat similarly to virtual machines. -Like virtual machines, Docker containers facilitate software distribution by bundling the software with all of its dependencies in a single location. -Unlike virtual machines, Docker containers are meant to only run a single service or process and are build on top of existing services provided by the host OS (such as disk access, networking, memory management etc.).

-

In Docker, an image refers to a binary snapshot of a piece of software and all of its dependencies. -A container refers to a running instance of a particular image. -A good rule of thumb is that each container should be responsible for no more than one running process. -A software stack refers to a collection of containers, each responsible for its own process, working together to power a particular application. -Docker makes it easy to run multiple software stacks at the same time in parallel on the same machine. -Stacks can be given a unique name, which is passed along as a prefix to all their containers. -Inside these stacks, containers can communicate using generic names not prefixed with the stack name, making it easy to deploy multiple stacks with the same internal configuration. -Containers within the same stack communicate with each other via a common network. -Like virtual machines or system processes, Docker stacks can also be instructed to open specific ports to facilitate communication with the host and other machines.

-

The PEcAn database BETY provides an instructive case-study. -BETY is comprised of two core processes – a PostgreSQL database, and a web-based front-end to that database (Apache web server with Ruby on Rails). -Running BETY as a “Dockerized” application therefore involves two containers – one for the PostgreSQL database, and one for the web server. -We could build these containers ourselves by starting from a container with nothing but the essentials of a particular operating system, but we can save some time and effort by starting with an existing image for PostgreSQL from Docker Hub. -When starting a Dockerized BETY, we start the PostgreSQL container first, then start the BETY container telling it how to communicate with the PostgreSQL container. -To upgrade an existing BETY instance, we stop the BETY container, download the latest version, tell it to upgrade the database, and re-start the BETY container. -There is no need to install new dependencies for BETY since they are all shipped as part of the container.

-

The PEcAn Docker architecture is designed to facilitate installation and maintenance on a variety of systems by eliminating the need to install and maintain complex system dependencies (such as PostgreSQL, Apache web server, and Shiny server). -Furthermore, using separate Docker containers for each ecosystem model helps avoid clashes between different software version requirements of different models (e.g. some models require GCC <5.0, while others may require GCC >=5.0).

-

The full PEcAn Docker stack is described in more detail in the next section.

-
-
-

24.1.2 Working with Docker

-

To run an image, you can use the Docker command line interface. -For example, the following runs a PostgreSQL image based on the pre-existing PostGIS image by mdillon:

- -

This will start the PostgreSQL+PostGIS container. -The following options were used:

-
    -
  • --detach makes the container run in the background.
  • -
  • --rm removes the container when it is finished (make sure to use the volume below).
  • -
  • --name the name of the container, also the hostname of the container which can be used by other docker containers in the same network inside docker.
  • -
  • --network pecan the network that the container should be running in, this leverages of network isolation in docker and allows this container to be connected to by others using the postgresql hostname.
  • -
  • --publish exposes the port to the outside world, this is like ssh, and maps port 9876 to port 5432 in the docker container
  • -
  • --volume maps a folder on your local machine to the machine in the container. This allows you to save data on your local machine.
  • -
  • mdillon/postgis:9.6-alpine is the actual image that will be run, in this case it comes from the group/person mdillon, the container is postgis and the version 9.6-alpine (version 9.6 build on alpine linux).
  • -
-

Other options that might be used:

-
    -
  • --tty allocate a pseudo-TTY to send stdout and stderr back to the console.
  • -
  • --interactive keeps stdin open so the user can interact with the application running.
  • -
  • --env sets environment variables, these are often used to change the behavior of the docker container.
  • -
-

To see a list of all running containers you can use the following command:

- -

To see the log files of this container you use the following command (you can either use their name or id as returned by docker ps). The -f flag will follow the stdout/stderr from the container, use Ctrl-C to stop following the stdout/stderr.

- -

To stop a running container use:

-
docker stop postgresql
-

Containers that are running in the foreground (without the --detach) can be stopped by pressing Ctrl-C. Any containers running in the background (with --detach) will continue running until the machine is restarted or the container is stopped using docker stop.

-
-
-

24.1.3 docker-compose

-

For a quick introduction to docker-compose, we recommend the following YouTube video: Docker Compose in 12 Minutes.

-

The complete docker-compose references can be found on the Docker documentation website.

-

docker-compose provides a convenient way to configure and run a multi-container Docker stack. -Basically, a docker-compose setup consists of a list of containers and their configuration parameters, which are then internally converted into a bunch of docker commands. -To configure BETY as described above, we can use a docker-compose.yml file like the following:

- -

This simple file allows us to bring up a full BETY application with both database and BETY application. The BETY app will not be brought up until the database container has started.

-

You can now start this application by changing into the same directory as the docker-compose.yml file (cd /path/to/file) and then running:

-
docker-compose up
-

This will start the application, and you will see the log files for the 2 different containers.

- -
-
- -
-

24.3 The PEcAn docker install process in detail

-
-

24.3.1 Configure docker-compose

-

This section will let you download some configuration files. The documentation provides links to the latest released version (master branch in GitHub) or the develop version that we are working on (develop branch in GitHub) which will become the next release. If you cloned the PEcAn GitHub repository you can use git checkout <branch> to switch branches.

-

The PEcAn Docker stack is configured using a docker-compose.yml file. You can download just this file directly from GitHub latest or develop. You can also find this file in the root of cloned PEcAn GitHub repository. There is no need to edit the docker-compose.yml file. You can use either the .env file to change some of the settings, or the docker-compose.override.yml file to modify the docker-compose.yml file. This makes it easier for you to get an updated version of the docker-compose.yml file and not lose any chances you have made to it.

-

Some of the settings in the docker-compose.yml can be set using a .env file. You can download either the latest or the develop version. If you have cloned the GitHub repository it is also located in the docker folder. This file should be called .env and be placed in the same folder as your docker-compose.yml file. This file will allow you to set which version of PEcAn or BETY to use. See the comments in this file to control the settings. Option you might want to set are:

-
    -
  • PECAN_VERSION : The docker images to use for PEcAn. The default is latest which is the latest released version of PEcAn. Setting this to develop will result in using the version of PEcAn which will become the next release.
  • -
  • PECAN_FQDN : Is the name of the server where PEcAn is running. This is what is used to register all files generated by this version of PEcAn (see also TRAEFIK_HOST).
  • -
  • PECAN_NAME : A short name of this PEcAn server that is shown in the pull down menu and might be easier to recognize.
  • -
  • BETY_VERSION : This controls the version of BETY. The default is latest which is the latest released version of BETY. Setting this to develop will result in using the version of BETY which will become the next release.
  • -
  • TRAEFIK_HOST : Should be the FQDN of the server, this is needed when generating a SSL certificate. For SSL certificates you will need to set TRAEFIK_ACME_ENABLE as well as TRAEFIK_ACME_EMAIL.
  • -
  • TRAEFIK_IPFILTER : is used to limit access to certain resources, such as RabbitMQ and the Traefik dashboard.
  • -
-

A final file, which is optional, is a docker-compose.override.yml. You can download a version for the latest and develop versions. If you have cloned the GitHub repository it is located in the docker folder. Use this file as an example of what you can do, only copy the pieces over that you really need. This will allow you to make changes to the docker-compose file for your local installation. You can use this to add additional containers to your stack, change the path where docker stores the data for the containers, or you can use this to open up the postgresql port.

- -

Once you have the docker-compose.yml file as well as the optional .env and docker-compose.override.yml in a folder you can start the PEcAn stack. The following instructions assume you are in the same directory as the file (if not, cd into it).

-

In the rest of this section we will use a few arguments for the docker-compose application. The location of these arguments are important. The general syntax of docker-compose is docker-compose <ARGUMENTS FOR DOCKER COMPOSE> <COMMAND> <ARGUMENTS FOR COMMAND> [SERVICES]. More generally, docker-compose options are very sensitive to their location relative to other commands in the same line – that is, docker-compose -f /my/docker-compose.yml -p pecan up -d postgres is not the same as docker-compose -d postgres -p pecan up -f /my/docker-compose.yml. If expected ever don’t seem to be working, check that the arguments are in the right order.)

-
    -
  • -f <filename> : ARGUMENTS FOR DOCKER COMPOSE : Allows you to specify a docker-compose.yml file explicitly. You can use this argument multiple times. Default is to use the docker-compose.yml and docker-compose.override.yml in your current folder.
  • -
  • -p <projectname> : ARGUMENTS FOR DOCKER COMPOSE : Project name, all volumes, networks, and containers will be prefixed with this argument. The default value is to use the current folder name.
  • -
  • -d : ARGUMENTS FOR up COMMAND : Will start all the containers in the background and return back to the command shell.
  • -
-

If no services as added to the docker-compose command all services possible will be started.

-
-
-

24.3.2 Initialize PEcAn (first time only)

-

Before you can start to use PEcAn for the first time you will need to initialize the database (and optionally add some data). The following two sections will first initialize the database and secondly add some data to the system.

-
-

24.3.2.1 Initialize the PEcAn database

-

The commands described in this section will set up the PEcAn database (BETY) and pre-load it with some common “default” data.

- -

The breakdown of this command is as follows:

-
    -
  • -p pecan – This tells docker-compose to do all of this as part of a “project” -p we’ll call pecan. By default, the project name is set to the name of the current working directory. The project name will be used as a prefix to all containers started by this docker-compose instance (so, if we have a service called postgres, this will create a container called pecan_postgres).
  • -
  • up -dup is a command that initializes the containers. Initialization involves downloading and building the target containers and any containers they depend on, and then running them. Normally, this happens in the foreground, printing logs directly to stderr/stdout (meaning you would have to interrupt it with Ctrl-C), but the -d flag forces this to happen more quietly and in the background.
  • -
  • postgres – This indicates that we only want to initialize the service called postgres (and its dependencies). If we omitted this, docker-compose would initialize all containers in the stack.
  • -
-

The end result of this command is to initialize a “blank” PostGIS container that will run in the background. -This container is not connected to any data (yet), and is basically analogous to just installing and starting PostgreSQL to your system. -As a side effect, the above command will also create blank data “volumes” and a “network” that containers will use to communicate with each other. -Because our project is called pecan and docker-compose.yml describes a network called pecan, the resulting network is called pecan_pecan. -This is relevant to the following commands, which will actually initialize and populate the BETY database.

-

Assuming the above has run successfully, next run the following:

- -

The breakdown of this command is as follows: {#docker-run-init}

-
    -
  • docker run – This says we will be running a container.
  • -
  • --rm – This automatically removes the resulting container once the specified command exits, as well as any volumes associated with the container. This is useful as a general “clean-up” flag for one-off commands (like this one) to make sure you don’t leave any “zombie” containers or volumes around at the end.
  • -
  • --network pecan_pecan – Thsi will start the container in the same network space as the posgres container, allowing it to push data into the database.
  • -
  • pecan/db – This is the name of the container, this holds a copy of the database used to initialize the postgresql database.
  • -
-

Note that this command may throw a bunch of errors related to functions and/or operators already existing. -This is normal – it just means that the PostGIS extension to PostgreSQL is already installed. -The important thing is that you see output near the end like:

-
----------------------------------------------------------------------
-Safety checks
-
-----------------------------------------------------------------------
-
-----------------------------------------------------------------------
-Making sure user 'bety' exists.
-

If you do not see this output, you can look at the troubleshooting section at the end of this section for some troubleshooting tips, as well as some solutions to common problems.

-

Once the command has finished successfully, proceed with the next step which will load some initial data into the database and place the data in the docker volumes.

-
-
-

24.3.2.2 Add first user to PEcAn database

-

You can add an initial user to the BETY database, for example the following commands will add the guestuser account as well as the demo carya account:

-
# guest user
-docker-compose run --rm bety user guestuser guestuser "Guest User" guestuser@example.com 4 4
-
-# example user
-docker-compose run --rm bety user carya illinois "Carya Demo User" carya@example.com 1 1
-
-
-

24.3.2.3 Add example data (first time only)

-

The following command will add some initial data to the PEcAn stack and register the data with the database.

- -

The breakdown of this command is as follows:

-
    -
  • docker run – This says we will be running a specific command inside the target Docker container. See docker run --help and the Docker run reference for more information.
  • -
  • -ti – This is actually two flags, -t to allocate a pseudo-tty and -i to keep STDIN open even if detached. -t is necessary to ensure lower-level script commands run correctly. -i makes sure that the command output (stdin) is displayed.
  • -
  • --rm – This automatically removes the resulting container once the specified command exits, as well as any volumes associated with the container. This is useful as a general “clean-up” flag for one-off commands (like this one) to make sure you don’t leave any “zombie” containers or volumes around at the end.
  • -
  • --network pecan_pecan – This indicates that the container will use the existing pecan_pecan network. This network is what ensures communication between the postgres container (which, recall, is just a PostGIS installation with some data) and the “volumes” where the actual data are persistently stored.
  • -
  • pecan/data:develop – This is the name of the image in which to run the specified command, in the form repository/image:version. This is interpreted as follows: -
      -
    • First, it sees if there are any images called pecan/data:develop available on your local machine. If there are, it uses that one.
    • -
    • If that image version is not available locally, it will next try to find the image online. By default, it searches Docker Hub, such that pecan/data gets expanded to the container at https://hub.docker.com/r/pecan/data. For custom repositories, a full name can be given, such as hub.ncsa.illinois.edu/pecan/data:latest.
    • -
    • If :version is omitted, Docker assumes :latest. NOTE that while online containers should have a :latest version, not all of them do, and if a :latest version does not exist, Docker will be unable to find the image and will throw an error.
    • -
  • -
  • Everything after the image name (here, pecan/data:develop) is interpreted as an argument to the image’s specified entrypoint.
  • -
  • --volume pecan_pecan:/data – This mounts the data from the subsequent container (pecan/data:develop) onto the current project volume, called pecan_pecan (as with the network, the project name pecan is the prefix, and the volume name also happens to be pecan as specified in the docker-compose.yml file).
  • -
  • --env FQDN=docker – the Fully Qualified Domain Name, this is the same value as specified in the .env file (for the web, monitor and executor containers). This will link the data files to the name in the machines table in BETY.
  • -
  • pecan/data:develop – As above, this is the target image to run. Since there is no argument after the image name, this command will run the default command (CMD) specified for this docker container. In this case, it is the docker/add_data.sh script from the PEcAn repository.
  • -
-

Under the hood, this container runs the docker/add-data.sh script, which copies a bunch of input files and registers them with the PEcAn database.

-

Successful execution of this command should take some time because it involves copying reasonably large amounts of data and performing a number of database operations.

-
-
-

24.3.2.4 Start PEcAn

-

If you already completed the above steps, you can start the full stack by just running the following:

- -

This will build and start all containers required to run PEcAn. -With the -d flag, this will run all of these containers quietly in the background, and show a nice architecture diagram with the name and status of each container while they are starting. -Once this is done you have a working instance of PEcAn.

-

If all of the containers started successfully, you should be able to access the various components from a browser via the following URLs (if you run these commands on a remote machine replace localhost with the actual hostname).

- -
-
-

24.3.2.5 Start model runs using curl

-

To test PEcAn you can use the following curl statement, or use the webpage to submit a request (if you run these commands on a remote machine replace localhost with the actual hostname):

- -

This should return some text with in there Location: this is shows the workflow id, you can prepend http://localhost:8000/pecan/ to the front of this, for example: http://localhost:8000/pecan/05-running.php?workflowid=99000000001. Here you will be able to see the progress of the workflow.

-

To see what is happening behind the scenes you can use look at the log file of the specific docker containers, once of interest are pecan_executor_1 this is the container that will execute a single workflow and pecan_sipnet_1 which executes the sipnet mode. To see the logs you use docker logs pecan_executor_1 Following is an example output:

-
2018-06-13 15:50:37,903 [MainThread     ] INFO    : pika.adapters.base_connection - Connecting to 172.18.0.2:5672
-2018-06-13 15:50:37,924 [MainThread     ] INFO    : pika.adapters.blocking_connection - Created channel=1
-2018-06-13 15:50:37,941 [MainThread     ] INFO    : root -  [*] Waiting for messages. To exit press CTRL+C
-2018-06-13 19:44:49,523 [MainThread     ] INFO    : root - b'{"folder": "/data/workflows/PEcAn_99000000001", "workflowid": "99000000001"}'
-2018-06-13 19:44:49,524 [MainThread     ] INFO    : root - Starting job in /data/workflows/PEcAn_99000000001.
-2018-06-13 19:45:15,555 [MainThread     ] INFO    : root - Finished running job.
-

This shows that the executor connects to RabbitMQ, waits for messages. Once it picks up a message it will print the message, and execute the workflow in the folder passed in with the message. Once the workflow (including any model executions) is finished it will print Finished. The log file for pecan_sipnet_1 is very similar, in this case it runs the job.sh in the run folder.

-

To run multiple executors in parallel you can duplicate the executor section in the docker-compose file and just rename it from executor to executor1 and executor2 for example. The same can be done for the models. To make this easier it helps to deploy the containers using Kubernetes allowing to easily scale up and down the containers.

-
-
-
-

24.3.3 Troubleshooting

-

When initializing the database, you will know you have encountered more serious errors if the command exits or hangs with output resembling the following:

-
LINE 1: SELECT count(*) FROM formats WHERE ...
-                             ^
-Error: Relation `formats` does not exist
-

If the above command fails, you can try to fix things interactively by first opening a shell inside the container…

-
docker run -ti --rm --network pecan_pecan pecan/bety:latest /bin/bash
-

…and then running the following commands, which emulate the functionality of the entrypoint.sh with the initialize argument.

- - -
-
-
-

24.4 PEcAn Docker Architecture

- -
-

24.4.1 Overview

-

The PEcAn docker architecture consists of many containers (see figure below) that will communicate with each other. The goal of this architecture is to easily expand the PEcAn system by deploying new model containers and registering them with PEcAn. Once this is done the user can now use these new models in their work. The PEcAn framework will setup the configurations for the models, and send a message to the model containers to start execution. Once the execution is finished the PEcAn framework will continue. This is exactly as if the model is running on a HPC machine. Models can be executed in parallel by launching multiple model containers.

-

-As can be seen in the figure the architecture leverages of two standard containers (in orange). The first container is postgresql with postgis (mdillon/postgis) which is used to store the database used by both BETY and PEcAn. The second containers is a messagebus, more specifically RabbitMQ (rabbitmq).

-

The BETY app container (pecan/bety) is the front end to the BETY database and is connected to the postgresql container. A http server can be put in front of this container for SSL termination as well to allow for load balancing (by using multiple BETY app containers).

-

The PEcAn framework containers consist of multiple unique ways to interact with the PEcAn system (none of these containers will have any models installed):

-
    -
  • PEcAn shiny hosts the shiny applications developed and will interact with the database to get all information necessary to display
  • -
  • PEcAn rstudio is a rstudio environment with the PEcAn libraries preloaded. This allows for prototyping of new algorithms that can be used as part of the PEcAn framework later.
  • -
  • PEcAn web allows the user to create a new PEcAn workflow. The workflow is stored in the database, and the models are executed by the model containers.
  • -
  • PEcAn cli will allow the user to give a pecan.xml file that will be executed by the PEcAn framework. The workflow created from the XML file is stored in the database, and the models are executed by the model containers.
  • -
-

The model containers contain the actual models that are executed as well as small wrappers to make them work in the PEcAn framework. The containers will run the model based on the parameters received from the message bus and convert the outputs back to the standard PEcAn output format. Once the container is finished processing a message it will immediatly get the next message and start processing it.

-
-
-

24.4.2 PEcAn’s docker-compose

-

The PEcAn Docker architecture is described in full by the PEcAn docker-compose.yml file. -For full docker-compose syntax, see the official documentation.

-

This section describes the top-level structure and each of the services, which are as follows:

- -

For reference, the complete docker-compose file is as follows:

-
version: '3.2'
-services:
-  traefik:
-    image: traefik:1.7
-    command:
-    - --loglevel=INFO
-    - --api
-    - --defaultentrypoints=https,http
-    - --entryPoints=Name:http Address::${TRAEFIK_HTTP_PORT:-8000} ${TRAEFIK_HTTP_REDIRECT:-""}
-    - --entryPoints=Name:https Address::${TRAEFIK_HTTPS_PORT:-8443} ${TRAEFIK_HTTPS_OPTIONS:-TLS}
-    - --acme=${TRAEFIK_ACME_ENABLE:-false}
-    - --acme.email=${TRAEFIK_ACME_EMAIL:-""}
-    - --acme.entrypoint=https
-    - --acme.onhostrule=true
-    - --acme.storage=/config/acme.json
-    - --acme.httpchallenge.entrypoint=http
-    - --acme.storage=/config/acme.json
-    - --acme.acmelogging=true
-    - --docker=true
-    - --docker.endpoint=unix:///var/run/docker.sock
-    - --docker.exposedbydefault=false
-    - --docker.watch=true
-    restart: unless-stopped
-    networks: pecan
-    ports:
-    - ${TRAEFIK_HTTP_PORT-8000}:${TRAEFIK_HTTP_PORT:-8000}
-    - ${TRAEFIK_HTTPS_PORT-8443}:${TRAEFIK_HTTPS_PORT:-8443}
-    labels:
-    - traefik.enable=true
-    - traefik.backend=traefik
-    - traefik.port=8080
-    - 'traefik.frontend.rule=${TRAEFIK_FRONTEND_RULE:-}PathPrefixStrip: /traefik'
-    - traefik.website.frontend.whiteList.sourceRange=${TRAEFIK_IPFILTER:-172.16.0.0/12}
-    volumes:
-    - /var/run/docker.sock:/var/run/docker.sock:ro
-    - traefik:/config
-  minio:
-    image: minio/minio:latest
-    command: server /data
-    restart: unless-stopped
-    networks: pecan
-    environment:
-    - MINIO_ACCESS_KEY=${MINIO_ACCESS_KEY:-carya}
-    - MINIO_SECRET_KEY=${MINIO_SECRET_KEY:-illinois}
-    labels:
-    - traefik.enable=true
-    - traefik.backend=minio
-    - traefik.port=9000
-    - traefik.frontend.rule=${TRAEFIK_FRONTEND_RULE:-}PathPrefix:/minio/
-    volumes: pecan:/data
-  thredds:
-    image: pecan/thredds:${PECAN_VERSION:-latest}
-    restart: unless-stopped
-    networks: pecan
-    volumes: pecan:/data
-    labels:
-    - traefik.enable=true
-    - traefik.port=8080
-    - traefik.frontend.rule=${TRAEFIK_FRONTEND_RULE:-}PathPrefix:/thredds
-    - traefik.backend=thredds
-  rabbitmq:
-    image: rabbitmq:management
-    restart: unless-stopped
-    networks: pecan
-    environment:
-    - RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS=-rabbitmq_management path_prefix "/rabbitmq"
-    - RABBITMQ_DEFAULT_USER=${RABBITMQ_DEFAULT_USER:-guest}
-    - RABBITMQ_DEFAULT_PASS=${RABBITMQ_DEFAULT_PASS:-guest}
-    labels:
-    - traefik.enable=true
-    - traefik.backend=rabbitmq
-    - traefik.port=15672
-    - traefik.frontend.rule=${TRAEFIK_FRONTEND_RULE:-}PathPrefix:/rabbitmq
-    - traefik.website.frontend.whiteList.sourceRange=${TRAEFIK_IPFILTER:-172.16.0.0/12}
-    volumes: rabbitmq:/var/lib/rabbitmq
-  postgres:
-    image: mdillon/postgis:9.5
-    restart: unless-stopped
-    networks: pecan
-    volumes: postgres:/var/lib/postgresql/data
-  bety:
-    image: pecan/bety:${BETY_VERSION:-latest}
-    restart: unless-stopped
-    networks: pecan
-    environment:
-    - UNICORN_WORKER_PROCESSES=1
-    - SECRET_KEY_BASE=${BETY_SECRET_KEY:-notasecret}
-    - RAILS_RELATIVE_URL_ROOT=/bety
-    - LOCAL_SERVER=${BETY_LOCAL_SERVER:-99}
-    depends_on: postgres
-    labels:
-    - traefik.enable=true
-    - traefik.frontend.rule=${TRAEFIK_FRONTEND_RULE:-}PathPrefix:/bety/
-    - traefik.backend=bety
-  rstudio-nginx:
-    image: pecan/rstudio-nginx:${PECAN_VERSION:-latest}
-    networks: pecan
-    depends_on: rstudio
-    labels:
-    - traefik.enable=true
-    - traefik.backend=rstudio
-    - traefik.port=80
-    - traefik.frontend.rule=${TRAEFIK_FRONTEND_RULE:-}PathPrefix:/rstudio
-    - traefik.website.frontend.whiteList.sourceRange=${TRAEFIK_IPFILTER:-172.16.0.0/12}
-  rstudio:
-    image: pecan/base:${PECAN_VERSION:-latest}
-    restart: unless-stopped
-    networks: pecan
-    depends_on:
-    - rabbitmq
-    - postgres
-    environment:
-    - RABBITMQ_URI=${RABBITMQ_URI:-amqp://guest:guest@rabbitmq/%2F}
-    - FQDN=${PECAN_FQDN:-docker}
-    - NAME=${PECAN_NAME:-docker}
-    - USER=${PECAN_RSTUDIO_USER:-carya}
-    - PASSWORD=${PECAN_RSTUDIO_PASS:-illinois}
-    entrypoint: /init
-    volumes:
-    - pecan:/data
-    - rstudio:/home
-  docs:
-    image: pecan/docs:${PECAN_VERSION:-latest}
-    restart: unless-stopped
-    networks: pecan
-    labels:
-    - traefik.enable=true
-    - traefik.frontend.rule=${TRAEFIK_FRONTEND_RULE:-}PathPrefix:/
-    - traefik.backend=docs
-  web:
-    image: pecan/web:${PECAN_VERSION:-latest}
-    restart: unless-stopped
-    networks: pecan
-    environment:
-    - RABBITMQ_URI=${RABBITMQ_URI:-amqp://guest:guest@rabbitmq/%2F}
-    - FQDN=${PECAN_FQDN:-docker}
-    - NAME=${PECAN_NAME:-docker}
-    depends_on:
-    - postgres
-    - rabbitmq
-    labels:
-    - traefik.enable=true
-    - traefik.frontend.rule=${TRAEFIK_FRONTEND_RULE:-}PathPrefix:/pecan/
-    - traefik.backend=pecan
-    volumes:
-    - pecan:/data
-    - pecan:/var/www/html/pecan/data
-  monitor:
-    image: pecan/monitor:${PECAN_VERSION:-latest}
-    restart: unless-stopped
-    networks: pecan
-    ports: 9999:9999
-    environment:
-    - RABBITMQ_URI=${RABBITMQ_URI:-amqp://guest:guest@rabbitmq/%2F}
-    - FQDN=${PECAN_FQDN:-docker}
-    depends_on: rabbitmq
-    labels:
-    - traefik.enable=true
-    - traefik.frontend.rule=${TRAEFIK_FRONTEND_RULE:-}PathPrefixStrip:/monitor/
-    - traefik.backend=monitor
-    volumes: pecan:/data
-  executor:
-    image: pecan/executor:${PECAN_VERSION:-latest}
-    restart: unless-stopped
-    networks: pecan
-    environment:
-    - RABBITMQ_URI=${RABBITMQ_URI:-amqp://guest:guest@rabbitmq/%2F}
-    - FQDN=${PECAN_FQDN:-docker}
-    depends_on:
-    - postgres
-    - rabbitmq
-    volumes: pecan:/data
-  basgra:
-    image: pecan/model-basgra-basgra_n_v1.0:${PECAN_VERSION:-latest}
-    restart: unless-stopped
-    networks: pecan
-    environment: RABBITMQ_URI=${RABBITMQ_URI:-amqp://guest:guest@rabbitmq/%2F}
-    depends_on: rabbitmq
-    volumes: pecan:/data
-  sipnet:
-    image: pecan/model-sipnet-r136:${PECAN_VERSION:-latest}
-    restart: unless-stopped
-    networks: pecan
-    environment: RABBITMQ_URI=${RABBITMQ_URI:-amqp://guest:guest@rabbitmq/%2F}
-    depends_on: rabbitmq
-    volumes: pecan:/data
-  ed2:
-    image: pecan/model-ed2-git:${PECAN_VERSION:-latest}
-    restart: unless-stopped
-    networks: pecan
-    environment: RABBITMQ_URI=${RABBITMQ_URI:-amqp://guest:guest@rabbitmq/%2F}
-    depends_on: rabbitmq
-    volumes: pecan:/data
-  maespa:
-    image: pecan/model-maespa-git:${PECAN_VERSION:-latest}
-    restart: unless-stopped
-    networks: pecan
-    environment: RABBITMQ_URI=${RABBITMQ_URI:-amqp://guest:guest@rabbitmq/%2F}
-    depends_on: rabbitmq
-    volumes: pecan:/data
-  dbsync:
-    image: pecan/shiny-dbsync:${PECAN_VERSION:-latest}
-    restart: unless-stopped
-    networks: pecan
-    depends_on: postgres
-    labels:
-    - traefik.enable=true
-    - traefik.backend=dbsync
-    - traefik.port=3838
-    - traefik.frontend.rule=${TRAEFIK_FRONTEND_RULE:-}PathPrefixStrip:/dbsync/
-  api:
-    image: pecan/api:${PECAN_VERSION:-latest}
-    networks: pecan
-    environment:
-    - PGHOST=${PGHOST:-postgres}
-    - HOST_ONLY=${HOST_ONLY:-FALSE}
-    - AUTH_REQ=${AUTH_REQ:-TRUE}
-    - RABBITMQ_URI=${RABBITMQ_URI:-amqp://guest:guest@rabbitmq/%2F}
-    - DATA_DIR=${DATA_DIR:-/data/}
-    - DBFILES_DIR=${DBFILES_DIR:-/data/dbfiles/}
-    labels:
-    - traefik.enable=true
-    - traefik.frontend.rule=${TRAEFIK_FRONTEND_RULE:-}PathPrefix:/api
-    - traefik.backend=api
-    - traefik.port=8000
-    depends_on: postgres
-    volumes: pecan:/data/
-networks:
-  pecan: ~
-volumes:
-  traefik: ~
-  postgres: ~
-  rabbitmq: ~
-  pecan: ~
-  portainer: ~
-  rstudio: ~
-

There are two ways you can override different values in the docker-compose.yml file. The first method is to create a file called .env that is placed in the same folder as the docker-compose.yml file. This file can override some of configuration variables used by docker-compose. For example the following is an example of the env file

-
# This file will override the configation options in the docker-compose
-# file. Copy this file to the same folder as docker-compose as .env
-
-# ----------------------------------------------------------------------
-# GENERAL CONFIGURATION
-# ----------------------------------------------------------------------
-
-# project name (-p flag for docker-compose)
-#COMPOSE_PROJECT_NAME=pecan
-
-# ----------------------------------------------------------------------
-# TRAEFIK CONFIGURATION
-# ----------------------------------------------------------------------
-
-# hostname of server
-#TRAEFIK_HOST=Host:pecan-docker.ncsa.illinois.edu;
-
-# only allow access from localhost and NCSA
-#TRAEFIK_IPFILTER=172.16.0.0/12, 141.142.0.0/16
-
-# Run traffik on port 80 (http) and port 443 (https)
-#TRAEFIK_HTTP_PORT=80
-#TRAEFIK_HTTPS_PORT=443
-#TRAEFIK_HTTPS_OPTIONS=TLS
-
-# enable SSL cerificate generation
-#TRAEFIK_ACME_ENABLE=true
-
-# Use you real email address here to be notified if cert expires
-#TRAEFIK_ACME_EMAIL=pecanproj@gmail.com
-
-# Always use https, trafic to http is redirected to https
-#TRAEFIK_HTTP_REDIRECT=Redirect.EntryPoint:https
-
-# ----------------------------------------------------------------------
-# PEcAn CONFIGURATION
-# ----------------------------------------------------------------------
-
-# what version of pecan to use
-#PECAN_VERSION=develop
-
-# the fully qualified hostname used for this server
-#PECAN_FQDN=pecan-docker.ncsa.illinois.edu
-
-# short name shown in the menu
-#PECAN_NAME=pecan-docker
-
-# ----------------------------------------------------------------------
-# BETY CONFIGURATION
-# ----------------------------------------------------------------------
-
-# what version of BETY to use
-#BETY_VERSION=develop
-
-# what is our server number, 99=vm, 98=docker
-#BETY_LOCAL_SERVER=98
-
-# secret used to encrypt cookies in BETY
-#BETY_SECRET_KEY=1208q7493e8wfhdsohfo9ewhrfiouaho908ruq30oiewfdjspadosuf08q345uwrasdy98t7q243
-
-# ----------------------------------------------------------------------
-# MINIO CONFIGURATION
-# ----------------------------------------------------------------------
-
-# minio username and password
-#MINIO_ACCESS_KEY=carya
-#MINIO_SECRET_KEY=illinois
-
-# ----------------------------------------------------------------------
-# PORTAINER CONFIGURATION
-# ----------------------------------------------------------------------
-
-# password for portainer admin account
-# use docker run --rm httpd:2.4-alpine htpasswd -nbB admin <password> | cut -d ":" -f 2
-#PORTAINER_PASSWORD=$2y$05$5meDPBtS3NNxyGhBpYceVOxmFhiiC3uY5KEy2m0YRbWghhBr2EVn2
-
-# ----------------------------------------------------------------------
-# RABBITMQ CONFIGURATION
-# ----------------------------------------------------------------------
-
-# RabbitMQ username and password
-#RABBITMQ_DEFAULT_USER=carya
-#RABBITMQ_DEFAULT_PASS=illinois
-
-# create the correct URI with above username and password
-#RABBITMQ_URI=amqp://carya:illinois@rabbitmq/%2F
-
-# ----------------------------------------------------------------------
-# RSTUDIO CONFIGURATION
-# ----------------------------------------------------------------------
-
-# Default RStudio username and password for startup of container
-#PECAN_RSTUDIO_USER=carya
-#PECAN_RSTUDIO_PASS=illinois
-

You can also extend the docker-compose.yml file with a docker-compose.override.yml file (in the same directory), allowing you to add more services, or for example to change where the volumes are stored (see official documentation). For example the following will change the volume for postgres to be stored in your home directory:

-
version: "3"
-
-volumes:
-  postgres:
-    driver_opts:
-      type: none
-      device: ${HOME}/postgres
-      o: bind
-
-
-

24.4.3 Top-level structure

-

The root of the docker-compose.yml file contains three sections:

-
    -
  • services – This is a list of services provided by the application, with each service corresponding to a container. -When communicating with each other internally, the hostnames of containers correspond to their names in this section. -For instance, regardless of the “project” name passed to docker-compose up, the hostname for connecting to the PostgreSQL database of any given container is always going to be postgres (e.g. you should be able to access the PostgreSQL database by calling the following from inside the container: psql -d bety -U bety -h postgres). -The services comprising the PEcAn application are described below.

  • -
  • networks – This is a list of networks used by the application. -Containers can only communicate with each other (via ports and hostnames) if they are on the same Docker network, and containers on different networks can only communicate through ports exposed by the host machine. -We just provide the network name (pecan) and resort to Docker’s default network configuration. -Note that the services we want connected to this network include a networks: ... - pecan tag. -For more details on Docker networks, see the official documentation.

  • -
  • volumes – Similarly to networks, this just contains a list of volume names we want. -Briefly, in Docker, volumes are directories containing files that are meant to be shared across containers. -Each volume corresponds to a directory, which can be mounted at a specific location by different containers. -For example, syntax like volumes: ... - pecan:/data in a service definition means to mount the pecan “volume” (including its contents) in the /data directory of that container. -Volumes also allow data to persist on containers between restarts, as normally, any data created by a container during its execution is lost when the container is re-launched. -For example, using a volume for the database allows data to be saved between different runs of the database container. -Without volumes, we would start with a blank database every time we restart the containers. -For more details on Docker volumes, see the official documentation. -Here, we define three volumes:

    -
      -
    • postgres – This contains the data files underlying the PEcAn PostgreSQL database (BETY). -Notice that it is mounted by the postgres container to /var/lib/postgresql/data. -This is the data that we pre-populate when we run the Docker commands to initialize the PEcAn database. -Note that these are the values stored directly in the PostgreSQL database. -The default files to which the database points (i.e. dbfiles) are stored in the pecan volume, described below.

    • -
    • rabbitmq – This volume contains persistent data for RabbitMQ. -It is only used by the rabbitmq service.

    • -
    • pecan – This volume contains PEcAn’s dbfiles, which include downloaded and converted model inputs, processed configuration files, and outputs. -It is used by almost all of the services in the PEcAn stack, and is typically mounted to /data.

    • -
  • -
-
-
-

24.4.4 traefik

-

Traefik manages communication among the different PEcAn services and between PEcAn and the web. -Among other things, traefik facilitates the setup of web access to each PEcAn service via common and easy-to-remember URLs. -For instance, the following lines in the web service configure access to the PEcAn web interface via the URL http://localhost:8000/pecan/ :

-
labels:
-- traefik.enable=true
-- traefik.frontend.rule=${TRAEFIK_FRONTEND_RULE:-}PathPrefix:/pecan/
-- traefik.backend=pecan
-

(Further details in the works…)

-

The traefik service configuration looks like this:

-
traefik:
-  image: traefik:1.7
-  command:
-  - --loglevel=INFO
-  - --api
-  - --defaultentrypoints=https,http
-  - --entryPoints=Name:http Address::${TRAEFIK_HTTP_PORT:-8000} ${TRAEFIK_HTTP_REDIRECT:-""}
-  - --entryPoints=Name:https Address::${TRAEFIK_HTTPS_PORT:-8443} ${TRAEFIK_HTTPS_OPTIONS:-TLS}
-  - --acme=${TRAEFIK_ACME_ENABLE:-false}
-  - --acme.email=${TRAEFIK_ACME_EMAIL:-""}
-  - --acme.entrypoint=https
-  - --acme.onhostrule=true
-  - --acme.storage=/config/acme.json
-  - --acme.httpchallenge.entrypoint=http
-  - --acme.storage=/config/acme.json
-  - --acme.acmelogging=true
-  - --docker=true
-  - --docker.endpoint=unix:///var/run/docker.sock
-  - --docker.exposedbydefault=false
-  - --docker.watch=true
-  restart: unless-stopped
-  networks: pecan
-  ports:
-  - ${TRAEFIK_HTTP_PORT-8000}:${TRAEFIK_HTTP_PORT:-8000}
-  - ${TRAEFIK_HTTPS_PORT-8443}:${TRAEFIK_HTTPS_PORT:-8443}
-  labels:
-  - traefik.enable=true
-  - traefik.backend=traefik
-  - traefik.port=8080
-  - 'traefik.frontend.rule=${TRAEFIK_FRONTEND_RULE:-}PathPrefixStrip: /traefik'
-  - traefik.website.frontend.whiteList.sourceRange=${TRAEFIK_IPFILTER:-172.16.0.0/12}
-  volumes:
-  - /var/run/docker.sock:/var/run/docker.sock:ro
-  - traefik:/config
-
-
-

24.4.5 portainer

-

portainer is lightweight management UI that allows you to manage the docker host (or swarm). You can use this service to monitor the different containers, see the logfiles, and start and stop containers.

-

The portainer service configuration looks like this:

-
NA: ~
-

Portainer is accessible by browsing to localhost:8000/portainer/. You can either set the password in the .env file (for an example see env.example) or you can use the web browser and go to the portainer url. If this is the first time it will ask for your password.

-
-
-

24.4.6 minio

-

Minio is a service that provides access to the a folder on disk through a variety of protocols, including S3 buckets and web-based access. -We mainly use Minio to facilitate access to PEcAn data using a web browser without the need for CLI tools.

-

Our current configuration is as follows:

-
minio:
-  image: minio/minio:latest
-  command: server /data
-  restart: unless-stopped
-  networks: pecan
-  environment:
-  - MINIO_ACCESS_KEY=${MINIO_ACCESS_KEY:-carya}
-  - MINIO_SECRET_KEY=${MINIO_SECRET_KEY:-illinois}
-  labels:
-  - traefik.enable=true
-  - traefik.backend=minio
-  - traefik.port=9000
-  - traefik.frontend.rule=${TRAEFIK_FRONTEND_RULE:-}PathPrefix:/minio/
-  volumes: pecan:/data
-

The Minio interface is accessible by browsing to localhost:8000/minio/. -From there, you can browse directories and download files. -You can also upload files by clicking the red “+” in the bottom-right corner.

-

Note that it is currently impossible to create or upload directories using the Minio interface (except in the /data root directory – those folders are called “buckets” in Minio). -Therefore, the recommended way to perform any file management tasks other than individual file uploads is through the command line, e.g.

- -
-
-

24.4.7 thredds

-

This service allows PEcAn model outputs to be accessible via the THREDDS data server (TDS). -When the PEcAn stack is running, the catalog can be explored in a web browser at http://localhost:8000/thredds/catalog.html. -Specific output files can also be accessed from the command line via commands like the following:

-

Note that everything after outputs/ exactly matches the directory structure of the workflows directory.

-

Which files are served, which subsetting services are available, and other aspects of the data server’s behavior are configured in the docker/thredds_catalog.xml file. -Specifically, this XML tells the data server to use the datasetScan tool to serve all files within the /data/workflows directory, with the additional filter that only files ending in .nc are served. -For additional information about the syntax of this file, see the extensive THREDDS documentation.

-

Our current configuration is as follows:

-
thredds:
-  image: pecan/thredds:${PECAN_VERSION:-latest}
-  restart: unless-stopped
-  networks: pecan
-  volumes: pecan:/data
-  labels:
-  - traefik.enable=true
-  - traefik.port=8080
-  - traefik.frontend.rule=${TRAEFIK_FRONTEND_RULE:-}PathPrefix:/thredds
-  - traefik.backend=thredds
-
-
-

24.4.8 postgres

-

This service provides a working PostGIS database. -Our configuration is fairly straightforward:

-
postgres:
-  image: mdillon/postgis:9.5
-  restart: unless-stopped
-  networks: pecan
-  volumes: postgres:/var/lib/postgresql/data
-

Some additional details about our configuration:

-
    -
  • image – This pulls a container with PostgreSQL + PostGIS pre-installed. -Note that by default, we use PostgreSQL version 9.5. -To experiment with other versions, you can change 9.5 accordingly.

  • -
  • networks – This allows PostgreSQL to communicate with other containers on the pecan network. -As mentioned above, the hostname of this service is just its name, i.e. postgres, so to connect to the database from inside a running container, use a command like the following: psql -d bety -U bety -h postgres

  • -
  • volumes – Note that the PostgreSQL data files (which store the values in the SQL database) are stored on a volume called postgres (which is not the same as the postgres service, even though they share the same name).

  • -
-
-
-

24.4.9 rabbitmq

-

RabbitMQ is a message broker service. -In PEcAn, RabbitMQ functions as a task manager and scheduler, coordinating the execution of different tasks (such as running models and analyzing results) associated with the PEcAn workflow.

-

Our configuration is as follows:

-
rabbitmq:
-  image: rabbitmq:management
-  restart: unless-stopped
-  networks: pecan
-  environment:
-  - RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS=-rabbitmq_management path_prefix "/rabbitmq"
-  - RABBITMQ_DEFAULT_USER=${RABBITMQ_DEFAULT_USER:-guest}
-  - RABBITMQ_DEFAULT_PASS=${RABBITMQ_DEFAULT_PASS:-guest}
-  labels:
-  - traefik.enable=true
-  - traefik.backend=rabbitmq
-  - traefik.port=15672
-  - traefik.frontend.rule=${TRAEFIK_FRONTEND_RULE:-}PathPrefix:/rabbitmq
-  - traefik.website.frontend.whiteList.sourceRange=${TRAEFIK_IPFILTER:-172.16.0.0/12}
-  volumes: rabbitmq:/var/lib/rabbitmq
-

Note that the traefik.frontend.rule indicates that browsing to http://localhost:8000/rabbitmq/ leads to the RabbitMQ management console.

-

By default, the RabbitMQ management console has username/password guest/guest, which is highly insecure. -For production instances of PEcAn, we highly recommend changing these credentials to something more secure, and removing access to the RabbitMQ management console via Traefik.

-
-
-

24.4.10 bety

-

This service operates the BETY web interface, which is effectively a web-based front-end to the PostgreSQL database. -Unlike the postgres service, which contains all the data needed to run PEcAn models, this service is not essential to the PEcAn workflow. -However, note that certain features of the PEcAn web interface do link to the BETY web interface and will not work if this container is not running.

-

Our configuration is as follows:

-
bety:
-  image: pecan/bety:${BETY_VERSION:-latest}
-  restart: unless-stopped
-  networks: pecan
-  environment:
-  - UNICORN_WORKER_PROCESSES=1
-  - SECRET_KEY_BASE=${BETY_SECRET_KEY:-notasecret}
-  - RAILS_RELATIVE_URL_ROOT=/bety
-  - LOCAL_SERVER=${BETY_LOCAL_SERVER:-99}
-  depends_on: postgres
-  labels:
-  - traefik.enable=true
-  - traefik.frontend.rule=${TRAEFIK_FRONTEND_RULE:-}PathPrefix:/bety/
-  - traefik.backend=bety
-

The BETY container Dockerfile is located in the root directory of the BETY GitHub repository (direct link).

-
-
-

24.4.11 docs

-

This service will show the documentation for the version of PEcAn running as well as a homepage with links to all relevant endpoints. You can access this at http://localhost:8000/. You can find the documentation for PEcAn at http://localhost:8000/docs/pecan/.

-

Our current configuration is as follows:

-
docs:
-  image: pecan/docs:${PECAN_VERSION:-latest}
-  restart: unless-stopped
-  networks: pecan
-  labels:
-  - traefik.enable=true
-  - traefik.frontend.rule=${TRAEFIK_FRONTEND_RULE:-}PathPrefix:/
-  - traefik.backend=docs
-
-
-

24.4.12 web

-

This service runs the PEcAn web interface. -It is effectively a thin wrapper around a standard Apache web server container from Docker Hub that installs some additional dependencies and copies over the necessary files from the PEcAn source code.

-

Our configuration is as follows:

-
web:
-  image: pecan/web:${PECAN_VERSION:-latest}
-  restart: unless-stopped
-  networks: pecan
-  environment:
-  - RABBITMQ_URI=${RABBITMQ_URI:-amqp://guest:guest@rabbitmq/%2F}
-  - FQDN=${PECAN_FQDN:-docker}
-  - NAME=${PECAN_NAME:-docker}
-  depends_on:
-  - postgres
-  - rabbitmq
-  labels:
-  - traefik.enable=true
-  - traefik.frontend.rule=${TRAEFIK_FRONTEND_RULE:-}PathPrefix:/pecan/
-  - traefik.backend=pecan
-  volumes:
-  - pecan:/data
-  - pecan:/var/www/html/pecan/data
-

Its Dockerfile ships with the PEcAn source code, in docker/web/Dockerfile.

-

In terms of actively developing PEcAn using Docker, this is the service to modify when making changes to the web interface (i.e. PHP, HTML, and JavaScript code located in the PEcAn web directory).

-
-
-

24.4.13 executor

-

This service is in charge of running the R code underlying the core PEcAn workflow. -However, it is not in charge of executing the models themselves – model binaries are located on their own dedicated Docker containers, and model execution is coordinated by RabbitMQ.

-

Our configuration is as follows:

-
executor:
-  image: pecan/executor:${PECAN_VERSION:-latest}
-  restart: unless-stopped
-  networks: pecan
-  environment:
-  - RABBITMQ_URI=${RABBITMQ_URI:-amqp://guest:guest@rabbitmq/%2F}
-  - FQDN=${PECAN_FQDN:-docker}
-  depends_on:
-  - postgres
-  - rabbitmq
-  volumes: pecan:/data
-

Its Dockerfile is ships with the PEcAn source code, in docker/executor/Dockerfile. -Its image is built on top of the pecan/base image (docker/base/Dockerfile), which contains the actual PEcAn source. -To facilitate caching, the pecan/base image is itself built on top of the pecan/depends image (docker/depends/Dockerfile), a large image that contains an R installation and PEcAn’s many system and R package dependencies (which usually take ~30 minutes or longer to install from scratch).

-

In terms of actively developing PEcAn using Docker, this is the service to modify when making changes to the PEcAn R source code. -Note that, unlike changes to the web image’s PHP code, changes to the R source code do not immediately propagate to the PEcAn container; instead, you have to re-compile the code by running make inside the container.

-
-
-

24.4.14 monitor

-

This service will show all models that are currently running http://localhost:8000/monitor/. This list returned is JSON and shows all models (grouped by type and version) that are currently running, or where seen in the past. This list will also contain a list of all current active containers, as well as how many jobs are waiting to be processed.

-

This service is also responsible for registering any new models with PEcAn so users can select it and execute the model from the web interface.

-

Our current configuration is as follows:

-
monitor:
-  image: pecan/monitor:${PECAN_VERSION:-latest}
-  restart: unless-stopped
-  networks: pecan
-  ports: 9999:9999
-  environment:
-  - RABBITMQ_URI=${RABBITMQ_URI:-amqp://guest:guest@rabbitmq/%2F}
-  - FQDN=${PECAN_FQDN:-docker}
-  depends_on: rabbitmq
-  labels:
-  - traefik.enable=true
-  - traefik.frontend.rule=${TRAEFIK_FRONTEND_RULE:-}PathPrefixStrip:/monitor/
-  - traefik.backend=monitor
-  volumes: pecan:/data
-
-
-

24.4.15 Model-specific containers

-

Additional models are added as additional services. -In general, their configuration should be similar to the following configuration for SIPNET, which ships with PEcAn:

-
sipnet:
-  image: pecan/model-sipnet-r136:${PECAN_VERSION:-latest}
-  restart: unless-stopped
-  networks: pecan
-  environment: RABBITMQ_URI=${RABBITMQ_URI:-amqp://guest:guest@rabbitmq/%2F}
-  depends_on: rabbitmq
-  volumes: pecan:/data
-

The PEcAn source contains Dockerfiles for ED2 (models/ed/Dockerfile) and SIPNET (models/sipnet/Dockerfile) that can serve as references. -For additional tips on constructing a Dockerfile for your model, see Dockerfiles for Models.

- -
-
-
-

24.5 Models using Docker

-

This section will discuss how to add new models to PEcAn docker. To be able to add a new model to PEcAn when using docker is as simple as starting a new container. The model will come online and let the PEcAn framework know there is a new model available, there is no need to go through the process of registering this model with PEcAn. Users will be able to select this new model from web interface and run with this model selected.

-

For this process to work a docker image of the model will need to be created as well as small json file that is used to announce this new model. A separate service in PEcAn (monitor) will use this json file to keep track of all models available as well as register these models with PEcAn.

-

Model information -Model build -Common problems

-
-

24.5.1 Model information

-

Each model will have a small json file called model_info.json that is used to describe the model and used by the monitor service to register the model with PEcAn. This file will contain information about the model that is send as part of the heartbeat of the container to the monitor service. Below is an example of this file for the ED model. The required fields are name, type, version and binary. The fields type and version are used by PEcAn to send the messages to RabbitMQ. There is no need to specify the queue name explicitly. The queue name will be created by combining these two fields with an underscore. The field binary is used to point to the actual binary in the docker container.

-

There are 2 special values that can be used, @VERSION@ which will be replaced by the version that is passed in when building the container, and @BINARY@ which will be replaced by the binary when building the docker image.

- -

Other fields that are recommended, but currently not used yet, are:

-
    -
  • description : a longer description of the model.
  • -
  • creator : contact person about this docker image.
  • -
  • contribuor : other people that have contributed to this docker image.
  • -
  • links : addtional links to help people when using this docker image, for example values that can be used are source to link to the source code, issues to link to issue tracking system, and documentation to link to model specific documentation.
  • -
  • citation : how the model should be cited in publications.
  • -
-
-
-

24.5.2 Model build

-

In general we try to minimize the size of the images. To be able to do this we split the process of creating the building of the model images into two pieces (or leverage of an image that exists from the original model developers). If you look at the example Dockerfile you will see that there are 2 sections, the first section will build the model binary, the second section will build the actual PEcAn model, which copies the binary from the first section.

-

This is an example of how the ED2 model is build. This will install all the packages needed to build ED2 model, gets the latest version from GitHub and builds the model.

-

The second section will create the actual model runner. This will leverage the PEcAn model image that has PEcAn already installed as well as the python code to listen for messages and run the actual model code. This will install some additional packages needed by the model binary (more about that below), copy the model_info.json file and change the @VERSION@ and @BINARY@ placeholders.

-

It is important values for type and version are set correct. The PEcAn code will use these to register the model with the BETY database, which is then used by PEcAn to send out a message to a specfic worker queue, if you do not set these variables correctly your model executor will pick up messages for the wrong model.

-

To build the docker image, we use a Dockerfile (see example below) and run the following command. This command will expect the Dockerfile to live in the model specific folder and the command is executed in the root pecan folder. It will copy the content of the pecan folder and make it available to the build process (in this example we do not need any additional files).

-

Since we can have multiple different versions of a model be available for PEcAn we ar using the following naming schema pecan/model-<modeltype>-<version>:<pecan version. For example the image below will be named pecan/model-ed2-git, since we do not specify the exact version it will be atomically be named pecan/model-ed2-git:latest.

- -

Example of a Dockerfile, in this case to build the ED2 model.

-
# ----------------------------------------------------------------------
-# BUILD MODEL BINARY
-# ----------------------------------------------------------------------
-FROM debian:stretch as model-binary
-
-# Some variables that can be used to set control the docker build
-ARG MODEL_VERSION=git
-
-# install dependencies
-RUN apt-get update \
-    && apt-get install -y --no-install-recommends \
-       build-essential \
-       curl \
-       gfortran \
-       git \
-       libhdf5-dev \
-       libopenmpi-dev \
-    && rm -rf /var/lib/apt/lists/*
-
-# download, unzip and build ed2
-WORKDIR /src
-RUN git -c http.sslVerify=false clone https://github.com/EDmodel/ED2.git \
-    && cd ED2/ED/build \
-    && curl -o make/include.mk.VM http://isda.ncsa.illinois.edu/~kooper/EBI/include.mk.opt.Linux \
-    && if [ "${MODEL_VERSION}" != "git" ]; then git checkout ${MODEL_VERSION}; fi \
-    && ./install.sh -g -p VM
-
-########################################################################
-
-# ----------------------------------------------------------------------
-# BUILD PECAN FOR MODEL
-# ----------------------------------------------------------------------
-FROM pecan/models:latest
-
-# ----------------------------------------------------------------------
-# INSTALL MODEL SPECIFIC PIECES
-# ----------------------------------------------------------------------
-
-RUN apt-get update \
-    && apt-get install -y --no-install-recommends \
-       libgfortran3 \
-       libopenmpi2 \
-    && rm -rf /var/lib/apt/lists/*
-
-# ----------------------------------------------------------------------
-# SETUP FOR SPECIFIC MODEL
-# ----------------------------------------------------------------------
-
-# Some variables that can be used to set control the docker build
-ARG MODEL_VERSION=git
-
-# Setup model_info file
-COPY models/ed/model_info.json /work/model.json
-RUN sed -i -e "s/@VERSION@/${MODEL_VERSION}/g" \
-           -e "s#@BINARY@#/usr/local/bin/ed2.${MODEL_VERSION}#g" /work/model.json
-
-# COPY model binary
-COPY --from=model-binary /src/ED2/ED/build/ed_2.1-opt /usr/local/bin/ed2.${MODEL_VERSION}
-

WARNING: Dockerfile environment variables set via ENV are assigned all at once; they do not evaluate successively, left to right. -Consider the following block:

- -

In this block, the expansion for setting MODEL_TYPE_VERSION is not aware of the current values of MODEL_TYPE or MODEL_VERSION, and will therefore be set incorrectly to just _ (unless they have been set previously, in which case it will be aware only of their earlier values). -As such, variables depending on other variables must be set in a separate, subsequent ENV statement than the variables they depend on.

-

Once the model has build and is working we can add it to the PEcAn stack and be able to use this model in the web interface. There are two methods to start this new model. First, we can add it to the docker-compose.yml file and start the container using docker-compose -p pecan -d up.

- -

Alternatively we can start the container manually using the following command.

- -
-
-

24.5.3 Common problems

-

Following are some solutions for common problems that you might encounter when building the docker images for a model.

-
-
-

24.5.4 Debugging missing libraries

-

When building the model binary it might require specific libraries to be installed. In the second stage the model binary is copied into a new image, which could result in the binary missing specific libraries. In the case of the ED2 model the following was used to find the libraries that are needed to be installed (libgfortran5 and libopenmpi3).

-

The first step is to build the model using the Dockerfile (in this case the ap-get install was missing in the second stage).

-
Step 5/9 : RUN git clone https://github.com/EDmodel/ED2.git     && cd ED2/ED/build     && curl -o make/include.mk.VM http://isda.ncsa.illinois.edu/~kooper/EBI/include.mk.opt.`uname -s`     && if [ "${MODEL_VERSION}" != "git" ]; then git checkout ${MODEL_VERSION}; fi     && ./install.sh -g -p VM
-... LOTS OF OUTPUT ...
-make[1]: Leaving directory '/src/ED2/ED/build/bin-opt-E'
-Installation Complete.
-Removing intermediate container a53eba9a8fc1
- ---> 7f23c6302130
-Step 6/9 : FROM pecan/executor:latest
- ---> f19d81b739f5
-... MORE OUTPUT ...
-Step 9/9 : COPY --from=model-binary /src/ED2/ED/build/ed_2.1-opt /usr/local/bin/ed2.${MODEL_VERSION}
- ---> 07ac841be457
-Successfully built 07ac841be457
-Successfully tagged pecan/pecan-ed2:latest
-

At this point we have created a docker image with the binary and all PEcAn code that is needed to run the model. Some models (especially those build as native code) might be missing additional packages that need to be installed in the docker image. To see if all libraries are installed for the binary.

- -

Start the build container again (this is the number before the line FROM pecan/executor:latest, 7f23c6302130 in the example), and find the missing libraries listed above (for example libmpi_usempif08.so.40):

- -

This shows the pages is libopenmpi3 that needs to be installed, do this for all missing packages, modify the Dockerfile and rebuild. Next time you run the ldd command there should be no more packages being listed.

- -
-
-
-

24.6 Building and modifying images

-

The only other section on this page is: -Local development and testing with Docker

-

For general use, it is sufficient to use the pre-built PEcAn images hosted on Docker Hub (see Docker quickstart). -However, there are cases where it makes sense to re-build the Docker images locally. -The following is a list of PEcAn-specific images and reasons why you would want to rebuild them locally:

-
    -
  • pecan/depends – Rebuild if: -
      -
    • You modify the docker/depends/Dockerfile
    • -
    • You introduce new system dependencies (i.e. things that need to be installed with apt-get)
    • -
    • You introduce new R package dependencies, and you want those R package installations to be cached during future builds. For packages with fast build times, it may be fine to let them be installed as part of PEcAn’s standard build process (i.e. make).
    • -
  • -
  • pecan/base – Rebuild if: -
      -
    • You built a new version of pecan/depends (on which pecan/base depends)
    • -
    • You modify the docker/base/Dockerfile
    • -
    • You made changes to the PEcAn R package source code, the Makefile, or web/workflow.R. -
        -
      • NOTE that changes to the web interface code affect pecan/web, not pecan/base
      • -
    • -
  • -
  • pecan/executor – Rebuild if: -
      -
    • You built a new version of pecan/base (on which pecan/executor depends) and/or, pecan/depends (on which pecan/base depends)
    • -
    • You modified the docker/executor/Dockerfile
    • -
    • You modified the RabbitMQ Python scripts (e.g. docker/receiver.py, docker/sender.py)
    • -
  • -
  • pecan/web – Rebuild if you modified any of the following: -
      -
    • docker/web/Dockerfile
    • -
    • The PHP/HTML/JavaScript code for the PEcAn web interface in web/ (except web/workflow.R – that goes in pecan/base)
    • -
    • docker/config.docker.php (the config.php file for Docker web instances)
    • -
    • documentation/index_vm.html (the documentation HTML website)
    • -
    • NOTE: Because changes to this code are applied instantly (i.e. do not require compilation or installation), a more effective way to do local development may be to mount the web/ or other relevant folders as a volume onto the pecan/web container.
    • -
  • -
-

The easiest way to quickly re-build all of the images is using the docker.sh script in the PEcAn source code root directory. -This script will build all of the docker images locally on your machine, and tag them as latest. -This will not build the pecan/depends image by default because that takes considerably longer. -However, you can force the script to build pecan/depends as well by setting the DEPEND environment variable to 1 (i.e. DEPEND=1 ./docker.sh). -The following instructions provide details on how to build each image individually.

-

To build an image locally, use the docker build command as described below. -For more details, see docker build --help or the online Docker build documentation.

-

First, in a terminal window, navigate (cd) into the PEcAn source code root directory. -From there, the general syntax for building an image looks like the following:

- -

For instance, to build a local version of the pecan/depends:latest image, you would run:

- -

The breakdown of this command is as follows:

-
    -
  • docker build – This is the core command. -The standard syntax is docker build [OPTIONS] <PATH>, where <PATH> refers to the directory to be used as the “build context”. -The “build context” is the working directory assumed by the Dockerfiles. -In PEcAn, this is always the PEcAn source code root directory, which allows Dockerfiles to use instructions such as COPY web/workflow.R /work/. -In this example, the <PATH> is set to the current working directory, i.e. . because we are already in the PEcAn root directory. -If you were located in a different directory, you would have to provide a path to the PEcAn source code root directory. -Also, by default, docker build will look for a Dockerfile located at <PATH>/Dockerfile, but this is modified by the -f option described below.

  • -
  • -t pecan/depends:latest – The -t/--tag option specifies how the image will be labeled. -By default, Docker only defines unique image IDs, which are hexidecimal strings that are unintuitive and hard to remember. -Tags are useful for referring to specific images in a human-readable way. -Note that the same unique image can have multiple tags associated with it, so it is possible for, e.g. pecan/depends:latest, pecan/depends:custom, and even mypecan/somethingelse:20.0 to refer to the same exact image. -To see a table of all local images, including their tags and IDs, run docker image ls. -
      -
    • NOTE: PEcAn’s docker-compose.yml can be configured via the PECAN environment variable to point at different versions of PEcAn images. -By default, it points to the :latest versions of all images. -However, if you wanted to, for instance, build :local images corresponding to your local source code and then run that version of PEcAn, you would run:
    • -
    -
    PECAN=local docker-compose -p pecan up -d
    -

    This is an effective way to do local development and testing of different PEcAn versions, as described below.

  • -
  • -f docker/depends/Dockerfile – The -f/--file tag is used to provide an alternative location and file name for the Dockerfile.

  • -
-
-

24.6.1 Local development and testing with Docker

-

The following is an example of one possible workflow for developing and testing PEcAn using local Docker images. -The basic idea is to mount a local version of the PEcAn source code onto a running pecan/executor image, and then send a special “rebuild” RabbitMQ message to the container to trigger the rebuild whenever you make changes. -NOTE: All commands assume you are working from the PEcAn source code root directory.

-
    -
  1. In the PEcAn source code directory, create a docker-compose.override.yml file with the following contents.:

    - -

    This will mount the current directory . to the /pecan directory in the executor container. -The special docker-compose.override.yml file is read automatically by docker-compose and overrides or extends any instructions set in the original docker-compose.yml file. -It provides a convenient way to host server-specific configurations without having to modify the project-wide (and version-controlled) default configuration. -For more details, see the Docker Compose documentation.

  2. -
  3. Update your PEcAn Docker stack with docker-compose up -d. -If the stack is already running, this should only restart your executor instance while leaving the remaining containers running.

  4. -
  5. To update to the latest local code, run ./scripts/docker_rebuild.sh. -Under the hood, this uses curl to post a RabbitMQ message to a running Docker instance. -By default, the scripts assumes that username and password are both guest and that the RabbitMQ URL is http://localhost:8000/rabbitmq. -All of these can be customized by setting the environment variables RABBITMQ_USER, RABBITMQ_PASSWORD, and RABBITMQ_URL, respectively (or running the script prefixed with those variables, e.g. RABBITMQ_USER=carya RABBITMQ_PASSWORD=illinois ./scripts/docker_rebuild.sh). -This step can be repeated whenever you want to trigger a rebuild of the local code.

  6. -
-

NOTE: The updates with this workflow are specific to the running container session; restarting the executor container will revert to the previous versions of the installed packages. -To make persistent changes, you should re-build the pecan/base and pecan/executor containers against the current version of the source code.

-

NOTE: The mounted PEcAn source code directory includes everything in your local source directory, including installation artifacts used by make. -This can lead to two common issues: -- Any previous make cache files (stuff in the .install, .docs, etc. directories) persist across container instances, even though the installed packages may not. To ensure a complete build, it’s a good idea to run make clean on the host machine to remove these artifacts. -- Similarly, any installation artifacts from local builds will be carried over to the build. In particular, be wary of packages with compiled code, such as modules/rtm (PEcAnRTM) – the compiled .o, .so, .mod, etc. files from compilation of such packages will carry over into the build, which can cause conflicts if the package was also built locally.

-

The docker-compose.override.yml is useful for some other local modifications. -For instance, the following adds a custom ED2 “develop” model container.

- -

Similarly, this snippet modifies the pecan network to use a custom IP subnet mask. -This is required on the PNNL cluster because its servers’ IP addresses often clash with Docker’s default IP mask.

- - -
-
-
-

24.7 Troubleshooting Docker

-
-

24.7.1 “Package not available” while building images

-

PROBLEM: Packages fail to install while building pecan/depends and/or pecan/base with an error like the following:

-
Installing package into ‘/usr/local/lib/R/site-library’
-(as ‘lib’ is unspecified)
-Warning: unable to access index for repository https://mran.microsoft.com/snapshot/2018-09-01/src/contrib:
- cannot open URL 'https://mran.microsoft.com/snapshot/2018-09-01/src/contrib/PACKAGES'
-Warning message:
-package ‘<PACKAGE>’ is not available (for R version 3.5.1)
-

CAUSE: This can sometimes happen if there are problems with Microsoft’s CRAN snapshots, which are the default repository for the rocker/tidyverse containers. -See GitHub issues rocker-org/rocker-versioned#102 and #58.

-

SOLUTION: Add the following line to the depends and/or base Dockerfiles before (i.e. above) any commands that install R packages (e.g. Rscript -e "install.packages(...)"):

-
RUN echo "options(repos = c(CRAN = 'https://cran.rstudio.org'))" >> /usr/local/lib/R/etc/Rprofile.site
-

This will set the default repository to the more reliable (albeit, more up-to-date; beware of breaking package changes!) RStudio CRAN mirror. -Then, build the image as usual.

- -
-
-
-

24.8 Migrating PEcAn from VM to Docker

-

This document assumes you have read through the Introduction to Docker as well as Docker quickstart and have docker running on the VM.

-

This document will slowly replace each of the components with the appropriate docker images. At then end of this document you should be able to use the docker-compose command to bring up the full docker stack as if you had started with this origianally.

-
-

24.8.1 Running BETY as a docker container

-

This will replace the BETY application running on the machine with a docker image. This will assume you still have the database running on the local machine and the only thing we replace is the BETY application.

-

If you are running systemd (Ubuntu 16.04 or Centos 7) you can copy the following file to /etc/systemd/system/bety.service (replace LOCAL_SERVER=99 with your actual server). If you have postgres running on another server replace 127.0.0.1 with the actual ip address of the postgres server.

-
[Unit]
-Description=BETY container
-After=docker.service
-
-[Service]
-Restart=always
-ExecStart=/usr/bin/docker run -t --rm --name bety --add-host=postgres:127.0.0.1 --network=host --env RAILS_RELATIVE_URL_ROOT=/bety --env LOCAL_SERVER=99 pecan/bety
-ExecStop=/usr/bin/docker stop -t 2 bety
-
-[Install]
-WantedBy=local.target
-

At this point we can enable the bety service (this only needs to be done once). First we need to tell systemd a new service is available using systemctl daemon-reload. Next we enable the BETY service so it will restart automatically when the machine reboots, using systemctl enable bety. Finally we can start the BETY service using systemctl start bety. At this point BETY is running as a docker container on port 8000. You can see the log messages using journalctl -u bety.

-

Next we need to modify apache configuration files. The file /etc/apache2/conf-enabled/bety.conf will be replaced with the following content:

-
ProxyPass                /bety/ http://localhost:8000/bety/
-ProxyPassReverse         /bety/ http://localhost:8000/bety/
-RedirectMatch permanent ^/bety$ /bety/
-

Once this modified we can restart apache using systemctl restart apache2. At this point BETY is running in a container and is accessable trough the webserver at http://server/bety/.

-

To upgrade to a new version of BETY you can now use the docker commands. You can use the following commands to stop BETY, pull the latest image down, migrate the database (you made a backup correct?) and start BETY again.

-
systemctl stop bety
-docker pull pecan/bety:latest
-docker run -ti --rm --add-host=postgres:127.0.0.1 --network=host --env LOCAL_SERVER=99 pecan/bety migrate
-systemctl start bety
-

Once you are satisfied with the migration of BETY you can remove the bety folder as well as any ruby binaries you have installed.

- -
-
-
-

24.9 The PEcAn Docker API

-

If you have a running instance of Dockerized PEcAn (or other setup where PEcAn workflows are submitted via RabbitMQ), -you have the option of running and managing PEcAn workflows using the pecanapi package.

-

For more details, see the pecanapi package vignette and function-level documentation. -What follows is a lightning introduction.

-
-

24.9.0.1 Installation

-

The package can be installed directly from GitHub via devtools::install_github:

- -
-
-

24.9.0.2 Creating and submitting a workflow

-

With pecanapi, creating a workflow, submitting it to RabbitMQ, monitoring its progress, and processing its output can all be accomplished via an R script.

-

Start by loading the package (and the magrittr package, for the %>% pipe operator).

- -

Set your PEcAn database user ID, and create a database connection object, which will be used for database operations throughout the workflow.

- -

Find model and site IDs for the site and model you want to run.

- -

Insert a new workflow into the PEcAn database, and extract its ID.

- -

Pull all of this information together into a settings list object.

- -

Submit the workflow via RabbitMQ, and monitor its progress in the R process.

- -

Use THREDDS to access and analyze the output.

- - -
-
-
-

24.10 RabbitMQ

-

This section provides additional details about how PEcAn uses RabbitMQ to manage communication between its Docker containers.

-

In PEcAn, we use the Python pika client to post and retrieve messages from RabbitMQ. -As such, every Docker container that communicates with RabbitMQ contains two Python scripts: sender.py and reciever.py. -Both are located in the docker directory in the PEcAn source code root.

-
-

24.10.1 Producer – sender.py

-

The sender.py script is in charge of posting messages to RabbitMQ. -In the RabbitMQ documentation, it is known as a “producer”. -It runs once for every message posted to RabbitMQ, and then immediately exits (unlike the receiver.py, which runs continuously – see below).

-

Its usage is as follows:

- -

The arguments are:

-
    -
  • <URI> – The unique identifier of the RabbitMQ instance, similar to a URL. -The format is amqp://username:password@host/vhost. -By default, this is amqp://guest:guest@rabbitmq/%2F (the %2F here is the hexadecimal encoding for the / character).

  • -
  • <queue> – The name of the queue on which to post the message.

  • -
  • <message> – The contents of the message to post, in JSON format. -A typical message posted by PEcAn looks like the following:

    -
  • -
-

The PEcAn.remote::start_rabbitmq function is a wrapper for this script that provides an easy way to post a folder message to RabbitMQ from R.

-
-
-

24.10.2 Consumer – receiver.py

-

Unlike sender.py, receiver.py runs like a daemon, constantly listening for messages. -In the RabbitMQ documentation, it is known as a “consumer”. -In PEcAn, you can tell that it is ready to receive messages if the corresponding logs (e.g. docker-compose logs executor) show the following message:

-
[*] Waiting for messages. To exit press CTRL+C.
-

Our reciever is configured by three environment variables:

-
    -
  • RABBITMQ_URI – This defines the URI where RabbitMQ is running. -See corresponding argument in the producer

  • -
  • RABBITMQ_QUEUE – This is the name of the queue on which the consumer will listen for messages, just as in the producer.

  • -
  • APPLICATION – This specifies the name (including the path) of the default executable to run when receiving a message. -At the moment, it should be an executable that runs in the directory specified by the message’s folder variable. -In the case of PEcAn models, this is usually ./job.sh, such that the folder corresponds to the run directory associated with a particular runID (i.e. where the job.sh is located). -For the PEcAn workflow itself, this is set to R CMD BATCH workflow.R, such that the folder is the root directory of the workflow (in the executor Docker container, something like /data/workflows/PEcAn_<workflowID>). -This default executable is overridden if the message contains a custom_application key. -If included, the string specified by the custom_application key will be run as a command exactly as is on the container, from the directory specified by folder. -For instance, in the example below, the container will print “Hello there!” instead of running its default application.

    - -

    NOTE that in RabbitMQ messages, the folder key is always required.

  • -
-
-
-

24.10.3 RabbitMQ and the PEcAn web interface

-

RabbitMQ is configured by the following variables in config.php:

-
    -
  • $rabbitmq_host – The RabbitMQ server hostname (default: rabbitmq, because that is the name of the rabbitmq service in docker-compose.yml)
  • -
  • $rabbitmq_port – The port on which RabbitMQ listens for messages (default: 5672)
  • -
  • $rabbitmq_vhost – The path of the RabbitMQ Virtual Host (default: /).
  • -
  • $rabbitmq_queue – The name of the RabbitMQ queue associated with the PEcAn workflow (default: pecan)
  • -
  • $rabbitmq_username – The RabbitMQ username (default: guest)
  • -
  • $rabbitmq_password – The RabbitMQ password (default: guest)
  • -
-

In addition, for running models via RabbitMQ, you will also need to add an entry like the following to the config.php $hostlist:

- -

This will set the hostname to the name of the current machine (defined by the $fqdn variable earlier in the config.php file) to an array with one entry, whose key is rabbitmq and whose value is the RabbitMQ URI (amqp://...).

-

These values are converted into the appropriate entries in the pecan.xml in web/04-runpecan.php.

-
-
-

24.10.4 RabbitMQ in the PEcAn XML

-

RabbitMQ is a special case of remote execution, so it is configured by the host node. -An example RabbitMQ configuration is as follows:

- -

Here, uri and queue have the same general meanings as described in “producer”. -Note that queue here refers to the target model. -In PEcAn, RabbitMQ model queues are named as MODELTYPE_REVISION, -so the example above refers to the SIPNET model version 136. -Another example is ED2_git, referring to the latest git version of the ED2 model.

-
-
-

24.10.5 RabbitMQ configuration in Dockerfiles

-

As described in the “consumer” section, our standard RabbitMQ receiver script is configured using three environment variables: RABBITMQ_URI, RABBITMQ_QUEUE, and APPLICATION. -Therefore, configuring a container to work with PEcAn’s RabbitMQ instance requires setting these three variables in the Dockerfile using an ENV statement.

-

For example, this excerpt from docker/base/Dockerfile.executor (for the pecan/executor image responsible for the PEcAn workflow) sets these variables as follows:

- -

Similarly, this excerpt from docker/models/Dockerfile.sipnet (which builds the SIPNET model image) is a typical example for a model image. -Note the use of ARG here to specify a default version model version of 136 while allowing this to be configurable (via --build-arg MODEL_VERSION=X) at build time:

- -

WARNING: Dockerfile environment variables set via ENV are assigned all at once; they do not evaluate successively, left to right. -Consider the following block:

- -

In this block, the expansion for setting RABBITMQ_QUEUE is not aware of the current values of MODEL_TYPE or MODEL_VERSION, and will therefore be set incorrectly to just _ (unless they have been set previously, in which case it will be aware only of their earlier values). -As such, variables depending on other variables must be set in a separate, subsequent ENV statement than the variables they depend on.

-
-
-

24.10.6 Case study: PEcAn web interface

-

The following describes in general terms what happens during a typical run of the PEcAn web interface with RabbitMQ.

-
    -
  1. The user initializes all containers with docker-compose up. -All the services that interact with RabbitMQ (executor and all models) run receiver.py in the foreground, waiting for messages to tell them what to do.

  2. -
  3. The user browses to http://localhost:8000/pecan/ and steps through the web interface. -All the pages up to the 04-runpecan.php run on the web container, and are primarily for setting up the pecan.xml file.

  4. -
  5. Once the user starts the PEcAn workflow at 04-runpecan.php, the underlying PHP code connects to RabbitMQ (based on the URI provided in config.php) and posts the following message to the pecan queue:

  6. -
- -
    -
  1. The executor service, which is listening on the pecan queue, hears this message and executes its APPLICATION (R CMD BATCH workflow.R) in the working directory specified in the message’s folder. -The executor service then performs the pre-execution steps (e.g. trait meta-analysis, conversions) itself. -Then, to actually execute the model, executor posts the following message to the target model’s queue:
  2. -
- -
    -
  1. The target model service, which is listening on its dedicated queue, hears this message and runs its APPLICATION, which is job.sh, in the directory indicated by the message. -Upon exiting (normally), the model service writes its status into a file called rabbitmq.out in the same directory.

  2. -
  3. The executor container continuously looks for the rabbitmq.out file as an indication of the model run’s status. -Once it sees this file, it reads the status and proceeds with the post-execution parts of the workflow. -(NOTE that this isn’t perfect. If the model running process exits abnormally, the rabbitmq.out file may not be created, which can cause the executor container to hang. If this happens, the solution is to restart the executor container with docker-compose restart executor).

  4. -
- -
-
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - - diff --git a/develop_test/faq.html b/develop_test/faq.html deleted file mode 100644 index 274a37bf7..000000000 --- a/develop_test/faq.html +++ /dev/null @@ -1,724 +0,0 @@ - - - - - - - 28 FAQ | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

28 FAQ

- -
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - - diff --git a/develop_test/figures/PEcAn_Components.jpeg b/develop_test/figures/PEcAn_Components.jpeg deleted file mode 100644 index 9acd5da3b..000000000 Binary files a/develop_test/figures/PEcAn_Components.jpeg and /dev/null differ diff --git a/develop_test/figures/PecanLogo.png b/develop_test/figures/PecanLogo.png deleted file mode 100644 index 1af8c7fa6..000000000 Binary files a/develop_test/figures/PecanLogo.png and /dev/null differ diff --git a/develop_test/figures/env-file.PNG b/develop_test/figures/env-file.PNG deleted file mode 100644 index f1ad8553b..000000000 Binary files a/develop_test/figures/env-file.PNG and /dev/null differ diff --git a/develop_test/figures/pic1.jpg b/develop_test/figures/pic1.jpg deleted file mode 100644 index 187131c1d..000000000 Binary files a/develop_test/figures/pic1.jpg and /dev/null differ diff --git a/develop_test/figures/pic1v2.png b/develop_test/figures/pic1v2.png deleted file mode 100644 index 05e3e35fb..000000000 Binary files a/develop_test/figures/pic1v2.png and /dev/null differ diff --git a/develop_test/figures/pic2.jpg b/develop_test/figures/pic2.jpg deleted file mode 100644 index 998018586..000000000 Binary files a/develop_test/figures/pic2.jpg and /dev/null differ diff --git a/develop_test/figures/pic3.jpg b/develop_test/figures/pic3.jpg deleted file mode 100644 index 07c501b90..000000000 Binary files a/develop_test/figures/pic3.jpg and /dev/null differ diff --git a/develop_test/index.html b/develop_test/index.html deleted file mode 100644 index 06c7ddd11..000000000 --- a/develop_test/index.html +++ /dev/null @@ -1,747 +0,0 @@ - - - - - - - The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
- -
-

Welcome

-

Ecosystem science, policy, and management informed by the best available data and models

-

-

Our Mission:

-

Develop and promote accessible tools for reproducible ecosystem modeling and forecasting

-

PEcAn Website

-

Public Chat Room

-

Github Repository

- - - - - - -
- - - -
- - -
-
-
- - -
- - - - - - - - - - - - - - - - - diff --git a/develop_test/installation-details.html b/develop_test/installation-details.html deleted file mode 100644 index 381d9efd3..000000000 --- a/develop_test/installation-details.html +++ /dev/null @@ -1,2207 +0,0 @@ - - - - - - - 23 Installation details | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

23 Installation details

-

This chapter contains details about installing and maintaining the uncontainerized version of PEcAn on a virtual machine or a server. If you are running PEcAn inside of Docker, many of the particulars will be different and you should refer to the docker chapter instead of this one.

- -
-

23.1 PEcAn Virtual Machine

-

See also other VM related documentation sections:

- -

The PEcAn virtual machine consists of all of PEcAn pre-compiled within a Linux operating system and saved in a “virtual machine” (VM). Virtual machines allow for running consistent set-ups without worrying about differences between operating systems, library dependencies, compiling the code, etc.

-
    -
  1. Install VirtualBox This is the software that runs the virtual machine. You can find the download link and instructions at http://www.virtualbox.org. NOTE: On Windows you may see a warning about Logo testing, it is okay to ignore the warning.

  2. -
  3. Download the PEcAn VM You can find the download link at http://opensource.ncsa.illinois.edu/projects/artifacts.php?key=PECAN, under the “Files” header. Click the “.ova” file to begin the download. Note that the file is ~7 GB, so this download can take several minutes to hours depending on your connection speed. Also, the VM requires >4 GB of RAM to operate correctly. Please check current usage of RAM and shutdown processes as needed.

  4. -
  5. Import the VM Once the download is complete, open VirtualBox. In the VirtualBox menus, go to “File” → “Import Appliance” and locate the downloaded “.ova” file.

  6. -
-

For Virtualbox version 5.x: In the Appliance Import Settings, make sure you select “Reinitialize the MAC address of all network cards” (picture below). This is not selected by default and can result in networking issues since multiple machines might claim to have the same network MAC Address.

-

-

For Virtualbox versions starting with 6.0, there is a slightly different interface (see figure). Select “Generate new MAC addresses for all network adapters” from the MAC Address Policy:

-

-

NOTE: If you experience network connection difficulties in the VM with this enabled, try re-importing the VM without this setting selected).

-

Finally, click “Import” to build the Virtual Machine from its image.

-
    -
  1. Launch PEcAn Double click the icon for the PEcAn VM. A terminal window will pop up showing the machine booting up which may take a minute. It is done booting when you get to the pecan login: prompt. You do not need to login as the VM behaves like a server that we will be accessing through you web browser. Feel free to minimize the VM window.
  2. -
-
    -
  • If you do want to login to the VM, the credentials are as follows: username: carya, password: illinois (after the pecan tree, [Carya illinoinensis][pecan-wikipedia]).
  • -
-
    -
  1. Open the PEcAn web interface With the VM running in the background, open any web browser on the same machine and navigate to localhost:6480/pecan/ to start the PEcAn workflow. (NOTE: The trailing backslash may be necessary depending on your browser)
  2. -
-
    -
  • To ssh into the VM, open up a terminal on your machine and execute ssh -l carya -p 6422 localhost. Username and password are the same as when you log into the machine.
  • -
- -
-
-

23.2 AWS Setup

-

***********Mirror of earlier section in installation section?*********************

-

The following are Mike’s rough notes from a first attempt to port the PEcAn VM to the AWS. This was done on a Mac

-

These notes are based on following the instructions here

-
-

23.2.1 Convert PEcAn VM

-

AWS allows upload of files as VMDK but the default PEcAn VM is in OVA format

-
    -
  1. If you haven’t done so already, download the PEcAn VM

  2. -
  3. Split the OVA file into OVF and VMDK files

  4. -
-
tar xf <ovafile>
-
-
-

23.2.2 Set up an account on AWS

-

After you have an account you need to set up a user and save your access key and secret key

-

In my case I created a user named ‘carya’

-

Note: the key that ended up working had to be made at https://console.aws.amazon.com/iam/home#security_credential, not the link above.

-
-
-

23.2.3 Install EC2 command line tools

-
wget http://s3.amazonaws.com/ec2-downloads/ec2-api-tools.zip
-
-sudo mkdir /usr/local/ec2
-
-sudo unzip ec2-api-tools.zip -d /usr/local/ec2
-

If need be, download and install JDK

-
export JAVA_HOME=$(/usr/libexec/java_home)
-
-export EC2_HOME=/usr/local/ec2/ec2-api-tools-<version>
-
-export PATH=$PATH:$EC2_HOME/bin
-

Then set your user credentials as environment variables:

-

export AWS_ACCESS_KEY=xxxxxxxxxxxxxx

-

export AWS_SECRET_KEY=xxxxxxxxxxxxxxxxxxxxxx

-

Note: you may want to add all the variables set in the above EXPORT commands above into your .bashrc or equivalent.

-
-
-

23.2.4 Create an AWS S3 ‘bucket’ to upload VM to

-

Go to https://console.aws.amazon.com/s3 and click “Create Bucket”

-

In my case I named the bucket ‘pecan’

-
-
-

23.2.5 Upload

-

In the code below, make sure to change the PEcAn version, the name of the bucket, and the name of the region. Make sure that the PEcAn version matches the one you downloaded.

-

Also, you may want to choose a considerably larger instance type. The one chosen below is that corresponding to the AWS Free Tier

-
ec2-import-instance PEcAn_1.2.6-disk1.vmdk --instance-type t2.micro --format VMDK --architecture x86_64 --platform Linux --bucket pecan --region us-east-1 --owner-akid $AWS_ACCESS_KEY --owner-sak $AWS_SECRET_KEY
-

Make sure to note the ID of the image since you’ll need it to check the VM status. Once the image is uploaded it will take a while (typically about an hour) for Amazon to convert the image to one it can run. You can check on this progress by running

-
ec2-describe-conversion-tasks <image.ID>
-
-
-

23.2.6 Configuring the VM

-

On the EC2 management webpage, https://console.aws.amazon.com/ec2, if you select Instances on the left hand side (LHS) you should be able to see your new PEcAn image as an option under Launch Instance.

-

Before launching, you will want to update the firewall to open up additional ports that PEcAn needs – specifically port 80 for the webpage. Port 22 (ssh/sftp) should be open by default. Under “Security Groups” select “Inbound” then “Edit” and then add “HTTP”.

-

Select “Elastic IPs” on the LHS, and “Allocate New Address” in order to create a public IP for your VM.

-

Next, select “Network Interfaces” on the LHS and then under Actions select “Associate Addresses” then choose the Elastic IP you just created.

-

See also http://docs.aws.amazon.com/AmazonVPC/latest/GettingStartedGuide/GetStarted.html

-
-
-

23.2.7 Set up multiple instances (optional)

-

For info on setting up multiple instances with load balancing see: http://docs.aws.amazon.com/ElasticLoadBalancing/latest/DeveloperGuide/gs-ec2VPC.html

-

Select “Load Balancers” on the LHS, click on “Create Load Balancer”, follow Wizard keeping defaults.

-

To be able to launch multiple VMs: Under “Instances” convert VM to an Image. When done, select Launch, enable multiple instances, and associate with the previous security group. Once running, go back to “Load Balancers” and add the instances to the load balancer. Each instance can be accessed individually by it’s own public IP, but external users should access the system more generally via the Load Balancers DNS.

-
-
-

23.2.8 Booting the VM

-

Return to “Instances” using the menu on the LHS.

-

To boot the VM select “Actions” then “Instance State” then “Start”. In the future, once you have the VM loaded and configured this last step is the only one you will need to repeat to turn your VM on and off.

-

The menu provided should specify the Public IP where the VM has launched

- -
-
-
-

23.3 Shiny Setup

-

Installing and configuring Shiny for PEcAn -authors - Alexey Shiklomanov -- Rob Kooper

-

NOTE: Instructions are only tested for CentOS 6.5 and Ubuntu 16.04 -NOTE: Pretty much every step here requires root access.

-
-

23.3.1 Install the Shiny R package and Shiny server

-

Follow the instructions on the Shiny download page for the operating system you are using.

-
-
-

23.3.2 Modify the shiny configuration file

-

The Shiny configuration file is located in /etc/shiny-server/shiny-server.conf. Comment out the entire file and add the following, replacing <username> with your user name and <location> with the URL location you want for your app. This will allow you to run Shiny apps from your web browser at https://your.server.edu/shiny/your-location

-
run as shiny;
-server {
-    listen 3838;
-    location /<location>/ {
-        run as <username>;
-        site_dir /path/to/your/shiny/app;
-        log_dir /var/log/shiny-server;
-        directory_index on;
-    }
-}
-

For example, my configuration on the old test-pecan looks like this.

-
run as shiny;
-server {
-    listen 3838;
-    location /ashiklom/ {
-        run as ashiklom;
-        site_dir /home/ashiklom/fs-data/pecan/shiny/;
-        log_dir /var/log/shiny-server;
-        directory_index on;
-    }
-}
-

…and I can access my Shiny apps at, for instance, https://test-pecan.bu.edu/shiny/ashiklom/workflowPlots.

-

You can add as many location <loc> { ... } fields as you would like.

-
run as shiny;
-server {
-    listen 3838;
-    location /ashiklom/ {
-        ...
-    }
-    location /bety/ {
-        ...
-    }
-}
-

If you change the configuration, for example to add a new location, you will need to restart Shiny server. -If you are setting up a new instance of Shiny, skip this step and continue with the guide, since there are a few more steps to get Shiny working. -If there is an instance of Shiny already running, you can restart it with:

-
## On CentOS
-sudo service shiny-server stop
-sudo service shiny-server start
-
-## On Ubuntu
-sudo systemctl stop shiny-server.service
-sudo systemctl start shiny-server.service
-
-
-

23.3.3 Set the Apache proxy

-

Create a file with the following name, based on the version of the operating system you are using:

-
    -
  • Ubuntu 16.04 (pecan1, pecan2, test-pecan) – /etc/apache2/conf-available/shiny.conf
  • -
  • CentOS 6.5 (psql-pecan) – /etc/httpd/conf.d/shiny.conf
  • -
-

Into this file, add the following:

-
ProxyPass           /shiny/ http://localhost:3838/
-ProxyPassReverse    /shiny/ http://localhost:3838/
-RedirectMatch permanent ^/shiny$ /shiny/
-
-

23.3.3.1 Ubuntu only: Enable the new shiny configuration

-
sudo a2enconf shiny
-

This will create a symbolic link to the newly created shiny.conf file inside the /etc/apache2/conf-enabled directory. -You can do ls -l /etc/apache2/conf-enabled to confirm that this worked.

-
-
-
-

23.3.4 Enable and start the shiny server, and restart apache

-
-

23.3.4.1 On CentOS

-
sudo ln -s /opt/shiny-server/config/init.d/redhat/shiny-server /etc/init.d
-sudo service shiny-server stop
-sudo service shiny-server start
-sudo service httpd restart
-

You can check that Shiny is running with service shiny-server status.

-
-
-

23.3.4.2 On Ubuntu

-

Enable the Shiny server service. -This will make sure Shiny runs automatically on startup.

-
sudo systemctl enable shiny-server.service
-

Restart Apache.

-
sudo apachectl restart
-

Start the Shiny server.

-
sudo systemctl start shiny-server.service
-

If there are problems, you can stop the shiny-server.service with…

-
sudo systemctl stop shiny-server.service
-

…and then use start again to restart it.

-
-
-
-

23.3.5 Troubleshooting

-

Refer to the log files for shiny (/var/log/shiny-server.log) and httpd (on CentOS, /var/log/httpd/error-log; on Ubuntu, /var/log/apache2/error-log).

-
-
-

23.3.6 Further reading

- - -
-
-
-

23.4 Thredds Setup

-

Installing and configuring Thredds for PEcAn -authors - Rob Kooper

-

NOTE: Instructions are only tested for Ubuntu 16.04 on the VM, if you have instructions for CENTOS/RedHat please update this documentation -NOTE: Pretty much every step here requires root access.

-
-

23.4.1 Install the Tomcat 8 and Thredds webapp

-

The Tomcat 8 server can be installed from the default Ubuntu repositories. The thredds webapp will be downloaded and installed from unidata.

-

First step is to install Tomcat 8 and configure it. The flag -Dtds.content.root.path should point to the location of where the thredds folder is located. This needs to be writeable by the user for tomcat. -Djava.security.egd is a special flag to use a different random number generator for tomcat. The default would take to long to generate a random number.

-
apt-get -y install tomcat8 openjdk-8-jdk
-echo JAVA_OPTS=\"-Dtds.content.root.path=/home/carya \${JAVA_OPTS}\" >> /etc/default/tomcat8
-echo JAVA_OPTS=\"-Djava.security.egd=file:/dev/./urandom \${JAVA_OPTS}\" >> /etc/default/tomcat8
-service tomcat8 restart
-

Next is to install the webapp.

-
mkdir /home/carya/thredds
-chmod 777 /home/carya/thredds
-
-wget -O /var/lib/tomcat8/webapps/thredds.war ftp://ftp.unidata.ucar.edu/pub/thredds/4.6/current/thredds.war
-

Finally we configure Apache to prox the thredds server

-
cat > /etc/apache2/conf-available/thredds.conf << EOF
-ProxyPass        /thredds/ http://localhost:8080/thredds/
-ProxyPassReverse /thredds/ http://localhost:8080/thredds/
-RedirectMatch permanent ^/thredds$ /thredds/
-EOF
-a2enmod proxy_http
-a2enconf thredds
-service apache2 reload
-
-

23.4.1.1 Customize the Thredds server

-

To customize the thredds server for your installation edit the file in /home/carya/thredds/threddsConfig.xml. For example the following file is included in the VM.

-
<?xml version="1.0" encoding="UTF-8"?>
-<threddsConfig>
-
-  <!-- all options are commented out in standard install - meaning use default values -->
-  <!-- see http://www.unidata.ucar.edu/software/thredds/current/tds/reference/ThreddsConfigXMLFile.html -->
-  <serverInformation>
-    <name>PEcAn</name>
-    <logoUrl>/pecan/images/pecan_small.jpg</logoUrl>
-    <logoAltText>PEcAn</logoAltText>
-
-    <abstract>Scientific Data</abstract>
-    <keywords>meteorology, atmosphere, climate, ocean, earth science</keywords>
-    
-    <contact>
-      <name>Rob Kooper</name>
-      <organization>NCSA</organization>
-      <email>kooper@illinois.edu</email>
-      <!--phone></phone-->
-    </contact>
-    <hostInstitution>
-      <name>PEcAn</name>
-      <webSite>http://www.pecanproject.org/</webSite>
-      <logoUrl>/pecan/images/pecan_small.jpg</logoUrl>
-      <logoAltText>PEcAn Project</logoAltText>
-    </hostInstitution>
-  </serverInformation>
-
-  <!--
-  The <catalogRoot> element:
-  For catalogs you don't want visible from the /thredds/catalog.xml chain
-  of catalogs, you can use catalogRoot elements. Each catalog root config
-  catalog is crawled and used in configuring the TDS.
-
-  <catalogRoot>myExtraCatalog.xml</catalogRoot>
-  <catalogRoot>myOtherExtraCatalog.xml</catalogRoot>
-  -->
-
-  <!--
-   * Setup for generated HTML pages.
-   *
-   * NOTE: URLs may be absolute or relative, relative URLs must be relative
-   * to the webapp URL, i.e., http://server:port/thredds/.
-    -->
-  <htmlSetup>
-    <!--
-     * CSS documents used in generated HTML pages.
-     * The CSS document given in the "catalogCssUrl" element is used for all pages
-     * that are HTML catalog views. The CSS document given in the "standardCssUrl"
-     * element is used in all other generated HTML pages.
-     * -->
-    <standardCssUrl>tds.css</standardCssUrl>
-    <catalogCssUrl>tdsCat.css</catalogCssUrl>
-    <openDapCssUrl>tdsDap.css</openDapCssUrl>
-
-    <!--
-     * The Google Analytics Tracking code you would like to use for the
-     * webpages associated with THREDDS. This will not track WMS or DAP
-     * requests for data, only browsing the catalog.
-    -->
-    <googleTrackingCode></googleTrackingCode>
-
-  </htmlSetup>
-  
-  <!-- 
-    The <TdsUpdateConfig> element controls if and how the TDS checks
-    for updates. The default is for the TDS to check for the current
-    stable and development release versions, and to log that information
-    in the TDS serverStartup.log file as INFO entries.
-
-  <TdsUpdateConfig>
-     <logVersionInfo>true</logVersionInfo>
-  </TdsUpdateConfig>
-  -->
-   
-  <!--
-   The <CORS> element controls Cross-Origin Resource Sharing (CORS).
-   CORS is a way to allow a website (such as THREDDS) to open up access
-   to resources to web pages and applications running on a different domain.
-   One example would be allowing a web-application to use fonts from
-   a separate host. For TDS, this can allow a javascript app running on a
-   different site to access data on a THREDDS server.
-   For more information see: https://en.wikipedia.org/wiki/Cross-origin_resource_sharing
-   The elements below represent defaults. Only the <enabled> tag is required
-   to enable CORS. The default allowed origin is '*', which allows sharing
-   to any domain.
-  <CORS>
-    <enabled>false</enabled>
-    <maxAge>1728000</maxAge>
-    <allowedMethods>GET</allowedMethods>
-    <allowedHeaders>Authorization</allowedHeaders>
-    <allowedOrigin>*</allowedOrigin>
-  </CORS>
-  -->
-
-  <!--
-   The <CatalogServices> element:
-   - Services on local TDS served catalogs are always on.
-   - Services on remote catalogs are set with the allowRemote element
-   below. They are off by default (recommended).
-   -->
-  <CatalogServices>
-    <allowRemote>false</allowRemote>
-  </CatalogServices>
-
-  <!--
-  Configuring the CDM (netcdf-java library)
-  see http://www.unidata.ucar.edu/software/netcdf-java/reference/RuntimeLoading.html
-
-  <nj22Config>
-    <ioServiceProvider class="edu.univ.ny.stuff.FooFiles"/>
-    <coordSysBuilder convention="foo" class="test.Foo"/>
-    <coordTransBuilder name="atmos_ln_sigma_coordinates" type="vertical" class="my.stuff.atmosSigmaLog"/>
-    <typedDatasetFactory datatype="Point" class="gov.noaa.obscure.file.Flabulate"/>
-  </nj22Config>
-  -->
-
-  <!--
-  CDM uses the DiskCache directory to store temporary files, like uncompressed files.
-  <DiskCache>
-    <alwaysUse>false</alwaysUse>
-    <scour>1 hour</scour>
-    <maxSize>1 Gb</maxSize>
-  </DiskCache>
-  -->
-
-  <!--
-  Caching open NetcdfFile objects.
-  default is to allow 50 - 100 open files, cleanup every 11 minutes
-  <NetcdfFileCache>
-    <minFiles>50</minFiles>
-    <maxFiles>100</maxFiles>
-    <scour>11 min</scour>
-  </NetcdfFileCache>
-  -->
-
-  <!--
-  The <HTTPFileCache> element:
-  allow 10 - 20 open datasets, cleanup every 17 minutes
-  used by HTTP Range requests.
-  <HTTPFileCache>
-    <minFiles>10</minFiles>
-    <maxFiles>20</maxFiles>
-    <scour>17 min</scour>
-  </HTTPFileCache>
-  -->
-
-  <!--
-  Writing GRIB indexes.
-  <GribIndexing>
-    <setExtendIndex>false</setExtendIndex>
-    <alwaysUseCache>false</alwaysUseCache>
-  </GribIndexing>
-  -->
-
-  <!--
-  Persist joinNew aggregations to named directory. scour every 24 hours, delete stuff older than 90 days
-  <AggregationCache>
-    <scour>24 hours</scour>
-    <maxAge>90 days</maxAge>
-    <cachePathPolicy>NestedDirectory</cachePathPolicy>
-  </AggregationCache>
-  -->
-
-  <!--
-  How to choose the template dataset for an aggregation. latest, random, or penultimate
-  <Aggregation>
-    <typicalDataset>penultimate</typicalDataset>
-  </Aggregation>
-  -->
-
-  <!--
-  The Netcdf Subset Service is off by default.
-  <NetcdfSubsetService>
-    <allow>false</allow>
-    <scour>10 min</scour>
-    <maxAge>-1 min</maxAge>
-  </NetcdfSubsetService>
-  -->
-
-  <!--
-  <Opendap>
-    <ascLimit>50</ascLimit>
-    <binLimit>500</binLimit>
-    <serverVersion>opendap/3.7</serverVersion>
-  </Opendap>
-    -->
-  
-  <!--
-  The WCS Service is off by default.
-  Also, off by default (and encouraged) is operating on a remote dataset.
-  <WCS>
-    <allow>false</allow>
-    <allowRemote>false</allowRemote>
-    <scour>15 min</scour>
-    <maxAge>30 min</maxAge>
-  </WCS>
-  -->
-
-  <!--
-  <WMS>
-    <allow>false</allow>
-    <allowRemote>false</allowRemote>
-    <maxImageWidth>2048</maxImageWidth>
-    <maxImageHeight>2048</maxImageHeight>
-  </WMS>
-  -->
-
-  <!--
-  <NCISO>
-    <ncmlAllow>false</ncmlAllow>
-    <uddcAllow>false</uddcAllow>
-    <isoAllow>false</isoAllow>
-  </NCISO>
-  -->
-
-  <!-- CatalogGen service is off by default.
-  <CatalogGen>
-    <allow>false</allow>
-  </CatalogGen>
-   -->
-
-  <!-- DLwriter service is off by default.
-       As is support for operating on remote catalogs.
-  <DLwriter>
-    <allow>false</allow>
-    <allowRemote>false</allowRemote>
-  </DLwriter>
-   -->
-
-  <!-- DqcService is off by default.
-  <DqcService>
-    <allow>false</allow>
-  </DqcService>
-   -->
-
-  <!--
-   Link to a Viewer application on the HTML page:
-   <Viewer>my.package.MyViewer</Viewer>
-   -->
-
-   <!--
-   Add a DataSource - essentially an IOSP with access to Servlet request parameters
-   <datasetSource>my.package.DatsetSourceImpl</datasetSource>
-   -->
-
-  <!--
-   set FeatureCollection logging
-  <FeatureCollection>
-     <RollingFileAppender>
-       <MaxFileSize>1 MB</MaxFileSize>
-       <MaxBackups>5</MaxBackups>
-       <Level>INFO</Level>
-     </RollingFileAppender>
-  </FeatureCollection>
-  -->
-
-  <!--
-    Configure how the NetCDF-4 C library is discovered and used.
-    libraryPath: The directory in which the native library is installed.
-    libraryName: The name of the native library. This will be used to locate the proper .DLL, .SO, or .DYLIB file
-      within the libraryPath directory.
-    useForReading: By default, the native library is only used for writing NetCDF-4 files; a pure-Java layer is
-      responsible for reading them. However, if this property is set to true, then it will be used for reading
-      NetCDF-4 (and HDF5) files as well.
-  -->
-  <!--
-  <Netcdf4Clibrary>
-    <libraryPath>/usr/local/lib</libraryPath>
-    <libraryName>netcdf</libraryName>
-    <useForReading>false</useForReading>
-  </Netcdf4Clibrary>
-  -->
-</threddsConfig>
-
-
-
-

23.4.2 Update the catalog

-

For example to update the catalog with the latest data, run the following command from the root crontab. This cronjob will also synchronize the database with remote servers and dump your database (by default in /home/carya/dump)

-
0 * * * * /home/carya/pecan/scripts/cron.sh -o /home/carya/dump
-
-
-

23.4.3 Troubleshooting

-

Refer to the log files for Tomcat (/var/log/tomcat8/*) and Thredds (/home/carya/thredds/logs).

-
-
-

23.4.4 Further reading

- - -
-
-
-

23.5 OS Specific Installations

- - -
-

23.5.1 Ubuntu

-

These are specific notes for installing PEcAn on Ubuntu (14.04) and will be referenced from the main installing PEcAn page. You will at least need to install the build environment and Postgres sections. If you want to access the database/PEcAn using a web browser you will need to install Apache. To access the database using the BETY interface, you will need to have Ruby installed.

-

This document also contains information on how to install the Rstudio server edition as well as any other packages that can be helpful.

- - - - - -
-

23.5.1.6 Additional packages

-

HDF5 Tools, netcdf, GDB and emacs

- - -
-
-
-

23.5.2 CentOS/RedHat

-

These are specific notes for installing PEcAn on CentOS (7) and will be referenced from the main installing PEcAn page. You will at least need to install the build environment and Postgres sections. If you want to access the database/PEcAn using a web browser you will need to install Apache. To access the database using the BETY interface, you will need to have Ruby installed.

-

This document also contains information on how to install the Rstudio server edition as well as any other packages that can be helpful.

- - - - -
-

23.5.2.5 Rstudio-server

-

NEED FIXING

-

NOTE This will allow anybody to login to the machine through the rstudio interface and run any arbitrary code. The login used however is the same as the system login/password.

- - -

Alternative Rstudio instructions

-
-
23.5.2.5.1 Install and configure Rstudio-server
-

Install RStudio Server by following the official documentation for your platform. -Then, proceed with the following:

-
    -
  • add PATH=$PATH:/usr/sbin:/sbin to /etc/profile
  • -
- - - -
    -
  • restart the Apache server: sudo httpd restart
  • -
  • now you should be able to access http://<server>/rstudio
  • -
-
-
- -
-

23.5.2.7 Additional packages

-

NEED FIXING

-

HDF5 Tools, netcdf, GDB and emacs

- - -
-
-
-

23.5.3 Mac OSX

-

These are specific notes for installing PEcAn on Mac OSX and will be referenced from the main installing PEcAn page. You will at least need to install the build environment and Postgres sections. If you want to access the database/PEcAn using a web browser you will need to install Apache. To access the database using the BETY interface, you will need to have Ruby installed.

-

This document also contains information on how to install the Rstudio server edition as well as any other packages that can be helpful.

- -
-

23.5.3.2 Install Postgres

-

For those on a Mac I use the following app for postgresql which has -postgis already installed (http://postgresapp.com/)

-

To get postgis run the following commands in psql:

- -

To check your postgis run the following command again in psql: SELECT PostGIS_full_version();

-
-
-

23.5.3.3 Additional installs

- - -
-
-

23.5.3.4 Apache Configuration

-

Mac does not support pdo/postgresql by default. The easiest way to install is use: http://php-osx.liip.ch/

-

To enable pecan to run from your webserver.

- -
-
-

23.5.3.5 Ruby

-

The default version of ruby should work. Or use JewelryBox.

-
-
-

23.5.3.6 Rstudio Server

-

For the mac you can download Rstudio Desktop.

- -
-
-
-

23.5.4 Installing BETY

-

**************THIS PAGE IS DEPRECATED*************

-

Official Instructions for BETY are maintained here: https://pecan.gitbook.io/betydb-documentation

-

If you would like to install the Docker Version of BETY, please consult the PEcAn Docker section.

- - -
-
-

23.5.5 Install Models

-

This page contains instructions on how to download and install ecosystem models that have been or are being coupled to PEcAn. -These instructions have been tested on the PEcAn unbuntu VM. Commands may vary on other operating systems. -Also, some model downloads require permissions before downloading, making them unavailable to the general public. Please contact the PEcAn team if you would like access to a model that is not already installed on the default PEcAn VM.

- - - -
-

23.5.5.2 CLM 4.5

-

The version of CLM installed on PEcAn is the ORNL branch provided by Dan Ricciuto. This version includes Dan’s point-level CLM processing scripts

-

Download the code (~300M compressed), input data (1.7GB compressed and expands to 14 GB), and a few misc inputs.

- -

Required libraries

- -

Compile and build default inputs

- -
-
23.5.5.2.1 CLM Test Run
-

You will see a new directory in scripts: US-UMB_I1850CLM45CN -Enter this directory and run (you shouldn’t have to do this normally, but there is a bug with the python script and doing this ensures all files get to the right place):

- -

Next you are ready to go to the run directory:

- -

Open to edit file: datm.streams.txt.CLM1PT.CLM_USRDAT and check file paths such that all paths start with /home/carya/models/ccsm_inputdata

-

From this directory, launch the executable that resides in the bld directory:

- -

not sure this was the right location, but wherever the executable is

-

You should begin to see output files that look like this: -US-UMB_I1850CLM45CN.clm2.h0.yyyy-mm.nc (yyyy is year, mm is month) -These are netcdf files containing monthly averages of lots of variables.

-

The lnd_in file in the run directory can be modified to change the output file frequency and variables.

- -
-
- -
-

23.5.5.4 ED2

- - - -
-
-

23.5.5.5 CLM-FATES

-

Prerequisites

-
sudo apt-get upgrade libnetcdf-dev
-sudo apt-get install subversion
-sudo apt-get install csh
-sudo apt-get install cmake
-sudo ln -s /usr/bin/make /usr/bin/gmake
-sudo rm /bin/sh
-sudo ln -s /bin/bash /bin/sh
-
-wget https://github.com/Unidata/netcdf-fortran/archive/v4.4.4.tar.gz
-cd netcdf-4.4.4
-./configure
-make
-sudo make install
-

you might need to mess around with installing netcdf and netcdf-fortran to get a version FATES likes…

-

Get code from Github (currently private) and go to cime/scripts directory

-
git clone git@github.com:NGEET/ed-clm.git
-cd ed-clm/cime/scripts/
-

Within CLM-FATES, to be able to build an executable we need to create a reference run. We’ll also use this reference run to grab defaults from, so we’ll be registering the location of both the reference case (location of executable, scripts, etc) and the reference inputs with the PEcAn database. To begin, copy reference run script from pecan

-
cp ~/pecan/models/fates/inst/create_1x1_ref_case.sh .
-

Edit reference case script to set NETCDF_HOME, CROOT (reference run case), DIN_LOC_ROOT (reference run inputs). Also, make sure DIN_LOC_ROOT exists as FATES will not create it itself. Then run the script

-
./create_1x1_ref_case.sh
-

Be aware that this script WILL ask you for your password on the NCAR server to download the reference case input data (the guest password may work, haven’t tried this). If it gives an error at the pio stage check the log, but the most likely error is it being unable to find a version of netcdf it likes.

-

Once FATES is installed, set the whole reference case directory as the Model path (leave filename blank) and set the whole inputs directory as an Input with format clm_defaults.

- -
-
-

23.5.5.6 GDAY

-

Navigate to a directory you would like to store GDAY and run the following:

- -

gday is your executable.

- -
- - -
-

23.5.5.9 LPJ-GUESS

-

Instructions to download source code

-

Go to LPJ-GUESS website for instructions to access code.

- -
-
-

23.5.5.10 MAESPA

-

Navigate to a directory you would like store MAESPA and run the following:

- -

maespa.out is your executable. Example input files can be found in the inpufiles directory. Executing measpa.out from within one of the example directories will produce output.

-

MAESPA developers have also developed a wrapper package called Maeswrap. The usual R package installation method install.packages may present issues with downloading an unpacking a dependency package called rgl. Here are a couple of solutions:

- - -
- -
-
-

23.5.6 Installing data for PEcAn

-

PEcAn assumes some of the data to be installed on the machine. This page will describe how to install this data.

- - -
-

23.5.6.3 Flux Camp

-

Following will install the data for flux camp (as well as the demo script for PEcAn).

- -
- -
-
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - - diff --git a/develop_test/intermediate-user.html b/develop_test/intermediate-user.html deleted file mode 100644 index f935b54cc..000000000 --- a/develop_test/intermediate-user.html +++ /dev/null @@ -1,1538 +0,0 @@ - - - - - - - 7 More on the PEcAn Web Interface | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

7 More on the PEcAn Web Interface

-

This section will provide information to those wanting to take advantage of PEcAn’s customizations from the web interface.

- - -
-

7.1 Additional web configuration

-

Additional settings for web configuration:

-
    -
  • Web interface setup
  • -
  • Brown Dog
  • -
  • Advanced setup -
      -
    • [Sensitivity analysis] (TODO)
    • -
    • [Uncertainty analysis] (TODO)
    • -
  • -
  • Editing model configuration files
  • -
-
-

7.1.1 Web interface setup

-

There are few options which you can change via web interface.

-

To visit the configuration page either you can just click on the setups link on the introduction page alternatively can type <host>/setups/.

-

The list of configuration available

-
    -
  1. Database configuration : BETYdb(Biofuel Ecophysiological Traits and Yields database) configuration details, can be edited according to need.

  2. -
  3. Browndog configuration : Browndog configuration details, Used to connect browndog. Its included by default in VM.

  4. -
  5. FIA Database : FIA(Forest Inventory and Analysis) Database configuration details, Can be used to add additional data to models.

  6. -
  7. Google MapKey : Google Map key, used to access the google map by PEcAn.

  8. -
  9. Change Password : A small infomation to change the VM user password. (if using Docker image it won’t work)

  10. -
  11. Automatic Sync : If ON then it will sync the database between local machine and the remote servers. Still unders testing part might be buggy.

  12. -
-

Still work on the adding other editing feature going on, this page will be updated as new configuration will be available.

-
-
-

7.1.2 Brown Dog

-

The Browndog service provides PEcAn with access to large and diverse sets of data at the click of a button in the format that PEcAn needs. By clicking the checkbox you will be using the Browndog Service to process data.

-

For more information regarding meteorological data check out Available Meteorological Drivers

-

More information can be found at the Browndog website.

-
-
-

7.1.3 Advanced Setup

-

(TODO: Under construction…)

-
-
-

7.1.4 Editing model configurations

-

(TODO: Under construction…)

- -
-
-
-

7.2 Settings-configured analyses

-

These analyses can be run through the web interface, but lack graphical interfaces and currently can only be configured throughthe XML settings. To run these analyses use the Edit pecan.xml checkbox on the Input configuration page. Eventually, these modules will be integrated into the web user interface.

- -

(TODO: Add links)

-
-

7.2.1 Parameter data assimilation (PDA)

-

All functions pertaining to Parameter Data Assimilation are housed within: pecan/modules/assim.batch.

-

For a detailed usage of the module, please see the vignette under pecan/modules/assim.batch/vignettes.

-

Hierarchical version of the PDA is also implemented, for more details, see the MultiSitePDAVignette package vignette and function-level documentation.

-
-

7.2.1.1 pda.mcmc.R

-

This is the main PDA code. It performs Bayesian MCMC on model parameters by proposing parameter values, running the model, calculating a likelihood (between model output and supplied observations), and accepting or rejecting the proposed parameters (Metropolis algorithm). Additional notes:

-
    -
  • The first argument is settings, followed by others that all default to NULL.settings is a list used throughout Pecan, which contains all the user options for whatever analyses are being done. The easiest thing to do is just pass that whole object all around the Pecan code and let different functions access whichever settings they need. That’s what a lot of the rest of the Pecan code does. But the flexibility to override most of the relevant settings in settings is there by providing them directly as arguments to the function.

  • -
  • The if(FALSE)… : If you’re trying to step through the function you probably will have the settings object around, but those other variables will be undefined. If you set them all to NULL then they’ll be ignored without causing errors. It is there for debugging purposes.

  • -
  • The next step calls pda.settings(), which is in the file pda.utils.R (see below). It checks whether any settings are being overridden by arguments, and in most cases supplies default values if it can’t find either.

  • -
  • In the MCMC setup section -
      -
    • The code is set up to allow you to start a new MCMC chain, or to continue a previous chain as specified in settings.
    • -
    • The code writes a simple text file of parameter samples at every iteration, which lets you get some results and even re-start an MCMC that fails for some reason.
    • -
    • The code has adaptive jump distributions. So you can see some initialization of the jump distributions and associated variables here.
    • -
    • Finally, note that after all this setup a new XML settings file is saved. The idea is that the original pecan.xml you create is preserved for provenance, and then periodically throughout the workflow the settings (likely containing new information) are re-saved with descriptive filenames.
    • -
  • -
  • MCMC loop -
      -
    • Periodically adjust jump distribution to make acceptance rate closer to target
    • -
    • Propose new parameters one at a time. For each: -
        -
      • First, note that Pecan may be handling many more parameters than are actually being targeted by PDA. Pecan puts priors on any variables it has information for (in the BETY database), and then these get passed around throughout the analysis and every step (meta-, sensitivity, ensemble analyses, etc.). But for PDA, you specify a separate list of probably far fewer parameters to constrain with data. These are the ones that get looped over and varied here. The distinction between all parameters and only those dealt with in PDA is dealt with in the setup code above.
      • -
      • First a new value is proposed for the parameter of interest.
      • -
      • Then, a new model run is set up, identical to the previous except with the new proposed value for the one parameter being updated on this run.
      • -
      • The model run is started, and outputs collected after waiting for it to finish.
      • -
      • A new likelihood is calculated based on the model outputs and the observed dataset provided.
      • -
      • Standard Metropolis acceptance criteria is used to decide whether to keep the proposed parameter.
      • -
      • Periodically (at interval specified in settings), a diagnostic figure is saved to disk so you can check on progress.
      • -
    • -
    • This works only for NEE currently
    • -
  • -
-
-
-

7.2.1.2 pda.mcmc.bs.R

-

This file is basically identical to pda.mcm.R, but rather than propose parameters one at a time, it proposes new values for all parameters at once (“bs” stands for “block sampling”). You choose which option to use by specifying settings\(assim.batch\)method: -* “bruteforce” means sample parameters one at a time -* “bruteforce.bs” means use this version, sampling all parameters at once -* “emulator” means use the emulated-likelihood version

-
-
-

7.2.1.3 pda.emulator

-

This version of the PDA code again looks quite similar to the basic “bruteforce” one, but its mechanics are very different. The basic idea is, rather than running thousands of model iterations to explore parameter space via MCMC, run a relatively smaller number of runs that have been carefully chosen to give good coverage of parameter space. Then, basically interpolate the likelihood calculated for each of those runs (actually, fit a Gaussian process to it), to get a surface that “emulates” the true likelihood. Now, perform regular MCMC (just like the “bruteforce” approach), except instead of actually running the model on every iteration to get a likelihood, just get an approximation from the likelihood emulator. Since the latter step takes virtually no time, you can run as long of an MCMC as you need at little computational cost, once you have done the initial model runs to create the likelihood emulator.

-
-
-

7.2.1.4 pda.mcmc.recover.R

-

This function is for recovering a failed PDA MCMC run.

-
-
-

7.2.1.5 pda.utils.R

-

This file contains most of the individual functions used by the main PDA functions (pda.mcmc.*.R).

-
    -
  • assim.batch is the main function Pecan calls to do PDA. It checks which method is requested (bruteforce, bruteforce.bs, or emulator) and call the appropriate function described above.
  • -
  • pda.setting handles settings. If a setting isn’t found, the code can usually supply a reasonable default.
  • -
  • pda.load.priors is fairly self explanatory, except that it handles a lot of cases and gives different options priority over others. Basically, the priors to use for PDA parameters can come from either a Pecan prior.distns or post.distns object (the latter would be, e.g., the posteriors of a meta-analysis or previous PDA), or specified either by file path or BETY ID. If not told otherwise, the code tries to just find the most recent posterior in BETY, and use that as prior for PDA.
  • -
  • pda.create.ensemble gets an ensemble ID for the PDA. All model runs associated with an individual PDA (any of the three methods) are considered part of a single ensemble. This function does is register a new ensemble in BETY, and return the ID that BETY gives it.
  • -
  • pda.define.prior.fn creates R functions for all of the priors the PDA will use.
  • -
  • pda.init.params sets up the parameter matrix for the run, which has one row per iteration, and one column per parameter. Columns include all Pecan parameters, not just the (probably small) subset that are being updated by PDA. This is for compatibility with other Pecan components. If starting a fresh run, the returned matrix is just a big empty matrix to fill in as the PDA runs. If continuing an existing MCMC, then it will be the previous params matrix, with a bunch of blank rows added on for filling in during this round of PDA.
  • -
  • pda.init.run This is basically a big wrapper for Pecan’s write.config function (actually functions [plural], since every model in Pecan has its own version). For the bruteforce and bruteforce.bs methods this will be run once per iteration, whereas the emulator method knows about all its runs ahead of time and this will be a big batch of all runs at once.
  • -
  • pda.adjust.jumps tweaks the jump distributions for the standard MCMC method, and pda.adjust.jumps.bs does the same for the block-sampled version.
  • -
  • pda.calc.llik calculates the log-likelihood of the model given all datasets provided to compare it to.
  • -
  • pda.generate.knots is for the emulator version of PDA. It uses a Latin hypercube design to sample a specified number of locations in parameter space. These locations are where the model will actually be run, and then the GP interpolates the likelihood surface in between.
  • -
  • pda.plot.params provides basic MCMC diagnostics (trace and density) for parameters being sampled.
  • -
  • pda.postprocess prepares the posteriors of the PDA, stores them to files and the database, and performs some other cleanup functions.
  • -
  • pda.load.data.r This is the function that loads in data that will be used to constrain the PDA. It’s supposed to be eventually more integrated with Pecan, which will know how to load all kinds of data from all kinds of sources. For now, it can do NEE from Ameriflux.
  • -
  • pda.define.llik.r A simple helper function that defines likelihood functions for different datasets. Probably in the future this should be queried from the database or something. For now, it is extremely limited. The original test case of NEE assimilation uses a heteroskedastic Laplacian distribution.
  • -
  • pda.get.model.output.R Another function that will eventually grow to handle many more cases, or perhaps be replaced by a better system altogether. For now though, it again just handles Ameriflux NEE.
  • -
-
-
-

7.2.1.6 get.da.data.*.R, plot.da.R

-

Old codes written by Carl Davidson. Defunct now, but may contain good ideas so currently left in.

-
-
-
-

7.2.2 State data assimilation (SDA)

-

sda.enkf.R is housed within: /pecan/modules/assim.sequential/R

-

The tree ring tutorial is housed within: /pecan/documentation/tutorials/StateAssimilation

-

More descriptive SDA methods can be found at: /pecan/book_source/adve_user_guide_web/SDA_Methods.Rmd

-
-

7.2.2.1 sda.enkf.R Description

-

This is the main ensemble Kalman filter and generalized filter code. Originally, this was just ensemble Kalman filter code. Mike Dietze and Ann Raiho added a generalized ensemble filter to avoid filter divergence. The output of this function will be all the of run outputs, a PDF of diagnostics, and an Rdata object that includes three lists:

-
    -
  • FORECAST will be the ensemble forecasts for each year
  • -
  • ANALYSIS will be the updated ensemble sample given the NPP observations
  • -
  • enkf.params contains the prior and posterior mean vector and covariance matrix for each time step.
  • -
-
-
-

7.2.2.2 sda.enkf.R Arguments

-
    -
  • settings - (required) State Data Assimilation Tags Example settings object

  • -
  • obs.mean - (required) a list of observation means named with dates in YYYY/MM/DD format

  • -
  • obs.cov - (required) a list of observation covariances names with dates in YYYY/MM/DD format

  • -
  • IC - (optional) initial condition matrix (dimensions: ensemble memeber # by state variables). Default is NULL.

  • -
  • Q - (optional) process covariance matrix (dimensions: state variable by state variables). Defualt is NULL.

  • -
-
-
-

7.2.2.3 State Data Assimilation Workflow

-

Before running sda.enkf, these tasks must be completed (in no particular order),

-
    -
  • Read in a State Data Assimilation Tags Example settings file with tags listed below. i.e. read.settings(‘pecan.SDA.xml’)

  • -
  • Load data means (obs.mean) and covariances (obs.cov) as lists with PEcAn naming and unit conventions. Each observation must have a date in YYYY/MM/DD format (optional time) associated with it. If there are missing data, the date must still be represented in the list with an NA as the list object.

  • -
  • Create initial conditions matrix (IC) that is state variables columns by ensemble members rows in dimension. sample.IC.MODEL can be used to create the IC matrix, but it is not required. This IC matrix is fed into write.configs for the initial model runs.

  • -
-

The main parts of the SDA function are:

-

Setting up for initial runs:

-
    -
  • Set parameters

  • -
  • Load initial run inputs via split.inputs.MODEL

  • -
  • Open database connection

  • -
  • Get new workflow ids

  • -
  • Create ensemble ids

  • -
-

Performing the initial set of runs

-

Set up for data assimilation

-

Loop over time

-
    -
  • read.restart.MODEL - read model restart files corresponding to start.time and stop.time that you want to assimilate data into

  • -
  • Analysis - There are four choices based on if process variance is TRUE or FALSE and if there is data or not. See explaination below.

  • -
  • write.restart.MODEL - This function has two jobs. First, to insert adjusted state back into model restart file. Second, to update start.time, stop.time, and job.sh.

  • -
  • run model

  • -
-

Save outputs

-

Create diagnostics

-
-
-

7.2.2.4 State Data Assimilation Tags Example

-
<state.data.assimilation>
-  <adjustment>TRUE</adjustment>
-  <process.variance>FALSE</process.variance>
-  <sample.parameters>FALSE</sample.parameters>
-  <q.type>Single</q.type>
-   <state.variables>
-    <variable>
-      <variable.name>AGB.pft</variable.name>
-      <unit>MgC/ha/yr</unit>
-      <min_value>0</min_value>
-      <max_value>100000000</max_value>
-    </variable>
-    <variable>
-      <variable.name>TotSoilCarb</variable.name>
-      <unit>KgC/m^2</unit>
-      <min_value>0</min_value>
-      <max_value>100000000</max_value>
-    </variable>
-  </state.variables>
-  <spin.up>
-    <start.date>1950/01/01</start.date>
-    <end.date>1960/12/31</end.date>
-  </spin.up>
-  <forecast.time.step>1</forecast.time.step>
-  <start.date>1961/01/01</start.date>
-  <end.date>2010/12/31</end.date>
- </state.data.assimilation>
-
-
-

7.2.2.5 State Data Assimilation Tags Descriptions

-
    -
  • adjustment : [optional] TRUE/FLASE flag for if ensembles needs to be adjusted based on weights estimated given their likelihood during analysis step. The defualt is TRUE for this flag.
  • -
  • process.variance : [optional] TRUE/FLASE flag for if process variance should be estimated (TRUE) or not (FALSE). If TRUE, a generalized ensemble filter will be used. If FALSE, an ensemble Kalman filter will be used. Default is FALSE. If you use the TRUE argument you can set three more optional tags to control the MCMCs built for the generalized esnsemble filter.
  • -
  • nitrGEF : [optional] numeric defining the length of the MCMC chains.
  • -
  • nthin : [optional] numeric defining thining length for the MCMC chains.
  • -
  • nburnin : [optional] numeric defining the number of burnins during the MCMCs.
  • -
  • q.type : [optional] If the process.variance is set to TRUE then this can take values of Single, Site or PFT.
  • -
  • censored.data : [optional] logical set TRUE for censored state variables.

  • -
  • sample.parameters : [optional] TRUE/FLASE flag for if parameters should be sampled for each ensemble member or not. This allows for more spread in the initial conditions of the forecast.
  • -
  • state.variable : [required] State variable that is to be assimilated (in PEcAn standard format).
  • -
  • spin.up : [required] start.date and end.date for initial model runs.
  • -
  • NOTE: start.date and end.date are distinct from values set in the run tag because initial runs can be done over a subset of the full run.
  • -
  • forecast.time.step : [optional] In the future, this will be used to allow the forecast time step to vary from the data time step.
  • -
  • start.date : [optional] start date of the state data assimilation (in YYYY/MM/DD format)
  • -
  • end.date : [optional] end date of the state data assimilation (in YYYY/MM/DD format)
  • -
  • NOTE: start.date and end.date are distinct from values set in the run tag because this analysis can be done over a subset of the run.

  • -
-
-
-

7.2.2.6 Model Specific Functions for SDA Workflow

-
-
-

7.2.2.7 read.restart.MODEL.R

-

The purpose of read.restart is to read model restart files and return a matrix that is site rows by state variable columns. The state variables must be in PEcAn names and units. The arguments are:

-
    -
  • outdir - output directory

  • -
  • runid - ensemble member run ID

  • -
  • stop.time - used to determine which restart file to read (in POSIX format)

  • -
  • settings - pecan.SDA.xml settings object

  • -
  • var.names - vector with state variable names with PEcAn standard naming. Example: c(‘AGB.pft’, ‘TotSoilCarb’)

  • -
  • params - parameters used by ensemble member (same format as write.configs)

  • -
-
-
-

7.2.2.8 write.restart.MODEL.R

-

This model specific function takes in new state and new parameter matrices from sda.enkf.R after the analysis step and translates new variables back to the model variables. Then, updates start.time, stop.time, and job.sh so that start.model.runs() does the correct runs with the new states. In write.restart.LINKAGES and write.restart.SIPNET, job.sh is updated by using write.configs.MODEL.

-
    -
  • outdir - output directory

  • -
  • runid - run ID for ensemble member

  • -
  • start.time - beginning of model run (in POSIX format)

  • -
  • stop.time - end of model run (in POSIX format)

  • -
  • settings - pecan.SDA.xml settings object

  • -
  • new.state - matrix from analysis of updated state variables with PEcAn names (dimensions: site rows by state variables columns)

  • -
  • new.params - In the future, this will allow us to update parameters based on states (same format as write.configs)

  • -
  • inputs - model specific inputs from split.inputs.MODEL used to run the model from start.time to stop.time

  • -
  • RENAME - [optional] Flag used in write.restart.LINKAGES.R for development.

  • -
-
-
-

7.2.2.9 split.inputs.MODEL.R

-

This model specific function gives the correct met and/or other model inputs to settings\(run\)inputs. This function returns settings\(run\)inputs to an inputs argument in sda.enkf.R. But, the inputs will not need to change for all models and should return settings\(run\)inputs unchanged if that is the case.

-
    -
  • settings - pecan.SDA.xml settings object

  • -
  • start.time - start time for model run (in POSIX format)

  • -
  • stop.time - stop time for model run (in POSIX format)

  • -
-
-
-

7.2.2.10 sample.IC.MODEL.R

-

This model specific function is optional. But, it can be used to create initial condition matrix (IC) with # state variables columns by # ensemble rows. This IC matrix is used for the initial runs in sda.enkf.R in the write.configs.MODEL function.

-
    -
  • ne - number of ensemble members

  • -
  • state - matrix of state variables to get initial conditions from

  • -
  • year - used to determine which year to sample initial conditions from

  • -
-
-
-

7.2.2.11 Analysis Options

-

There are four options depending on whether process variance is TRUE/FALSE and whether or not there is data or not.

-
    -
  • If there is no data and process variance = FALSE, there is no analysis step.

  • -
  • If there is no data and process variance = TRUE, process variance is added to the forecast.

  • -
  • If there is data and process variance = TRUE, the generalized ensemble filter is implemented with MCMC.

  • -
  • If there is data and process variance = FALSE, the Kalman filter is used and solved analytically.

  • -
-
-
-

7.2.2.12 The Generalized Ensemble Filter

-

An ensemble filter is a sequential data assimilation algorithm with two procedures at every time step: a forecast followed by an analysis. The forecast ensembles arise from a model while the analysis makes an adjustment of the forecasts ensembles from the model towards the data. An ensemble Kalman filter is typically suggested for this type of analysis because of its computationally efficient analytical solution and its ability to update states based on an estimate of covariance structure. But, in some cases, the ensemble Kalman filter fails because of filter divergence. Filter divergence occurs when forecast variability is too small, which causes the analysis to favor the forecast and diverge from the data. Models often produce low forecast variability because there is little internal stochasticity. Our ensemble filter overcomes this problem in a Bayesian framework by including an estimation of model process variance. This methodology also maintains the benefits of the ensemble Kalman filter by updating the state vector based on the estimated covariance structure.

-

This process begins after the model is spun up to equilibrium.

-

The likelihood function uses the data vector \(\left(\boldsymbol{y_{t}}\right)\) conditional on the estimated state vector \(\left(\boldsymbol{x_{t}}\right)\) such that

-

\(\boldsymbol{y}_{t}\sim\mathrm{multivariate\:normal}(\boldsymbol{x}_{t},\boldsymbol{R}_{t})\)

-

where \(\boldsymbol{R}_{t}=\boldsymbol{\sigma}_{t}^{2}\boldsymbol{I}\) and \(\boldsymbol{\sigma}_{t}^{2}\) is a vector of data variances. To obtain an estimate of the state vector \(\left(\boldsymbol{x}_{t}\right)\), we use a process model that incorporates a process covariance matrix \(\left(\boldsymbol{Q}_{t}\right)\). This process covariance matrix differentiates our methods from past ensemble filters. Our process model contains the following equations

-

\(\boldsymbol{x}_{t} \sim \mathrm{multivariate\: normal}(\boldsymbol{x}_{model_{t}},\boldsymbol{Q}_{t})\)

-

\(\boldsymbol{x}_{model_{t}} \sim \mathrm{multivariate\: normal}(\boldsymbol{\mu}_{forecast_{t}},\boldsymbol{P}_{forecast_{t}})\)

-

where \(\boldsymbol{\mu}_{forecast_{t}}\) is a vector of means from the ensemble forecasts and \(\boldsymbol{P}_{forecast_{t}}\) is a covariance matrix calculated from the ensemble forecasts. The prior for our process covariance matrix is \(\boldsymbol{Q}_{t}\sim\mathrm{Wishart}(\boldsymbol{V}_{t},n_{t})\) where \(\boldsymbol{V}_{t}\) is a scale matrix and \(n_{t}\) is the degrees of freedom. The prior shape parameters are updated at each time step through moment matching such that

-

\(\boldsymbol{V}_{t+1} = n_{t}\bar{\boldsymbol{Q}}_{t}\)

-

\(n_{t+1} = \frac{\sum_{i=1}^{I}\sum_{j=1}^{J}\frac{v_{ijt}^{2}+v_{iit}v_{jjt}}{Var(\boldsymbol{\bar{Q}}_{t})}}{I\times J}\)

-

where we calculate the mean of the process covariance matrix \(\left(\bar{\boldsymbol{Q}_{t}}\right)\) from the posterior samples at time t. Degrees of freedom for the Wishart are typically calculated element by element where \(v_{ij}\) are the elements of \(\boldsymbol{V}_{t}\). \(I\) and \(J\) index rows and columns of \(\boldsymbol{V}\). Here, we calculate a mean number of degrees of freedom for \(t+1\) by summing over all the elements of the scale matrix \(\left(\boldsymbol{V}\right)\) and dividing by the count of those elements \(\left(I\times J\right)\). We fit this model sequentially through time in the R computing environment using R package ‘rjags.’

-

Users have control over how they think is the best way to estimate \(Q\). Our code will look for the tag q.type in the XML settings under state.data.assimilation which can take 3 values of Single, PFT or Site. If q.type is set to single then one value of process variance will be estimated across all different sites or PFTs. On the other hand, when q.type` is set to Site or PFT then a process variance will be estimated for each site or PFT at a cost of more time and computation power.

-
-
-

7.2.2.13 Multi-site State data assimilation.

-

sda.enkf.multisite function allows for assimilation of observed data at multiple sites at the same time. In order to run a multi-site SDA, one needs to send a multisettings pecan xml file to this function. This multisettings xml file needs to contain information required for running at least two sites under run tag. The code will automatically run the ensembles for all the sites and reformats the outputs matching the required formats for analysis step.

-

The observed mean and cov needs to be formatted as list of different dates with observations. For each element of this list also there needs to be a list with mean and cov matrices of different sites named by their siteid. In case that zero variance was estimated for a variable inside the obs.cov, the SDA code will automatically replace that with half of the minimum variance from other non-zero variables in that time step.

-

This would look like something like this:

-
> obs.mean
-
-$`2010/12/31`
-$`2010/12/31`$`1000000650`
-   AbvGrndWood     GWBI
-    111.502    1.0746
-
-$`2010/12/31`$`1000000651`
-   AbvGrndWood     GWBI
-    114.302    1.574695
-
> obs.cov
-
-$`2010/12/31`
-$`2010/12/31`$`1000000650`
-           [,1]        [,2]
-[1,] 19.7821691 0.213584319
-[2,]  0.5135843 0.005162113
-
-$`2010/12/31`$`1000000651`
-           [,1]        [,2]
-[1,] 15.2821691 0.513584319
-[2,]  0.1213583 0.001162113
-

An example of multi-settings pecan xml file also may look like below:

-
<?xml version="1.0"?>
-<pecan.multi>
- <state.data.assimilation>
-   <process.variance>FALSE</process.variance>
-   <adjustment>TRUE</adjustment>
-   <data>
-    <format_id>1000000040</format_id>
-    <input.id>1000013298</input.id>
-  </data>
-   <state.variables>
-   <variable>
-      <variable.name>GWBI</variable.name>
-   <unit>KgC/m^2</unit>
-       <min_value>0</min_value>
-       <max_value>9999</max_value>
-   </variable>
-   <variable>
-   <variable.name>AbvGrndWood</variable.name>
-   <unit>KgC/m^2</unit>
-   <min_value>0</min_value>
-   <max_value>9999</max_value>
-   </variable>
-   </state.variables>
-  <start.date>1960/01/01</start.date>
-  <end.date>2000/12/31</end.date>
-  </state.data.assimilation>
- <info>
-    <notes></notes>
-    <userid>-1</userid>
-    <username></username>
-    <date>2017/12/06 21:19:33 +0000</date>
-  </info>
- <outdir>/fs/data3/hamzed/output/MultiSite_Sandbox/paleon_sda_SIPNET-8768</outdir>
- <database>
-    <bety>
-      <user>bety</user>
-      <password>bety</password>
-      <host>128.197.168.114</host>
-      <dbname>bety</dbname>
-      <driver>PostgreSQL</driver>
-      <write>false</write>
-    </bety>
-    <dbfiles>/fs/data1/pecan.data/dbfiles/</dbfiles>
-  </database>
- <pfts>
-  <pft>
-   <name>temperate.deciduous_SDA</name>
-   <constants>
-    <num>2</num>
-   </constants>
-   <outdir>/fs/data2/output//PEcAn_1000008768/pft/temperate.deciduous_SDA</outdir>
-   <posteriorid>1000008552</posteriorid>
-  </pft>
- </pfts>
- <meta.analysis>
-    <iter>3000</iter>
-    <random.effects>
-      <on>FALSE</on>
-      <use_ghs>TRUE</use_ghs>
-    </random.effects>
-  </meta.analysis>
- <ensemble>
-  <size>20</size>
-  <ensemble.id>1000016146</ensemble.id>
-  <start.year>1995</start.year>
-  <end.year>1999</end.year>
-  <samplingspace>
-  <parameters>
-    <method>uniform</method>
-  </parameters>
-  <met>
-    <method>sampling</method>
-  </met>
-  <soil>    
-  <parent>parameters</parent>
-  </soil>
-  <vegetation>
-  <parent>soil</parent>
-  </vegetation>
-  </samplingspace>
- </ensemble>
- <model>
-  <id>1000000022</id>
-  <default.param>/fs/data3/hamzed/output/paleon_sda_SIPNET-8768/Bartlett.param</default.param>
-  <type>SIPNET</type>
-  <revision>r136</revision>
-  <delete.raw>FALSE</delete.raw>
-  <binary>/fs/data5/pecan.models/SIPNET/trunk/sipnet_ssr</binary>
- </model>
- <workflow>
-    <id>1000008768</id>
-  </workflow>
- <run>
-  <settings.1000000650>
-  <site>
-   <id>1000000650</id>
-   <met.start>1960/01/01</met.start>
-   <met.end>1965/12/31</met.end>
-   <name>Harvard Forest - Lyford Plots (PalEON PHA)</name>
-   <lat>42.53</lat>
-   <lon>-72.18</lon>
-  </site>
-  <inputs>
-   <met>
-    <source>CRUNCEP</source>
-    <output>SIPNET</output>
-    <path>
-    <path1>/fs/data1/pecan.data/dbfiles/CRUNCEP_SIPNET_site_0-758/CRUNCEP.1960-01-01.2010-12-31.clim</path1>
-    </path>
-   </met>
-  </inputs>
-  <start.date>1960/01/01</start.date>
-  <end.date>1980/12/31</end.date>
-  </settings.1000000650>
-  <settings.1000000651>
-  <site>
-   <id>1000000651</id>
-   <met.start>1960/01/01</met.start>
-   <met.end>1965/12/31</met.end>
-   <name>Harvard Forest - Lyford Plots (PalEON PHA)</name>
-   <lat>42.53</lat>
-   <lon>-72.18</lon>
-  </site>
-  <inputs>
-   <met>
-    <source>CRUNCEP</source>
-    <output>SIPNET</output>
-    <path>
-    <path1>/fs/data1/pecan.data/dbfiles/CRUNCEP_SIPNET_site_0-758/CRUNCEP.1960-01-01.2010-12-31.clim</path1>
-    </path>
-   </met>
-  </inputs>
-  <start.date>1960/01/01</start.date>
-  <end.date>1980/12/31</end.date>
-  </settings.1000000651>
- </run>
- <host>
-  <name>localhost</name>
-  <rundir>/fs/data3/hamzed/output/MultiSite_Sandbox/paleon_sda_SIPNET-8768/run</rundir>
-  <outdir>/fs/data3/hamzed/output/MultiSite_Sandbox/paleon_sda_SIPNET-8768/out</outdir>
- </host>
- <settings.info>
-  <deprecated.settings.fixed>TRUE</deprecated.settings.fixed>
-  <settings.updated>TRUE</settings.updated>
-  <checked>TRUE</checked>
- </settings.info>
- <rundir>/fs/data3/hamzed/output/MultiSite_Sandbox/paleon_sda_SIPNET-8768/run</rundir>
- <modeloutdir>/fs/data3/hamzed/output/MultiSite_Sandbox/paleon_sda_SIPNET-8768/out</modeloutdir>
- <multisettings>run</multisettings>
-</pecan.multi>
-
-
-
-

7.2.3 Running SDA on remote

-

In general, the idea is that sending, running and monitoring an SDA job should all be done using two functions (SDA_remote_launcher and Remote_Sync_launcher). SDA_remote_launcher checks the XML settings defining the run, sets up the SDA on the remote machine, and then sends a qusb command for running the job. Remote_Sync_launcher, on the other hand, sits on the local machine and monitors the progress of the job(s) and brings back the outputs as long as the job is running.

-

SDA_remote_launcher sets up the job by copying a template SDA workflow R script and a bash file template that are ready for submission to the remote machine. This function checks the paths to all inputs including met, soil, site_pft and etc., testing whether they exists on the remote machine or not. If they do not exist, the function copies the missing paths over and replaces the settings accordingly. After submitting the bash script, the function returns the PID of the job writing the log file, allowing the Remote_Sync_launcher to monitor the progress of the run, checks to see if the job is still alive, and determines if sda.output.rdata has been updated since the last check or not.

-

Additionally, the Remote_Sync_launcher function follows the progress of the remote job by executing a nohup command on a template R script and keeps the R console open for further use. This R script, as mentioned above, constantly pings the given PID every 5 minutes and copies over the SDA output.

-

Several points on how to prepare your xml settings for the remote SDA run: -1 - In the main pecan workflow.R, if you were able to generate pecan.TRAIT.xml, your settings are ready to be used for an SDA run. All you need to add is your state data assimilation tags. -2 - Inside the xml setting an <outdir> flag needs to be included and point to a local directory where SDA_remote_launcher will look for either a sample.Rdata file or a pft folder. -3 - You need to set your <host> tag according to the desired remote machine. You can learn more about this on the Remote execution with PEcAn section of the documentation. Please make sure that the <folder> tag inside <host> is pointing to a directory where you would like to store and run your SDA job(s). -4 - Finally, make sure the tag inside the tag is set to the correct path on the remote machine.

-
-
-

7.2.4 Restart functionality in SDA

-

If you prefer to run your SDA analysis in multiple stages, where each phase picks up where the previous one left off, you can use the restart argument in the sda.enkf.multisite function. You need to make sure that the output from previous step exists in the SDA folder (in the outfolder), and the <start.date> is the same as <end.date> from the previous step. When you run the SDA with the restart parameter, it will load the output from the previous step and use configs already written in the run folder to set itself up for the next step. Using the restart argument could be as easy as :

-
sda.enkf.multisite(settings,
-                   obs.mean =obs.mean ,
-                   obs.cov = obs.cov,
-                   control = SDA.arguments(debug = FALSE, TimeseriesPlot = FALSE),
-                   restart = FALSE
-        )
-
-

Where the new settings, obs.mean and obs.cov contain the relevant information for the next phase.

-
-
-

7.2.5 State Data Assimilation Methods

-

By Ann Raiho

-

Our goal is build a fully generalizable state data assimilation (SDA) workflow that will assimilate multiple types of data and data products into ecosystem models within PEcAn temporally and spatially. But, during development, specifically with PalEON goals in mind, we have been focusing on assimilating tree ring estimated NPP and AGB and pollen derived fractional composition into two ecosystem models, SIPNET and LINKAGES, at Harvard Forest. This methodology will soon be expanded to include the PalEON sites listed on the state data assimilation wiki page.

-
-

7.2.5.1 Data Products

-

During workflow development, we have been working with tree ring estimated NPP and AGB and pollen derived fractional composition data products. Both of these data products have been estimated with a full accounting of uncertainty, which provides us with state variable observation mean vector and covariance matrix at each time step. These data products are discussed in more detail below. Even though we have been working with specific data products during development, our workflow is generalizable to alternative data products as long as we can calculate a state variable observation mean vector and covariance for a time point.

-
-
-

7.2.5.2 Tree Rings

-

We have been primarily been working with the tree ring data product created by Andria Dawson and Chris Paciorek and the PEcAn tree ring allometry module. They have developed a Bayesian model that estimates annual aboveground biomass increment (Mg/ha/yr) and aboveground biomass (Mg/ha) for each tree in a dataset. We obtain this data and aggregate to the level appropriate for the ecosystem model. In SIPNET, we are assimilating annual gross woody increment (Mg/ha/yr) and above ground woody biomass (Mg/ha). In LINKAGES, we are assimilating annual species biomass. More information on deriving these tree ring data products can be found in Dawson et al 201?.

-

We have been working mostly with tree data collected at Harvard Forest. Tree rings and census data were collected at Lyford Plot between 1960 and 2010 in three separate plots. Other tree ring data will be added to this analysis in the future from past PEON courses (UNDERC), Kelly Heilman (Billy’s Lake and Bigwoods), and Alex Dye (Huron Mt. Club).

-
-
-

7.2.5.3 Pollen

-

STEPPS is a Bayesian model developed by Paciorek and McLachlan 2009 and Dawson et al 2016 to estimate spatially gridded fractional composition from fossil pollen. We have been working with STEPPS1 output, specifically with the grid cell that contains Harvard Forest. The temporal resolution of this data product is centennial. Our workflow currently operates at annual time steps, but does not require data at every time step. So, it is possible to assimilate fractional composition every one hundred years or to assimilate fractional composition data every year by accounting for variance inflation.

-

In the future, pollen derived biomass (ReFAB) will also be available for data assimilation. Although, we have not discussed how STEPPS and ReFAB data assimilation will work.

-
-
-

7.2.5.4 Variance Inflation

-

*Side Note: Probably want to call this something else now.

-

Since the fractional composition data product has a centennial resolution, in order to use fractional composition information every year we need to change the weight the data has on the analysis. The basic idea is to downweight the likelihood relative to the prior to account for (a) the fact that we assimilate an observation multiple times and (b) the fact that the number of STEPPS observations is ‘inflated’ because of the autocorrelation. To do this, we take the likelihood and raise it to the power of (1/w) where ‘w’ is an inflation factor.

-

w = D * (N / ESS)

-

where D is the length of the time step. In our case D = 100. N is the number of time steps. In our case N = 11. and ESS is the effective sample size. The ESS is calculated with the following function where ntimes is the same as N above and sims is a matrix with the dimensions number of MCMC samples by number of state variables.

-
ESS_calc <- function(ntimes, sims){
-        # center based on mean at each time to remove baseline temporal correlation 
-        # (we want to estimate effective sample size effect from correlation of the errors)
-        row.means.sims <- sims - rowMeans(sims)  
-        
-        # compute all pairwise covariances at different times
-        covars <- NULL
-        for(lag in 1:(ntimes-1)){
-          covars <- c(covars, rowMeans(row.means.sims[(lag+1):ntimes, , drop = FALSE] * row.means.sims[1:(ntimes-lag), , drop = FALSE])) 
-        }
-        vars <- apply(row.means.sims, 1, var) # pointwise post variances at each time, might not be homoscedastic
-        
-        # nominal sample size scaled by ratio of variance of an average
-        # under independence to variance of average of correlated values
-        neff <- ntimes * sum(vars) / (sum(vars) + 2 * sum(covars))
-        return(neff)
-      }
-

The ESS for the STEPPS1 data product is 3.6, so w in our assimilation of fractional composition at Harvard Forest will be w = 305.6.

-
-
-

7.2.5.5 Current Models

-

SIPNET and LINKAGES are the two ecosystem models that have been used during state data assimilation development within PEcAn. SIPNET is a simple ecosystem model that was built for… LINKAGES is a forest gap model created to simulate the process of succession that occurs when a gap is opened in the forest canopy. LINKAGES has 72 species level plant functional types and the ability to simulate some below ground processes (C and N cycles).

-
-
-

7.2.5.6 Model Calibration

-

Without model calibration both SIPNET and LINKAGES make incorrect predictions about Harvard Forest. To confront this problem, SIPNET and LINKAGES will both be calibrated using data collected at the Harvard Forest flux tower. Istem has completed calibration for SIPNET using a parameter data assimilation emulator contained within the PEcAn workflow. LINKAGES will also be calibrated using this method. This method is also generalizable to other sites assuming there is data independent of data assimilation data available to calibrate against.

-
-
-

7.2.5.7 Initial Conditions

-

The initial conditions for SIPNET are sampled across state space based on data distributions at the time when the data assimilation will begin. We do not sample LINAKGES for initial conditions and instead perform model spin up for 100 years prior to beginning data assimilation. In the future, we would like to estimate initial conditions based on data. We achieve adequate spread in the initial conditions by allowing the parameters to vary across ensemble members.

-
-
-

7.2.5.8 Drivers

-

We are currently using Global Climate Model (GCM) drivers from the PaLEON model intercomparison. Christy Rollinson and John Tipton are creating MET downscaled GCM drivers for the Paleon data assimilation sites. We will use these drivers when they are available because they are a closer representation of reality.

-
-
-

7.2.5.9 Sequential State Data Assimilation

-

We are using sequential state data assimilation methods to assimilate paleon data products into ecosystem models because less computation power is required for sequential state data assimilation than for particle filter methods.

-
-
-

7.2.5.10 General Description

-

The general sequential data assimilation framework consists of three steps at each time step: -1. Read the state variable output for time t from the model forecast ensembles and save the forecast mean (muf) and covariance (Pf). -2. If there are data mean (y) and covariance (R) at this time step, perform data assimilation analysis (either EnKF or generalized ensemble filter) to calculate the new mean (mua) and covariance (Pa) of the state variables. -3. Use mua and Pa to restart and run the ecosystem model ensembles with new state variables for time t+1.

-
-
-

7.2.5.11 EnKF

-

There are two ways to implement sequential state data assimilation at this time. The first is the Ensemble Kalman Filter (EnKF). EnKF has an analytical solution, so the kalman gain, analysis mean vector, and analysis covariance matrix can be calculated directly:

-
       
-        K <- Pf %*% t(H) %*% solve((R + H %*% Pf %*% t(H))) ## Kalman Gain
-        
-        mu.a <- mu.f + K %*% (Y - H %*% mu.f) # Analysis mean vector
-        
-        Pa   <- (diag(ncol(X)) - K %*% H) %*% Pf # Analysis covariance matrix
-        
-

The EnKF is typically used for sequential state data assimilation, but we found that EnKF lead to filter divergence when combined with our uncertain data products. Filter divergence led us to create a generalized ensemble filter that estimates process variance.

-
-
-

7.2.5.12 Generalized Ensemble Filter

-

The generalized ensemble filter follows generally the three steps of sequential state data assimilation. But, in the generalized ensemble filter we add a latent state vector that accounts for added process variance. Furthermore, instead of solving the analysis analytically like the EnKF, we have to estimate the mean analysis vector and covariance matrix with MCMC.

-
-
-

7.2.5.13 Mapping Ensemble Output to Tobit Space

-

There are some instances when we have right or left censored variables from the model forecast. For example, a model estimating species level biomass may have several ensemble members that produce zero biomass for a given species. We are considering this case a left censored state variable that needs to be mapped to normal space using a tobit model. We do this by creating two matrices with dimensions number of ensembles by state variable. The first matrix is a matrix of indicator variables (y.ind), and the second is a matrix of censored variables (y.censored). When the indicator variable is 0 the state variable (j) for ensemble member (i) is sampled. This allows us to impute a normal distribution for each state variable that contains ‘missing’ forecasts or forecasts of zero.

-
tobit2space.model <- nimbleCode({
-    for(i in 1:N){
-      y.censored[i,1:J] ~ dmnorm(muf[1:J], cov = pf[1:J,1:J])
-      for(j in 1:J){
-        y.ind[i,j] ~ dconstraint(y.censored[i,j] > 0)
-      }
-    }
-    
-    muf[1:J] ~ dmnorm(mean = mu_0[1:J], cov = pf[1:J,1:J])
-    
-    Sigma[1:J,1:J] <- lambda_0[1:J,1:J]/nu_0
-    pf[1:J,1:J] ~ dinvwish(S = Sigma[1:J,1:J], df = J)
-    
-  })
-
-
-

7.2.5.14 Generalized Ensemble Filter Model Description

-

Below is the BUGS code for the full analysis model. The forecast mean an covariance are calculated from the tobit2space model above. We use a tobit likelihood in this model because there are instances when the data may be left or right censored. Process variance is included by adding a latent model state (X) with a process precision matrix (q). We update our prior on q at each time step using our estimate of q from the previous time step.

-
  tobit.model <- nimbleCode({ 
-    
-    q[1:N,1:N]  ~ dwish(R = aq[1:N,1:N], df = bq) ## aq and bq are estimated over time
-    Q[1:N,1:N] <- inverse(q[1:N,1:N])
-    X.mod[1:N] ~ dmnorm(muf[1:N], prec = pf[1:N,1:N]) ## Model Forecast ##muf and pf are assigned from ensembles
-    
-    ## add process error
-    X[1:N]  ~ dmnorm(X.mod[1:N], prec = q[1:N,1:N])
-    
-    #agb linear
-    #y_star[1:YN,1:YN] <- X[1:YN,1:YN] #[choose]
-    
-    #f.comp non linear
-    #y_star[1:YN] <- X[1:YN] / sum(X[1:YN])
-    
-    ## Analysis
-    y.censored[1:YN] ~ dmnorm(X[1:YN], prec = r[1:YN,1:YN]) #is it an okay assumpution to just have X and Y in the same order?
-    
-    #don't flag y.censored as data, y.censored in inits
-    #remove y.censored samplers and only assign univariate samplers on NAs
-    
-    for(i in 1:YN){
-      y.ind[i] ~ dconstraint(y.censored[i] > 0)
-    }
-    
-  })
-
-
-

7.2.5.15 Ensemble Adjustment

-

Each ensemble member has a different set of species parameters. We adjust the updated state variables by using an ensemble adjustment. The ensemble adjustment weights the ensemble members based on their likelihood during the analysis step.

-
      S_f  <- svd(Pf)
-      L_f  <- S_f$d
-      V_f  <- S_f$v
-      
-      ## normalize
-      Z <- X*0
-      for(i in seq_len(nrow(X))){
-          Z[i,] <- 1/sqrt(L_f) * t(V_f)%*%(X[i,]-mu.f)
-      }
-      Z[is.na(Z)]<-0
-      
-      ## analysis
-      S_a  <- svd(Pa)
-      L_a  <- S_a$d
-      V_a  <- S_a$v
-      
-      ## analysis ensemble
-      X_a <- X*0
-      for(i in seq_len(nrow(X))){
-        X_a[i,] <- V_a %*%diag(sqrt(L_a))%*%Z[i,] + mu.a
-      }
-
-
-

7.2.5.16 Diagnostics

-

There are three diagnostics we have currently implemented: time series, bias time series, and process variance. The time series diagnostics show the data, forecast, and analysis time series for each state variable. These are useful for visually assessing variance and magnitude of change of state variables through time. These time series are also updated throughout the analysis and are also created as a pdf at the end of the SDA workflow. There are two types of bias time series the first assess the bias in the update (the forecast minus the analysis) and the second assess the bias in the error (the forecast minus the data). These bias time series are useful for identifying which state variables have intrinsic bias within the model. For example, if red oak biomass in LINKAGES increases at every time step (the update and the error are always positive), this would suggest that LINKAGES has a positive growth or recruitment bias for red oak. Finally, when using the generalized ensemble filter to estimate process variance, there are two additional plots to assess estimation of process variance. The first is a correlation plot of the process covariance matrix. This tells us what correlations are incorrectly represented by the model. For example, if red oak biomass and white pine biomass are highly negatively correlated in the process covariance matrix, this means that the model either 1) has no relationship between red oak and white pine and they should affect each other negatively or 2) there is a positive relationship between red oak and white pine and there shouldn’t be any relationship. We can determine which of these is true by comparing the process covariance matrix to the model covariance matrix. The second process variance diagnostic plot shows how the degrees of freedom associated with estimating the process covariance matrix have changed through time. This plot should show increasing degrees of freedom through time.

-
-
-
-

7.2.6 MultiSettings

-

(TODO: Under construction…)

-
-
-

7.2.7 Benchmarking

-

Benchmarking is the process of comparing model outputs against either experimental data or against other model outputs as a way to validate model performance. -We have a suit of statistical comparisons that provide benchmarking scores as well as visual comparisons that help in diagnosing data-model and/or model-model differences.

-
-

7.2.7.1 Data Preparation

-

All data that you want to compare with model runs must be registered in the database. -This is currently a step that must be done by hand either from the command line or through the online BETY interface. -The data must have three records:

-
    -
  1. An input record (Instructions here)

  2. -
  3. A database file record (Instructions here)

  4. -
  5. A format record (Instructions here)

  6. -
-
-
-

7.2.7.2 Model Runs

-

Model runs can be setup and executed -- Using the PEcAn web interface online or with a VM (see setup) -- By hand using the pecan.xml

-
-
-

7.2.7.3 The Benchmarking Shiny App

-

The entire benchmarking process can be done through the Benchmarking R Shiny app.

-

When the model run has completed, navigate to the workflow visualization Shiny app.

-
    -
  • Load model data -
      -
    • Select the workflow and run id
    • -
    • Make sure that your model output is loading properly (i.e. you can see plots of your data)
    • -
  • -
  • Load benchmarking data -
      -
    • Again make sure that you can see the uploaded data plotted alongside the model output. In the future there will be more tools for double checking that your uploaded data is appropriate for benchmarking, but for now you may need to do the sanity checks by hand.
    • -
  • -
-
-
-

7.2.7.4 Create a reference run record

-
    -
  • Navigate to the Benchmarking tab -
      -
    • The first step is to register the new model run as a reference run in the database. Benchmarking cannot be done before this step is completed. When the reference run record has been created, additional menus for benchmarking will appear.
    • -
  • -
-
-
-

7.2.7.5 Setup Benchmarks and metrics

-
    -
  • From the menus select -
      -
    • The variables in the uploaded data that you wish to compare with model output.
    • -
    • The numerical metrics you would like to use in your comparison.
    • -
    • Additional comparison plots that you would like to see.
    • -
  • -
  • Note: All these selections populate the benchmarking section of the pecan.BENCH.xml which is then saved in the same location as the original run output. This xml is purely for reference.
  • -
-
-
7.2.7.5.1 Benchmarking Output
-
    -
  • All benchmarking results are stored in the benchmarking directory which is created in the same folder as the original model run.
  • -
  • The benchmaking directory contains subdirectories for each of the datasets compared with the model output. The names of these directories are the same as the corresponding data set’s input id in BETY.
  • -
  • Each input directory contains benchmarking.output.Rdata, an Rdata file contianing all the results of the benchmarking workflow. load(benchmarking.output.Rdata) loads a list called result.out which contains the following: -
      -
    • bench.results: a data frame of all numeric benchmarking scores
    • -
    • format: a data frame that can be used to see how the input data was transformed to make it comparable to the model output. This involves converting from the original variable names and units to the internal pecan standard.
    • -
    • aligned.dat: a data frame of the final aligned model and input values.
    • -
  • -
  • All plots are saved as pdf files with names with “benchmark_plot-type_variable_input-id.pdf”

  • -
  • To view interactive results, naviage to the Benchmarking Plots tab in the shiny app.

  • -
-
-
-
-

7.2.7.6 Benchmarking in pecan.xml

-

Before reading this section, it is recommended that you familiarize yourself with basics of the pecan.xml file.

-

The pecan.xml has an optional benchmarking section. Below are all the tags in the benchmarking section explained. Many of these field are filled in automatically during the benchmarking process when using the benchmarking shiny app.

-

The only time one should edit the benchmarking section by hand is for performing clone runs. See clone run documentation.

-

<benchmarking> settings:

-
    -
  • ensemble_id: the id of the ensemble that you will be using - the settings from this ensemble will be saved in a reference run record and then ensemble_id will be replaced with reference_run_id
  • -
  • new_run: TRUE = create new run, FALSE = use existing run (required, default FALSE)
  • -
-

It is possible to look at more than one benchmark with a particular run. -The specific settings related to each benchmark are in a sub section called benchmark

-
    -
  • input_id: the id of the benchmarking data (required)
  • -
  • variable_id: the id of the variable of interest within the data. If you leave this blank, all variables that are shared between the input and model output will be used.
  • -
  • metric_id: the id(s) of the metric(s) to be calculated. If you leave this blank, all metrics will be used.
  • -
-

Example: -In this example, -- we are using a pre-existing run from ensemble_id = 1000010983 (new_run = FALSE) -- the output will be compared to data from input_id = 1000013743, specifically two variables of interest: variable_id = 411, variable_id = 18 -- for variable_id = 411 we will perform only one metric of comparison metric_id = 1000000001 -- for for variable_id = 18 we will perform two metrics of comparison metric_id = 1000000001, metric_id = 1000000002

- - -
-
-
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - - diff --git a/develop_test/libs/crosstalk-1.0.0/css/crosstalk.css b/develop_test/libs/crosstalk-1.0.0/css/crosstalk.css deleted file mode 100644 index 46befd2ed..000000000 --- a/develop_test/libs/crosstalk-1.0.0/css/crosstalk.css +++ /dev/null @@ -1,27 +0,0 @@ -/* Adjust margins outwards, so column contents line up with the edges of the - parent of container-fluid. */ -.container-fluid.crosstalk-bscols { - margin-left: -30px; - margin-right: -30px; - white-space: normal; -} - -/* But don't adjust the margins outwards if we're directly under the body, - i.e. we were the top-level of something at the console. */ -body > .container-fluid.crosstalk-bscols { - margin-left: auto; - margin-right: auto; -} - -.crosstalk-input-checkboxgroup .crosstalk-options-group .crosstalk-options-column { - display: inline-block; - padding-right: 12px; - vertical-align: top; -} - -@media only screen and (max-width:480px) { - .crosstalk-input-checkboxgroup .crosstalk-options-group .crosstalk-options-column { - display: block; - padding-right: inherit; - } -} diff --git a/develop_test/libs/crosstalk-1.0.0/js/crosstalk.min.js b/develop_test/libs/crosstalk-1.0.0/js/crosstalk.min.js deleted file mode 100644 index 55262e871..000000000 --- a/develop_test/libs/crosstalk-1.0.0/js/crosstalk.min.js +++ /dev/null @@ -1,2 +0,0 @@ -!function a(b,c,d){function e(g,h){if(!c[g]){if(!b[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);var j=new Error("Cannot find module '"+g+"'");throw j.code="MODULE_NOT_FOUND",j}var k=c[g]={exports:{}};b[g][0].call(k.exports,function(a){var c=b[g][1][a];return e(c?c:a)},k,k.exports,a,b,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;gb?1:void 0}Object.defineProperty(c,"__esModule",{value:!0});var f=function(){function a(a,b){for(var c=0;c0&&void 0!==arguments[0]?arguments[0]:this._allKeys,b=Object.keys(this._handles).length;if(0===b)this._value=null;else{this._value=[];for(var c=0;c?@\[\\\]^`{|}~])/g,"\\$1")}function f(a){var b=h(a);Object.keys(i).forEach(function(c){if(b.hasClass(c)&&!b.hasClass("crosstalk-input-bound")){var d=i[c];g(d,a)}})}function g(a,b){var c=h(b).find("script[type='application/json'][data-for='"+e(b.id)+"']"),d=JSON.parse(c[0].innerText),f=a.factory(b,d);h(b).data("crosstalk-instance",f),h(b).addClass("crosstalk-input-bound")}Object.defineProperty(c,"__esModule",{value:!0}),c.register=b;var h=a.jQuery,i={};a.Shiny&&!function(){var b=new a.Shiny.InputBinding,c=a.jQuery;c.extend(b,{find:function(a){return c(a).find(".crosstalk-input")},initialize:function(a){c(a).hasClass("crosstalk-input-bound")||f(a)},getId:function(a){return a.id},getValue:function(a){},setValue:function(a,b){},receiveMessage:function(a,b){},subscribe:function(a,b){c(a).data("crosstalk-instance").resume()},unsubscribe:function(a){c(a).data("crosstalk-instance").suspend()}}),a.Shiny.inputBindings.register(b,"crosstalk.inputBinding")}()}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}],7:[function(a,b,c){(function(b){"use strict";function c(a){if(a&&a.__esModule)return a;var b={};if(null!=a)for(var c in a)Object.prototype.hasOwnProperty.call(a,c)&&(b[c]=a[c]);return b.default=a,b}var d=a("./input"),e=c(d),f=a("./filter"),g=b.jQuery;e.register({className:"crosstalk-input-checkboxgroup",factory:function(a,b){var c=new f.FilterHandle(b.group),d=void 0,e=g(a);return e.on("change","input[type='checkbox']",function(){var a=e.find("input[type='checkbox']:checked");0===a.length?(d=null,c.clear()):!function(){var e={};a.each(function(){b.map[this.value].forEach(function(a){e[a]=!0})});var f=Object.keys(e);f.sort(),d=f,c.set(f)}()}),{suspend:function(){c.clear()},resume:function(){d&&c.set(d)}}}})}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{"./filter":2,"./input":6}],8:[function(a,b,c){(function(b){"use strict";function c(a){if(a&&a.__esModule)return a;var b={};if(null!=a)for(var c in a)Object.prototype.hasOwnProperty.call(a,c)&&(b[c]=a[c]);return b.default=a,b}var d=a("./input"),e=c(d),f=a("./util"),g=c(f),h=a("./filter"),i=b.jQuery;e.register({className:"crosstalk-input-select",factory:function(a,b){var c=[{value:"",label:"(All)"}],d=g.dataframeToD3(b.items),e={options:c.concat(d),valueField:"value",labelField:"label",searchField:"label"},f=i(a).find("select")[0],j=i(f).selectize(e)[0].selectize,k=new h.FilterHandle(b.group),l=void 0;return j.on("change",function(){0===j.items.length?(l=null,k.clear()):!function(){var a={};j.items.forEach(function(c){b.map[c].forEach(function(b){a[b]=!0})});var c=Object.keys(a);c.sort(),l=c,k.set(c)}()}),{suspend:function(){k.clear()},resume:function(){l&&k.set(l)}}}})}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{"./filter":2,"./input":6,"./util":11}],9:[function(a,b,c){(function(b){"use strict";function c(a){if(a&&a.__esModule)return a;var b={};if(null!=a)for(var c in a)Object.prototype.hasOwnProperty.call(a,c)&&(b[c]=a[c]);return b.default=a,b}function d(a,b){for(var c=a.toString();c.length=i&&m<=j&&k.push(b.keys[l])}k.sort(),d.set(k),p=k}}),{suspend:function(){d.clear()},resume:function(){p&&d.set(p)}}}})}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{"./filter":2,"./input":6}],10:[function(a,b,c){"use strict";function d(a){if(a&&a.__esModule)return a;var b={};if(null!=a)for(var c in a)Object.prototype.hasOwnProperty.call(a,c)&&(b[c]=a[c]);return b.default=a,b}function e(a){return a&&a.__esModule?a:{default:a}}function f(a,b){if(!(a instanceof b))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(c,"__esModule",{value:!0}),c.SelectionHandle=void 0;var g=function(){function a(a,b){for(var c=0;c0&&void 0!==arguments[0]?arguments[0]:null,c=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;f(this,a),this._eventRelay=new i.default,this._emitter=new m.SubscriptionTracker(this._eventRelay),this._group=null,this._var=null,this._varOnChangeSub=null,this._extraInfo=m.extend({sender:this},c),this.setGroup(b)}return g(a,[{key:"setGroup",value:function(a){var b=this;if(this._group!==a&&(this._group||a)&&(this._var&&(this._var.off("change",this._varOnChangeSub),this._var=null,this._varOnChangeSub=null),this._group=a,a)){this._var=(0,k.default)(a).var("selection");var c=this._var.on("change",function(a){b._eventRelay.trigger("change",a,b)});this._varOnChangeSub=c}}},{key:"_mergeExtraInfo",value:function(a){return m.extend({},this._extraInfo?this._extraInfo:null,a?a:null)}},{key:"set",value:function(a,b){this._var&&this._var.set(a,this._mergeExtraInfo(b))}},{key:"clear",value:function(a){this._var&&this.set(void 0,this._mergeExtraInfo(a))}},{key:"on",value:function(a,b){return this._emitter.on(a,b)}},{key:"off",value:function(a,b){return this._emitter.off(a,b)}},{key:"close",value:function(){this._emitter.removeAllListeners(),this.setGroup(null)}},{key:"value",get:function(){return this._var?this._var.get():null}}]),a}()},{"./events":1,"./group":4,"./util":11}],11:[function(a,b,c){"use strict";function d(a,b){if(!(a instanceof b))throw new TypeError("Cannot call a class as a function")}function e(a){for(var b=arguments.length,c=Array(b>1?b-1:0),d=1;d 123,456,666.7890 -var markInterval = function(d, digits, interval, mark, decMark, precision) { - x = precision ? d.toPrecision(digits) : d.toFixed(digits); - if (!/^-?[\d.]+$/.test(x)) return x; - var xv = x.split('.'); - if (xv.length > 2) return x; // should have at most one decimal point - xv[0] = xv[0].replace(new RegExp('\\B(?=(\\d{' + interval + '})+(?!\\d))', 'g'), mark); - return xv.join(decMark); -}; - -DTWidget.formatCurrency = function(thiz, row, data, col, currency, digits, interval, mark, decMark, before) { - var d = parseFloat(data[col]); - if (isNaN(d)) return; - var res = markInterval(d, digits, interval, mark, decMark); - res = before ? (/^-/.test(res) ? '-' + currency + res.replace(/^-/, '') : currency + res) : - res + currency; - $(thiz.api().cell(row, col).node()).html(res); -}; - -DTWidget.formatString = function(thiz, row, data, col, prefix, suffix) { - var d = data[col]; - if (d === null) return; - var cell = $(thiz.api().cell(row, col).node()); - cell.html(prefix + cell.html() + suffix); -}; - -DTWidget.formatPercentage = function(thiz, row, data, col, digits, interval, mark, decMark) { - var d = parseFloat(data[col]); - if (isNaN(d)) return; - $(thiz.api().cell(row, col).node()) - .html(markInterval(d * 100, digits, interval, mark, decMark) + '%'); -}; - -DTWidget.formatRound = function(thiz, row, data, col, digits, interval, mark, decMark) { - var d = parseFloat(data[col]); - if (isNaN(d)) return; - $(thiz.api().cell(row, col).node()).html(markInterval(d, digits, interval, mark, decMark)); -}; - -DTWidget.formatSignif = function(thiz, row, data, col, digits, interval, mark, decMark) { - var d = parseFloat(data[col]); - if (isNaN(d)) return; - $(thiz.api().cell(row, col).node()) - .html(markInterval(d, digits, interval, mark, decMark, true)); -}; - -DTWidget.formatDate = function(thiz, row, data, col, method, params) { - var d = data[col]; - if (d === null) return; - // (new Date('2015-10-28')).toDateString() may return 2015-10-27 because the - // actual time created could be like 'Tue Oct 27 2015 19:00:00 GMT-0500 (CDT)', - // i.e. the date-only string is treated as UTC time instead of local time - if ((method === 'toDateString' || method === 'toLocaleDateString') && /^\d{4,}\D\d{2}\D\d{2}$/.test(d)) { - d = d.split(/\D/); - d = new Date(d[0], d[1] - 1, d[2]); - } else { - d = new Date(d); - } - $(thiz.api().cell(row, col).node()).html(d[method].apply(d, params)); -}; - -window.DTWidget = DTWidget; - -var transposeArray2D = function(a) { - return a.length === 0 ? a : HTMLWidgets.transposeArray2D(a); -}; - -var crosstalkPluginsInstalled = false; - -function maybeInstallCrosstalkPlugins() { - if (crosstalkPluginsInstalled) - return; - crosstalkPluginsInstalled = true; - - $.fn.dataTable.ext.afnFiltering.push( - function(oSettings, aData, iDataIndex) { - var ctfilter = oSettings.nTable.ctfilter; - if (ctfilter && !ctfilter[iDataIndex]) - return false; - - var ctselect = oSettings.nTable.ctselect; - if (ctselect && !ctselect[iDataIndex]) - return false; - - return true; - } - ); -} - -HTMLWidgets.widget({ - name: "datatables", - type: "output", - renderOnNullValue: true, - initialize: function(el, width, height) { - $(el).html(' '); - return { - data: null, - ctfilterHandle: new crosstalk.FilterHandle(), - ctfilterSubscription: null, - ctselectHandle: new crosstalk.SelectionHandle(), - ctselectSubscription: null - }; - }, - renderValue: function(el, data, instance) { - if (el.offsetWidth === 0 || el.offsetHeight === 0) { - instance.data = data; - return; - } - instance.data = null; - var $el = $(el); - $el.empty(); - - if (data === null) { - $el.append(' '); - // clear previous Shiny inputs (if any) - for (var i in instance.clearInputs) instance.clearInputs[i](); - instance.clearInputs = {}; - return; - } - - var crosstalkOptions = data.crosstalkOptions; - if (!crosstalkOptions) crosstalkOptions = { - 'key': null, 'group': null - }; - if (crosstalkOptions.group) { - maybeInstallCrosstalkPlugins(); - instance.ctfilterHandle.setGroup(crosstalkOptions.group); - instance.ctselectHandle.setGroup(crosstalkOptions.group); - } - - // If we are in a flexdashboard scroll layout then we: - // (a) Always want to use pagination (otherwise we'll have - // a "double scroll bar" effect on the phone); and - // (b) Never want to fill the container (we want the pagination - // level to determine the size of the container) - if (window.FlexDashboard && !window.FlexDashboard.isFillPage()) { - data.options.bPaginate = true; - data.fillContainer = false; - } - - // if we are in the viewer then we always want to fillContainer and - // and autoHideNavigation (unless the user has explicitly set these) - if (window.HTMLWidgets.viewerMode) { - if (!data.hasOwnProperty("fillContainer")) - data.fillContainer = true; - if (!data.hasOwnProperty("autoHideNavigation")) - data.autoHideNavigation = true; - } - - // propagate fillContainer to instance (so we have it in resize) - instance.fillContainer = data.fillContainer; - - var cells = data.data; - - if (cells instanceof Array) cells = transposeArray2D(cells); - - $el.append(data.container); - var $table = $el.find('table'); - if (data.class) $table.addClass(data.class); - if (data.caption) $table.prepend(data.caption); - - if (!data.selection) data.selection = { - mode: 'none', selected: null, target: 'row' - }; - if (HTMLWidgets.shinyMode && data.selection.mode !== 'none' && - data.selection.target === 'row+column') { - if ($table.children('tfoot').length === 0) { - $table.append($('')); - $table.find('thead tr').clone().appendTo($table.find('tfoot')); - } - } - - // column filters - var filterRow; - switch (data.filter) { - case 'top': - $table.children('thead').append(data.filterHTML); - filterRow = $table.find('thead tr:last td'); - break; - case 'bottom': - if ($table.children('tfoot').length === 0) { - $table.append($('')); - } - $table.children('tfoot').prepend(data.filterHTML); - filterRow = $table.find('tfoot tr:first td'); - break; - } - - var options = { searchDelay: 1000 }; - if (cells !== null) $.extend(options, { - data: cells - }); - - // options for fillContainer - var bootstrapActive = typeof($.fn.popover) != 'undefined'; - if (instance.fillContainer) { - - // force scrollX/scrollY and turn off autoWidth - options.scrollX = true; - options.scrollY = "100px"; // can be any value, we'll adjust below - - // if we aren't paginating then move around the info/filter controls - // to save space at the bottom and rephrase the info callback - if (data.options.bPaginate === false) { - - // we know how to do this cleanly for bootstrap, not so much - // for other themes/layouts - if (bootstrapActive) { - options.dom = "<'row'<'col-sm-4'i><'col-sm-8'f>>" + - "<'row'<'col-sm-12'tr>>"; - } - - options.fnInfoCallback = function(oSettings, iStart, iEnd, - iMax, iTotal, sPre) { - return Number(iTotal).toLocaleString() + " records"; - }; - } - } - - // auto hide navigation if requested - if (data.autoHideNavigation === true) { - if (bootstrapActive && data.options.bPaginate !== false) { - // strip all nav if length >= cells - if ((cells instanceof Array) && data.options.iDisplayLength >= cells.length) - options.dom = "<'row'<'col-sm-12'tr>>"; - // alternatively lean things out for flexdashboard mobile portrait - else if (window.FlexDashboard && window.FlexDashboard.isMobilePhone()) - options.dom = "<'row'<'col-sm-12'f>>" + - "<'row'<'col-sm-12'tr>>" + - "<'row'<'col-sm-12'p>>"; - } - } - - $.extend(true, options, data.options || {}); - - var searchCols = options.searchCols; - if (searchCols) { - searchCols = searchCols.map(function(x) { - return x === null ? '' : x.search; - }); - // FIXME: this means I don't respect the escapeRegex setting - delete options.searchCols; - } - - // server-side processing? - var server = options.serverSide === true; - - // use the dataSrc function to pre-process JSON data returned from R - var DT_rows_all = [], DT_rows_current = []; - if (server && HTMLWidgets.shinyMode && typeof options.ajax === 'object' && - /^session\/[\da-z]+\/dataobj/.test(options.ajax.url) && !options.ajax.dataSrc) { - options.ajax.dataSrc = function(json) { - DT_rows_all = $.makeArray(json.DT_rows_all); - DT_rows_current = $.makeArray(json.DT_rows_current); - var data = json.data; - if (!colReorderEnabled()) return data; - var table = $table.DataTable(), order = table.colReorder.order(), flag = true, i, j, row; - for (i = 0; i < order.length; ++i) if (order[i] !== i) flag = false; - if (flag) return data; - for (i = 0; i < data.length; ++i) { - row = data[i].slice(); - for (j = 0; j < order.length; ++j) data[i][j] = row[order[j]]; - } - return data; - }; - } - - var thiz = this; - if (instance.fillContainer) $table.on('init.dt', function(e) { - thiz.fillAvailableHeight(el, $(el).innerHeight()); - }); - // If the page contains serveral datatables and one of which enables colReorder, - // the table.colReorder.order() function will exist but throws error when called. - // So it seems like the only way to know if colReorder is enabled or not is to - // check the options. - var colReorderEnabled = function() { return "colReorder" in options; }; - var table = $table.DataTable(options); - $el.data('datatable', table); - - // Unregister previous Crosstalk event subscriptions, if they exist - if (instance.ctfilterSubscription) { - instance.ctfilterHandle.off("change", instance.ctfilterSubscription); - instance.ctfilterSubscription = null; - } - if (instance.ctselectSubscription) { - instance.ctselectHandle.off("change", instance.ctselectSubscription); - instance.ctselectSubscription = null; - } - - if (!crosstalkOptions.group) { - $table[0].ctfilter = null; - $table[0].ctselect = null; - } else { - var key = crosstalkOptions.key; - function keysToMatches(keys) { - if (!keys) { - return null; - } else { - var selectedKeys = {}; - for (var i = 0; i < keys.length; i++) { - selectedKeys[keys[i]] = true; - } - var matches = {}; - for (var j = 0; j < key.length; j++) { - if (selectedKeys[key[j]]) - matches[j] = true; - } - return matches; - } - } - - function applyCrosstalkFilter(e) { - $table[0].ctfilter = keysToMatches(e.value); - table.draw(); - } - instance.ctfilterSubscription = instance.ctfilterHandle.on("change", applyCrosstalkFilter); - applyCrosstalkFilter({value: instance.ctfilterHandle.filteredKeys}); - - function applyCrosstalkSelection(e) { - if (e.sender !== instance.ctselectHandle) { - table - .rows('.' + selClass, {search: 'applied'}) - .nodes() - .to$() - .removeClass(selClass); - if (selectedRows) - changeInput('rows_selected', selectedRows(), void 0, true); - } - - if (e.sender !== instance.ctselectHandle && e.value && e.value.length) { - var matches = keysToMatches(e.value); - - // persistent selection with plotly (& leaflet) - var ctOpts = crosstalk.var("plotlyCrosstalkOpts").get() || {}; - if (ctOpts.persistent === true) { - var matches = $.extend(matches, $table[0].ctselect); - } - - $table[0].ctselect = matches; - table.draw(); - } else { - if ($table[0].ctselect) { - $table[0].ctselect = null; - table.draw(); - } - } - } - instance.ctselectSubscription = instance.ctselectHandle.on("change", applyCrosstalkSelection); - // TODO: This next line doesn't seem to work when renderDataTable is used - applyCrosstalkSelection({value: instance.ctselectHandle.value}); - } - - var inArray = function(val, array) { - return $.inArray(val, $.makeArray(array)) > -1; - }; - - // encode + to %2B when searching in the table on server side, because - // shiny::parseQueryString() treats + as spaces, and DataTables does not - // encode + to %2B (or % to %25) when sending the request - var encode_plus = function(x) { - return server ? x.replace(/%/g, '%25').replace(/\+/g, '%2B') : x; - }; - - // search the i-th column - var searchColumn = function(i, value) { - var regex = false, ci = true; - if (options.search) { - regex = options.search.regex, - ci = options.search.caseInsensitive !== false; - } - return table.column(i).search(encode_plus(value), regex, !regex, ci); - }; - - if (data.filter !== 'none') { - - filterRow.each(function(i, td) { - - var $td = $(td), type = $td.data('type'), filter; - var $input = $td.children('div').first().children('input'); - $input.prop('disabled', !table.settings()[0].aoColumns[i].bSearchable || type === 'disabled'); - $input.on('input blur', function() { - $input.next('span').toggle(Boolean($input.val())); - }); - // Bootstrap sets pointer-events to none and we won't be able to click - // the clear button - $input.next('span').css('pointer-events', 'auto').hide().click(function() { - $(this).hide().prev('input').val('').trigger('input').focus(); - }); - var searchCol; // search string for this column - if (searchCols && searchCols[i]) { - searchCol = searchCols[i]; - $input.val(searchCol).trigger('input'); - } - var $x = $td.children('div').last(); - - // remove the overflow: hidden attribute of the scrollHead - // (otherwise the scrolling table body obscures the filters) - var scrollHead = $(el).find('.dataTables_scrollHead,.dataTables_scrollFoot'); - var cssOverflow = scrollHead.css('overflow'); - if (cssOverflow === 'hidden') { - $x.on('show hide', function(e) { - scrollHead.css('overflow', e.type === 'show' ? '' : cssOverflow); - }); - $x.css('z-index', 25); - } - - if (inArray(type, ['factor', 'logical'])) { - $input.on({ - click: function() { - $input.parent().hide(); $x.show().trigger('show'); filter[0].selectize.focus(); - }, - input: function() { - if ($input.val() === '') filter[0].selectize.setValue([]); - } - }); - var $input2 = $x.children('select'); - filter = $input2.selectize({ - options: $input2.data('options').map(function(v, i) { - return ({text: v, value: v}); - }), - plugins: ['remove_button'], - hideSelected: true, - onChange: function(value) { - if (value === null) value = []; // compatibility with jQuery 3.0 - $input.val(value.length ? JSON.stringify(value) : ''); - if (value.length) $input.trigger('input'); - $input.attr('title', $input.val()); - if (server) { - table.column(i).search(value.length ? encode_plus(JSON.stringify(value)) : '').draw(); - return; - } - // turn off filter if nothing selected - $td.data('filter', value.length > 0); - table.draw(); // redraw table, and filters will be applied - } - }); - if (searchCol) filter[0].selectize.setValue(JSON.parse(searchCol)); - filter[0].selectize.on('blur', function() { - $x.hide().trigger('hide'); $input.parent().show(); $input.trigger('blur'); - }); - filter.next('div').css('margin-bottom', 'auto'); - } else if (type === 'character') { - var fun = function() { - searchColumn(i, $input.val()).draw(); - }; - if (server) { - fun = $.fn.dataTable.util.throttle(fun, options.searchDelay); - } - $input.on('input', fun); - } else if (inArray(type, ['number', 'integer', 'date', 'time'])) { - var $x0 = $x; - $x = $x0.children('div').first(); - $x0.css({ - 'background-color': '#fff', - 'border': '1px #ddd solid', - 'border-radius': '4px', - 'padding': '20px 20px 10px 20px' - }); - var $spans = $x0.children('span').css({ - 'margin-top': '10px', - 'white-space': 'nowrap' - }); - var $span1 = $spans.first(), $span2 = $spans.last(); - var r1 = +$x.data('min'), r2 = +$x.data('max'); - // when the numbers are too small or have many decimal places, the - // slider may have numeric precision problems (#150) - var scale = Math.pow(10, Math.max(0, +$x.data('scale') || 0)); - r1 = Math.round(r1 * scale); r2 = Math.round(r2 * scale); - var scaleBack = function(x, scale) { - if (scale === 1) return x; - var d = Math.round(Math.log(scale) / Math.log(10)); - // to avoid problems like 3.423/100 -> 0.034230000000000003 - return (x / scale).toFixed(d); - }; - $input.on({ - focus: function() { - $x0.show().trigger('show'); - // first, make sure the slider div leaves at least 20px between - // the two (slider value) span's - $x0.width(Math.max(160, $span1.outerWidth() + $span2.outerWidth() + 20)); - // then, if the input is really wide, make the slider the same - // width as the input - if ($x0.outerWidth() < $input.outerWidth()) { - $x0.outerWidth($input.outerWidth()); - } - // make sure the slider div does not reach beyond the right margin - if ($(window).width() < $x0.offset().left + $x0.width()) { - $x0.offset({ - 'left': $input.offset().left + $input.outerWidth() - $x0.outerWidth() - }); - } - }, - blur: function() { - $x0.hide().trigger('hide'); - }, - input: function() { - if ($input.val() === '') filter.val([r1, r2]); - }, - change: function() { - var v = $input.val().replace(/\s/g, ''); - if (v === '') return; - v = v.split('...'); - if (v.length !== 2) { - $input.parent().addClass('has-error'); - return; - } - if (v[0] === '') v[0] = r1; - if (v[1] === '') v[1] = r2; - $input.parent().removeClass('has-error'); - // treat date as UTC time at midnight - var strTime = function(x) { - var s = type === 'date' ? 'T00:00:00Z' : ''; - var t = new Date(x + s).getTime(); - // add 10 minutes to date since it does not hurt the date, and - // it helps avoid the tricky floating point arithmetic problems, - // e.g. sometimes the date may be a few milliseconds earlier - // than the midnight due to precision problems in noUiSlider - return type === 'date' ? t + 3600000 : t; - }; - if (inArray(type, ['date', 'time'])) { - v[0] = strTime(v[0]); - v[1] = strTime(v[1]); - } - if (v[0] != r1) v[0] *= scale; - if (v[1] != r2) v[1] *= scale; - filter.val(v); - } - }); - var formatDate = function(d, isoFmt) { - d = scaleBack(d, scale); - if (type === 'number') return d; - if (type === 'integer') return parseInt(d); - var x = new Date(+d); - var fmt = ('filterDateFmt' in data) ? data.filterDateFmt[i] : undefined; - if (fmt !== undefined && isoFmt === false) return x[fmt.method].apply(x, fmt.params); - if (type === 'date') { - var pad0 = function(x) { - return ('0' + x).substr(-2, 2); - }; - return x.getUTCFullYear() + '-' + pad0(1 + x.getUTCMonth()) - + '-' + pad0(x.getUTCDate()); - } else { - return x.toISOString(); - } - }; - var opts = type === 'date' ? { step: 60 * 60 * 1000 } : - type === 'integer' ? { step: 1 } : {}; - filter = $x.noUiSlider($.extend({ - start: [r1, r2], - range: {min: r1, max: r2}, - connect: true - }, opts)); - if (scale > 1) (function() { - var t1 = r1, t2 = r2; - var val = filter.val(); - while (val[0] > r1 || val[1] < r2) { - if (val[0] > r1) { - t1 -= val[0] - r1; - } - if (val[1] < r2) { - t2 += r2 - val[1]; - } - filter = $x.noUiSlider($.extend({ - start: [t1, t2], - range: {min: t1, max: t2}, - connect: true - }, opts), true); - val = filter.val(); - } - r1 = t1; r2 = t2; - })(); - var updateSliderText = function(v1, v2) { - $span1.text(formatDate(v1, false)); $span2.text(formatDate(v2, false)); - }; - updateSliderText(r1, r2); - var updateSlider = function(e) { - var val = filter.val(); - // turn off filter if in full range - $td.data('filter', val[0] > r1 || val[1] < r2); - var v1 = formatDate(val[0]), v2 = formatDate(val[1]), ival; - if ($td.data('filter')) { - ival = v1 + ' ... ' + v2; - $input.attr('title', ival).val(ival).trigger('input'); - } else { - $input.attr('title', '').val(''); - } - updateSliderText(val[0], val[1]); - if (e.type === 'slide') return; // no searching when sliding only - if (server) { - table.column(i).search($td.data('filter') ? ival : '').draw(); - return; - } - table.draw(); - }; - filter.on({ - set: updateSlider, - slide: updateSlider - }); - } - - // server-side processing will be handled by R (or whatever server - // language you use); the following code is only needed for client-side - // processing - if (server) { - // if a search string has been pre-set, search now - if (searchCol) searchColumn(i, searchCol).draw(); - return; - } - - var customFilter = function(settings, data, dataIndex) { - // there is no way to attach a search function to a specific table, - // and we need to make sure a global search function is not applied to - // all tables (i.e. a range filter in a previous table should not be - // applied to the current table); we use the settings object to - // determine if we want to perform searching on the current table, - // since settings.sTableId will be different to different tables - if (table.settings()[0] !== settings) return true; - // no filter on this column or no need to filter this column - if (typeof filter === 'undefined' || !$td.data('filter')) return true; - - var r = filter.val(), v, r0, r1; - var i_data = function(i) { - if (!colReorderEnabled()) return i; - var order = table.colReorder.order(), k; - for (k = 0; k < order.length; ++k) if (order[k] === i) return k; - return i; // in theory it will never be here... - } - v = data[i_data(i)]; - if (type === 'number' || type === 'integer') { - v = parseFloat(v); - // how to handle NaN? currently exclude these rows - if (isNaN(v)) return(false); - r0 = parseFloat(scaleBack(r[0], scale)) - r1 = parseFloat(scaleBack(r[1], scale)); - if (v >= r0 && v <= r1) return true; - } else if (type === 'date' || type === 'time') { - v = new Date(v); - r0 = new Date(r[0] / scale); r1 = new Date(r[1] / scale); - if (v >= r0 && v <= r1) return true; - } else if (type === 'factor') { - if (r.length === 0 || inArray(v, r)) return true; - } else if (type === 'logical') { - if (r.length === 0) return true; - if (inArray(v === '' ? 'na' : v, r)) return true; - } - return false; - }; - - $.fn.dataTable.ext.search.push(customFilter); - - // search for the preset search strings if it is non-empty - if (searchCol) { - if (inArray(type, ['factor', 'logical'])) { - filter[0].selectize.setValue(JSON.parse(searchCol)); - } else if (type === 'character') { - $input.trigger('input'); - } else if (inArray(type, ['number', 'integer', 'date', 'time'])) { - $input.trigger('change'); - } - } - - }); - - } - - // highlight search keywords - var highlight = function() { - var body = $(table.table().body()); - // removing the old highlighting first - body.unhighlight(); - - // don't highlight the "not found" row, so we get the rows using the api - if (table.rows({ filter: 'applied' }).data().length === 0) return; - // highlight gloal search keywords - body.highlight($.trim(table.search()).split(/\s+/)); - // then highlight keywords from individual column filters - if (filterRow) filterRow.each(function(i, td) { - var $td = $(td), type = $td.data('type'); - if (type !== 'character') return; - var $input = $td.children('div').first().children('input'); - var column = table.column(i).nodes().to$(), - val = $.trim($input.val()); - if (type !== 'character' || val === '') return; - column.highlight(val.split(/\s+/)); - }); - }; - - if (options.searchHighlight) { - table - .on('draw.dt.dth column-visibility.dt.dth column-reorder.dt.dth', highlight) - .on('destroy', function() { - // remove event handler - table.off('draw.dt.dth column-visibility.dt.dth column-reorder.dt.dth'); - }); - - // initial highlight for state saved conditions and initial states - highlight(); - } - - // run the callback function on the table instance - if (typeof data.callback === 'function') data.callback(table); - - // double click to edit the cell - if (data.editable) table.on('dblclick.dt', 'tbody td', function() { - var $input = $(''); - var $this = $(this), value = table.cell(this).data(), html = $this.html(); - var changed = false; - $input.val(value); - $this.empty().append($input); - $input.css('width', '100%').focus().on('change', function() { - changed = true; - var valueNew = $input.val(); - if (valueNew != value) { - table.cell($this).data(valueNew); - if (HTMLWidgets.shinyMode) changeInput('cell_edit', cellInfo($this)); - // for server-side processing, users have to call replaceData() to update the table - if (!server) table.draw(false); - } else { - $this.html(html); - } - $input.remove(); - }).on('blur', function() { - if (!changed) $input.trigger('change'); - }); - }); - - // interaction with shiny - if (!HTMLWidgets.shinyMode && !crosstalkOptions.group) return; - - var methods = {}; - var shinyData = {}; - - methods.updateCaption = function(caption) { - if (!caption) return; - $table.children('caption').replaceWith(caption); - } - - // register clear functions to remove input values when the table is removed - instance.clearInputs = {}; - - var changeInput = function(id, value, type, noCrosstalk) { - var event = id; - id = el.id + '_' + id; - if (type) id = id + ':' + type; - // do not update if the new value is the same as old value - if (shinyData.hasOwnProperty(id) && shinyData[id] === JSON.stringify(value)) - return; - shinyData[id] = JSON.stringify(value); - if (HTMLWidgets.shinyMode) { - Shiny.onInputChange(id, value); - if (!instance.clearInputs[id]) instance.clearInputs[id] = function() { - Shiny.onInputChange(id, null); - } - } - - // HACK - if (event === "rows_selected" && !noCrosstalk) { - if (crosstalkOptions.group) { - var keys = crosstalkOptions.key; - var selectedKeys = null; - if (value) { - selectedKeys = []; - for (var i = 0; i < value.length; i++) { - // The value array's contents use 1-based row numbers, so we must - // convert to 0-based before indexing into the keys array. - selectedKeys.push(keys[value[i] - 1]); - } - } - instance.ctselectHandle.set(selectedKeys); - } - } - }; - - var addOne = function(x) { - return x.map(function(i) { return 1 + i; }); - }; - - var unique = function(x) { - var ux = []; - $.each(x, function(i, el){ - if ($.inArray(el, ux) === -1) ux.push(el); - }); - return ux; - } - - // change the row index of a cell - var tweakCellIndex = function(cell) { - var info = cell.index(); - if (server) { - info.row = DT_rows_current[info.row]; - } else { - info.row += 1; - } - return {row: info.row, col: info.column}; - } - - var selMode = data.selection.mode, selTarget = data.selection.target; - if (inArray(selMode, ['single', 'multiple'])) { - var selClass = data.style === 'bootstrap' ? 'active' : 'selected'; - var selected = data.selection.selected, selected1, selected2; - // selected1: row indices; selected2: column indices - if (selected === null) { - selected1 = selected2 = []; - } else if (selTarget === 'row') { - selected1 = $.makeArray(selected); - } else if (selTarget === 'column') { - selected2 = $.makeArray(selected); - } else if (selTarget === 'row+column') { - selected1 = $.makeArray(selected.rows); - selected2 = $.makeArray(selected.cols); - } - - // After users reorder the rows or filter the table, we cannot use the table index - // directly. Instead, we need this function to find out the rows between the two clicks. - // If user filter the table again between the start click and the end click, the behavior - // would be undefined, but it should not be a problem. - var shiftSelRowsIndex = function(start, end) { - var indexes = server ? DT_rows_all : table.rows({ search: 'applied' }).indexes().toArray(); - start = indexes.indexOf(start); end = indexes.indexOf(end); - // if start is larger than end, we need to swap - if (start > end) { - var tmp = end; end = start; start = tmp; - } - return indexes.slice(start, end + 1); - } - - var serverRowIndex = function(clientRowIndex) { - return server ? DT_rows_current[clientRowIndex] : clientRowIndex + 1; - } - - // row, column, or cell selection - var lastClickedRow; - if (inArray(selTarget, ['row', 'row+column'])) { - var selectedRows = function() { - var rows = table.rows('.' + selClass); - var idx = rows.indexes().toArray(); - if (!server) return addOne(idx); - idx = idx.map(function(i) { - return DT_rows_current[i]; - }); - selected1 = selMode === 'multiple' ? unique(selected1.concat(idx)) : idx; - return selected1; - } - table.on('mousedown.dt', 'tbody tr', function(e) { - var $this = $(this), thisRow = table.row(this); - if (selMode === 'multiple') { - if (e.shiftKey && lastClickedRow !== undefined) { - // select or de-select depends on the last clicked row's status - var flagSel = !$this.hasClass(selClass); - var crtClickedRow = serverRowIndex(thisRow.index()); - if (server) { - var rowsIndex = shiftSelRowsIndex(lastClickedRow, crtClickedRow); - // update current page's selClass - rowsIndex.map(function(i) { - var rowIndex = DT_rows_current.indexOf(i); - if (rowIndex >= 0) { - var row = table.row(rowIndex).nodes().to$(); - var flagRowSel = !row.hasClass(selClass); - if (flagSel === flagRowSel) row.toggleClass(selClass); - } - }); - // update selected1 - if (flagSel) { - selected1 = unique(selected1.concat(rowsIndex)); - } else { - selected1 = selected1.filter(function(index) { - return !inArray(index, rowsIndex); - }); - } - } else { - // js starts from 0 - shiftSelRowsIndex(lastClickedRow - 1, crtClickedRow - 1).map(function(value) { - var row = table.row(value).nodes().to$(); - var flagRowSel = !row.hasClass(selClass); - if (flagSel === flagRowSel) row.toggleClass(selClass); - }); - } - e.preventDefault(); - } else { - $this.toggleClass(selClass); - } - } else { - if ($this.hasClass(selClass)) { - $this.removeClass(selClass); - } else { - table.$('tr.' + selClass).removeClass(selClass); - $this.addClass(selClass); - } - } - if (server && !$this.hasClass(selClass)) { - var id = DT_rows_current[thisRow.index()]; - // remove id from selected1 since its class .selected has been removed - if (inArray(id, selected1)) selected1.splice($.inArray(id, selected1), 1); - } - changeInput('rows_selected', selectedRows()); - changeInput('row_last_clicked', serverRowIndex(thisRow.index())); - lastClickedRow = serverRowIndex(thisRow.index()); - }); - changeInput('rows_selected', selected1); - var selectRows = function() { - table.$('tr.' + selClass).removeClass(selClass); - if (selected1.length === 0) return; - if (server) { - table.rows({page: 'current'}).every(function() { - if (inArray(DT_rows_current[this.index()], selected1)) { - $(this.node()).addClass(selClass); - } - }); - } else { - var selected0 = selected1.map(function(i) { return i - 1; }); - $(table.rows(selected0).nodes()).addClass(selClass); - } - } - selectRows(); // in case users have specified pre-selected rows - // restore selected rows after the table is redrawn (e.g. sort/search/page); - // client-side tables will preserve the selections automatically; for - // server-side tables, we have to *real* row indices are in `selected1` - if (server) table.on('draw.dt', selectRows); - methods.selectRows = function(selected) { - selected1 = $.makeArray(selected); - selectRows(); - changeInput('rows_selected', selected1); - } - } - - if (inArray(selTarget, ['column', 'row+column'])) { - if (selTarget === 'row+column') { - $(table.columns().footer()).css('cursor', 'pointer'); - } - table.on('click.dt', selTarget === 'column' ? 'tbody td' : 'tfoot tr th', function() { - var colIdx = selTarget === 'column' ? table.cell(this).index().column : - $.inArray(this, table.columns().footer()), - thisCol = $(table.column(colIdx).nodes()); - if (colIdx === -1) return; - if (thisCol.hasClass(selClass)) { - thisCol.removeClass(selClass); - selected2.splice($.inArray(colIdx, selected2), 1); - } else { - if (selMode === 'single') $(table.cells().nodes()).removeClass(selClass); - thisCol.addClass(selClass); - selected2 = selMode === 'single' ? [colIdx] : unique(selected2.concat([colIdx])); - } - changeInput('columns_selected', selected2); - }); - changeInput('columns_selected', selected2); - var selectCols = function() { - table.columns().nodes().flatten().to$().removeClass(selClass); - if (selected2.length > 0) - table.columns(selected2).nodes().flatten().to$().addClass(selClass); - } - selectCols(); // in case users have specified pre-selected columns - if (server) table.on('draw.dt', selectCols); - methods.selectColumns = function(selected) { - selected2 = $.makeArray(selected); - selectCols(); - changeInput('columns_selected', selected2); - } - } - - if (selTarget === 'cell') { - var selected3; - if (selected === null) { - selected3 = []; - } else { - selected3 = selected; - } - var findIndex = function(ij) { - for (var i = 0; i < selected3.length; i++) { - if (ij[0] === selected3[i][0] && ij[1] === selected3[i][1]) return i; - } - return -1; - } - table.on('click.dt', 'tbody td', function() { - var $this = $(this), info = tweakCellIndex(table.cell(this)); - if ($this.hasClass(selClass)) { - $this.removeClass(selClass); - selected3.splice(findIndex([info.row, info.col]), 1); - } else { - if (selMode === 'single') $(table.cells().nodes()).removeClass(selClass); - $this.addClass(selClass); - selected3 = selMode === 'single' ? [[info.row, info.col]] : - unique(selected3.concat([[info.row, info.col]])); - } - changeInput('cells_selected', transposeArray2D(selected3), 'shiny.matrix'); - }); - changeInput('cells_selected', transposeArray2D(selected3), 'shiny.matrix'); - var selectCells = function() { - table.$('td.' + selClass).removeClass(selClass); - if (selected3.length === 0) return; - if (server) { - table.cells({page: 'current'}).every(function() { - var info = tweakCellIndex(this); - if (findIndex([info.row, info.col], selected3) > -1) - $(this.node()).addClass(selClass); - }); - } else { - selected3.map(function(ij) { - $(table.cell(ij[0] - 1, ij[1]).node()).addClass(selClass); - }); - } - }; - selectCells(); // in case users have specified pre-selected columns - if (server) table.on('draw.dt', selectCells); - methods.selectCells = function(selected) { - selected3 = selected ? selected : []; - selectCells(); - changeInput('cells_selected', transposeArray2D(selected3), 'shiny.matrix'); - } - } - } - - // expose some table info to Shiny - var updateTableInfo = function(e, settings) { - // TODO: is anyone interested in the page info? - // changeInput('page_info', table.page.info()); - var updateRowInfo = function(id, modifier) { - var idx; - if (server) { - idx = modifier.page === 'current' ? DT_rows_current : DT_rows_all; - } else { - var rows = table.rows($.extend({ - search: 'applied', - page: 'all' - }, modifier)); - idx = addOne(rows.indexes().toArray()); - } - changeInput('rows' + '_' + id, idx); - }; - updateRowInfo('current', {page: 'current'}); - updateRowInfo('all', {}); - } - table.on('draw.dt', updateTableInfo); - updateTableInfo(); - - // state info - table.on('draw.dt column-visibility.dt', function() { - changeInput('state', table.state()); - }); - changeInput('state', table.state()); - - // search info - var updateSearchInfo = function() { - changeInput('search', table.search()); - if (filterRow) changeInput('search_columns', filterRow.toArray().map(function(td) { - return $(td).find('input').first().val(); - })); - } - table.on('draw.dt', updateSearchInfo); - updateSearchInfo(); - - var cellInfo = function(thiz) { - var info = tweakCellIndex(table.cell(thiz)); - info.value = table.cell(thiz).data(); - return info; - } - // the current cell clicked on - table.on('click.dt', 'tbody td', function() { - changeInput('cell_clicked', cellInfo(this)); - }) - changeInput('cell_clicked', {}); - - // do not trigger table selection when clicking on links unless they have classes - table.on('click.dt', 'tbody td a', function(e) { - if (this.className === '') e.stopPropagation(); - }); - - methods.addRow = function(data, rowname) { - var data0 = table.row(0).data(), n = data0.length, d = n - data.length; - if (d === 1) { - data = rowname.concat(data) - } else if (d !== 0) { - console.log(data); - console.log(data0); - throw 'New data must be of the same length as current data (' + n + ')'; - }; - table.row.add(data).draw(); - } - - methods.updateSearch = function(keywords) { - if (keywords.global !== null) - $(table.table().container()).find('input[type=search]').first() - .val(keywords.global).trigger('input'); - var columns = keywords.columns; - if (!filterRow || columns === null) return; - filterRow.toArray().map(function(td, i) { - var v = typeof columns === 'string' ? columns : columns[i]; - if (typeof v === 'undefined') { - console.log('The search keyword for column ' + i + ' is undefined') - return; - } - $(td).find('input').first().val(v); - searchColumn(i, v); - }); - table.draw(); - } - - methods.hideCols = function(hide, reset) { - if (reset) table.columns().visible(true, false); - table.columns(hide).visible(false); - } - - methods.showCols = function(show, reset) { - if (reset) table.columns().visible(false, false); - table.columns(show).visible(true); - } - - methods.colReorder = function(order, origOrder) { - table.colReorder.order(order, origOrder); - } - - methods.selectPage = function(page) { - if (table.page.info().pages < page || page < 1) { - throw 'Selected page is out of range'; - }; - table.page(page - 1).draw(false); - } - - methods.reloadData = function(resetPaging, clearSelection) { - // empty selections first if necessary - if (methods.selectRows && inArray('row', clearSelection)) methods.selectRows([]); - if (methods.selectColumns && inArray('column', clearSelection)) methods.selectColumns([]); - if (methods.selectCells && inArray('cell', clearSelection)) methods.selectCells([]); - table.ajax.reload(null, resetPaging); - } - - table.shinyMethods = methods; - }, - resize: function(el, width, height, instance) { - if (instance.data) this.renderValue(el, instance.data, instance); - - // dynamically adjust height if fillContainer = TRUE - if (instance.fillContainer) - this.fillAvailableHeight(el, height); - - this.adjustWidth(el); - }, - - // dynamically set the scroll body to fill available height - // (used with fillContainer = TRUE) - fillAvailableHeight: function(el, availableHeight) { - - // see how much of the table is occupied by header/footer elements - // and use that to compute a target scroll body height - var dtWrapper = $(el).find('div.dataTables_wrapper'); - var dtScrollBody = $(el).find($('div.dataTables_scrollBody')); - var framingHeight = dtWrapper.innerHeight() - dtScrollBody.innerHeight(); - var scrollBodyHeight = availableHeight - framingHeight; - - // set the height - dtScrollBody.height(scrollBodyHeight + 'px'); - }, - - // adjust the width of columns; remove the hard-coded widths on table and the - // scroll header when scrollX/Y are enabled - adjustWidth: function(el) { - var $el = $(el), table = $el.data('datatable'); - if (table) table.columns.adjust(); - $el.find('.dataTables_scrollHeadInner').css('width', '') - .children('table').css('margin-left', ''); - } -}); - - if (!HTMLWidgets.shinyMode) return; - - Shiny.addCustomMessageHandler('datatable-calls', function(data) { - var id = data.id; - var el = document.getElementById(id); - var table = el ? $(el).data('datatable') : null; - if (!table) { - console.log("Couldn't find table with id " + id); - return; - } - - var methods = table.shinyMethods, call = data.call; - if (methods[call.method]) { - methods[call.method].apply(table, call.args); - } else { - console.log("Unknown method " + call.method); - } - }); - -})(); diff --git a/develop_test/libs/datatables-css-0.0.0/datatables-crosstalk.css b/develop_test/libs/datatables-css-0.0.0/datatables-crosstalk.css deleted file mode 100644 index 43422d252..000000000 --- a/develop_test/libs/datatables-css-0.0.0/datatables-crosstalk.css +++ /dev/null @@ -1,7 +0,0 @@ -.dt-crosstalk-fade { - opacity: 0.2; -} - -html body div.DTS div.dataTables_scrollBody { - background: none; -} diff --git a/develop_test/libs/dt-core-1.10.16/css/jquery.dataTables.extra.css b/develop_test/libs/dt-core-1.10.16/css/jquery.dataTables.extra.css deleted file mode 100644 index dbbac6ddd..000000000 --- a/develop_test/libs/dt-core-1.10.16/css/jquery.dataTables.extra.css +++ /dev/null @@ -1,8 +0,0 @@ -/* Selected rows/cells */ -table.dataTable tr.selected td, table.dataTable td.selected { - background-color: #b0bed9 !important; -} -/* In case of scrollX/Y or FixedHeader */ -.dataTables_scrollBody .dataTables_sizing { - visibility: hidden; -} diff --git a/develop_test/libs/dt-core-1.10.16/css/jquery.dataTables.min.css b/develop_test/libs/dt-core-1.10.16/css/jquery.dataTables.min.css deleted file mode 100644 index 71ae98a41..000000000 --- a/develop_test/libs/dt-core-1.10.16/css/jquery.dataTables.min.css +++ /dev/null @@ -1 +0,0 @@ -table.dataTable{width:100%;margin:0 auto;clear:both;border-collapse:separate;border-spacing:0}table.dataTable thead th,table.dataTable tfoot th{font-weight:bold}table.dataTable thead th,table.dataTable thead td{padding:10px 18px;border-bottom:1px solid #111}table.dataTable thead th:active,table.dataTable thead td:active{outline:none}table.dataTable tfoot th,table.dataTable tfoot td{padding:10px 18px 6px 18px;border-top:1px solid #111}table.dataTable thead .sorting,table.dataTable thead .sorting_asc,table.dataTable thead .sorting_desc,table.dataTable thead .sorting_asc_disabled,table.dataTable thead .sorting_desc_disabled{cursor:pointer;*cursor:hand;background-repeat:no-repeat;background-position:center right}table.dataTable thead .sorting{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAQAAADYWf5HAAAAkElEQVQoz7XQMQ5AQBCF4dWQSJxC5wwax1Cq1e7BAdxD5SL+Tq/QCM1oNiJidwox0355mXnG/DrEtIQ6azioNZQxI0ykPhTQIwhCR+BmBYtlK7kLJYwWCcJA9M4qdrZrd8pPjZWPtOqdRQy320YSV17OatFC4euts6z39GYMKRPCTKY9UnPQ6P+GtMRfGtPnBCiqhAeJPmkqAAAAAElFTkSuQmCC)}table.dataTable thead .sorting_asc{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAYAAAByUDbMAAAAZ0lEQVQ4y2NgGLKgquEuFxBPAGI2ahhWCsS/gDibUoO0gPgxEP8H4ttArEyuQYxAPBdqEAxPBImTY5gjEL9DM+wTENuQahAvEO9DMwiGdwAxOymGJQLxTyD+jgWDxCMZRsEoGAVoAADeemwtPcZI2wAAAABJRU5ErkJggg==)}table.dataTable thead .sorting_desc{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAYAAAByUDbMAAAAZUlEQVQ4y2NgGAWjYBSggaqGu5FA/BOIv2PBIPFEUgxjB+IdQPwfC94HxLykus4GiD+hGfQOiB3J8SojEE9EM2wuSJzcsFMG4ttQgx4DsRalkZENxL+AuJQaMcsGxBOAmGvopk8AVz1sLZgg0bsAAAAASUVORK5CYII=)}table.dataTable thead .sorting_asc_disabled{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAQAAADYWf5HAAAAW0lEQVQoz2NgoCm4w3Vnwh02wspK7/y6k01Ikdadx3f+37l9RxmfIsY7c4GKQHDiHUbcyhzvvIMq+3THBpci3jv7oIpAcMcdduzKEu/8vPMdDn/eiWQYBYMKAAC3ykIEuYQJUgAAAABJRU5ErkJggg==)}table.dataTable thead .sorting_desc_disabled{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAQAAADYWf5HAAAAWUlEQVQoz2NgGAWDCtyJvPPzznc4/HknEbsy9js77vyHw313eHGZZ3PnE1TRuzuOuK1lvDMRqmzuHUZ87lO+cxuo6PEdLUIeyb7z604pYf+y3Zlwh4u2YQoAc7ZCBHH4jigAAAAASUVORK5CYII=)}table.dataTable tbody tr{background-color:#ffffff}table.dataTable tbody tr.selected{background-color:#B0BED9}table.dataTable tbody th,table.dataTable tbody td{padding:8px 10px}table.dataTable.row-border tbody th,table.dataTable.row-border tbody td,table.dataTable.display tbody th,table.dataTable.display tbody td{border-top:1px solid #ddd}table.dataTable.row-border tbody tr:first-child th,table.dataTable.row-border tbody tr:first-child td,table.dataTable.display tbody tr:first-child th,table.dataTable.display tbody tr:first-child td{border-top:none}table.dataTable.cell-border tbody th,table.dataTable.cell-border tbody td{border-top:1px solid #ddd;border-right:1px solid #ddd}table.dataTable.cell-border tbody tr th:first-child,table.dataTable.cell-border tbody tr td:first-child{border-left:1px solid #ddd}table.dataTable.cell-border tbody tr:first-child th,table.dataTable.cell-border tbody tr:first-child td{border-top:none}table.dataTable.stripe tbody tr.odd,table.dataTable.display tbody tr.odd{background-color:#f9f9f9}table.dataTable.stripe tbody tr.odd.selected,table.dataTable.display tbody tr.odd.selected{background-color:#acbad4}table.dataTable.hover tbody tr:hover,table.dataTable.display tbody tr:hover{background-color:#f6f6f6}table.dataTable.hover tbody tr:hover.selected,table.dataTable.display tbody tr:hover.selected{background-color:#aab7d1}table.dataTable.order-column tbody tr>.sorting_1,table.dataTable.order-column tbody tr>.sorting_2,table.dataTable.order-column tbody tr>.sorting_3,table.dataTable.display tbody tr>.sorting_1,table.dataTable.display tbody tr>.sorting_2,table.dataTable.display tbody tr>.sorting_3{background-color:#fafafa}table.dataTable.order-column tbody tr.selected>.sorting_1,table.dataTable.order-column tbody tr.selected>.sorting_2,table.dataTable.order-column tbody tr.selected>.sorting_3,table.dataTable.display tbody tr.selected>.sorting_1,table.dataTable.display tbody tr.selected>.sorting_2,table.dataTable.display tbody tr.selected>.sorting_3{background-color:#acbad5}table.dataTable.display tbody tr.odd>.sorting_1,table.dataTable.order-column.stripe tbody tr.odd>.sorting_1{background-color:#f1f1f1}table.dataTable.display tbody tr.odd>.sorting_2,table.dataTable.order-column.stripe tbody tr.odd>.sorting_2{background-color:#f3f3f3}table.dataTable.display tbody tr.odd>.sorting_3,table.dataTable.order-column.stripe tbody tr.odd>.sorting_3{background-color:whitesmoke}table.dataTable.display tbody tr.odd.selected>.sorting_1,table.dataTable.order-column.stripe tbody tr.odd.selected>.sorting_1{background-color:#a6b4cd}table.dataTable.display tbody tr.odd.selected>.sorting_2,table.dataTable.order-column.stripe tbody tr.odd.selected>.sorting_2{background-color:#a8b5cf}table.dataTable.display tbody tr.odd.selected>.sorting_3,table.dataTable.order-column.stripe tbody tr.odd.selected>.sorting_3{background-color:#a9b7d1}table.dataTable.display tbody tr.even>.sorting_1,table.dataTable.order-column.stripe tbody tr.even>.sorting_1{background-color:#fafafa}table.dataTable.display tbody tr.even>.sorting_2,table.dataTable.order-column.stripe tbody tr.even>.sorting_2{background-color:#fcfcfc}table.dataTable.display tbody tr.even>.sorting_3,table.dataTable.order-column.stripe tbody tr.even>.sorting_3{background-color:#fefefe}table.dataTable.display tbody tr.even.selected>.sorting_1,table.dataTable.order-column.stripe tbody tr.even.selected>.sorting_1{background-color:#acbad5}table.dataTable.display tbody tr.even.selected>.sorting_2,table.dataTable.order-column.stripe tbody tr.even.selected>.sorting_2{background-color:#aebcd6}table.dataTable.display tbody tr.even.selected>.sorting_3,table.dataTable.order-column.stripe tbody tr.even.selected>.sorting_3{background-color:#afbdd8}table.dataTable.display tbody tr:hover>.sorting_1,table.dataTable.order-column.hover tbody tr:hover>.sorting_1{background-color:#eaeaea}table.dataTable.display tbody tr:hover>.sorting_2,table.dataTable.order-column.hover tbody tr:hover>.sorting_2{background-color:#ececec}table.dataTable.display tbody tr:hover>.sorting_3,table.dataTable.order-column.hover tbody tr:hover>.sorting_3{background-color:#efefef}table.dataTable.display tbody tr:hover.selected>.sorting_1,table.dataTable.order-column.hover tbody tr:hover.selected>.sorting_1{background-color:#a2aec7}table.dataTable.display tbody tr:hover.selected>.sorting_2,table.dataTable.order-column.hover tbody tr:hover.selected>.sorting_2{background-color:#a3b0c9}table.dataTable.display tbody tr:hover.selected>.sorting_3,table.dataTable.order-column.hover tbody tr:hover.selected>.sorting_3{background-color:#a5b2cb}table.dataTable.no-footer{border-bottom:1px solid #111}table.dataTable.nowrap th,table.dataTable.nowrap td{white-space:nowrap}table.dataTable.compact thead th,table.dataTable.compact thead td{padding:4px 17px 4px 4px}table.dataTable.compact tfoot th,table.dataTable.compact tfoot td{padding:4px}table.dataTable.compact tbody th,table.dataTable.compact tbody td{padding:4px}table.dataTable th.dt-left,table.dataTable td.dt-left{text-align:left}table.dataTable th.dt-center,table.dataTable td.dt-center,table.dataTable td.dataTables_empty{text-align:center}table.dataTable th.dt-right,table.dataTable td.dt-right{text-align:right}table.dataTable th.dt-justify,table.dataTable td.dt-justify{text-align:justify}table.dataTable th.dt-nowrap,table.dataTable td.dt-nowrap{white-space:nowrap}table.dataTable thead th.dt-head-left,table.dataTable thead td.dt-head-left,table.dataTable tfoot th.dt-head-left,table.dataTable tfoot td.dt-head-left{text-align:left}table.dataTable thead th.dt-head-center,table.dataTable thead td.dt-head-center,table.dataTable tfoot th.dt-head-center,table.dataTable tfoot td.dt-head-center{text-align:center}table.dataTable thead th.dt-head-right,table.dataTable thead td.dt-head-right,table.dataTable tfoot th.dt-head-right,table.dataTable tfoot td.dt-head-right{text-align:right}table.dataTable thead th.dt-head-justify,table.dataTable thead td.dt-head-justify,table.dataTable tfoot th.dt-head-justify,table.dataTable tfoot td.dt-head-justify{text-align:justify}table.dataTable thead th.dt-head-nowrap,table.dataTable thead td.dt-head-nowrap,table.dataTable tfoot th.dt-head-nowrap,table.dataTable tfoot td.dt-head-nowrap{white-space:nowrap}table.dataTable tbody th.dt-body-left,table.dataTable tbody td.dt-body-left{text-align:left}table.dataTable tbody th.dt-body-center,table.dataTable tbody td.dt-body-center{text-align:center}table.dataTable tbody th.dt-body-right,table.dataTable tbody td.dt-body-right{text-align:right}table.dataTable tbody th.dt-body-justify,table.dataTable tbody td.dt-body-justify{text-align:justify}table.dataTable tbody th.dt-body-nowrap,table.dataTable tbody td.dt-body-nowrap{white-space:nowrap}table.dataTable,table.dataTable th,table.dataTable td{box-sizing:content-box}.dataTables_wrapper{position:relative;clear:both;*zoom:1;zoom:1}.dataTables_wrapper .dataTables_length{float:left}.dataTables_wrapper .dataTables_filter{float:right;text-align:right}.dataTables_wrapper .dataTables_filter input{margin-left:0.5em}.dataTables_wrapper .dataTables_info{clear:both;float:left;padding-top:0.755em}.dataTables_wrapper .dataTables_paginate{float:right;text-align:right;padding-top:0.25em}.dataTables_wrapper .dataTables_paginate .paginate_button{box-sizing:border-box;display:inline-block;min-width:1.5em;padding:0.5em 1em;margin-left:2px;text-align:center;text-decoration:none !important;cursor:pointer;*cursor:hand;color:#333 !important;border:1px solid transparent;border-radius:2px}.dataTables_wrapper .dataTables_paginate .paginate_button.current,.dataTables_wrapper .dataTables_paginate .paginate_button.current:hover{color:#333 !important;border:1px solid #979797;background-color:white;background:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #fff), color-stop(100%, #dcdcdc));background:-webkit-linear-gradient(top, #fff 0%, #dcdcdc 100%);background:-moz-linear-gradient(top, #fff 0%, #dcdcdc 100%);background:-ms-linear-gradient(top, #fff 0%, #dcdcdc 100%);background:-o-linear-gradient(top, #fff 0%, #dcdcdc 100%);background:linear-gradient(to bottom, #fff 0%, #dcdcdc 100%)}.dataTables_wrapper .dataTables_paginate .paginate_button.disabled,.dataTables_wrapper .dataTables_paginate .paginate_button.disabled:hover,.dataTables_wrapper .dataTables_paginate .paginate_button.disabled:active{cursor:default;color:#666 !important;border:1px solid transparent;background:transparent;box-shadow:none}.dataTables_wrapper .dataTables_paginate .paginate_button:hover{color:white !important;border:1px solid #111;background-color:#585858;background:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #585858), color-stop(100%, #111));background:-webkit-linear-gradient(top, #585858 0%, #111 100%);background:-moz-linear-gradient(top, #585858 0%, #111 100%);background:-ms-linear-gradient(top, #585858 0%, #111 100%);background:-o-linear-gradient(top, #585858 0%, #111 100%);background:linear-gradient(to bottom, #585858 0%, #111 100%)}.dataTables_wrapper .dataTables_paginate .paginate_button:active{outline:none;background-color:#2b2b2b;background:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #2b2b2b), color-stop(100%, #0c0c0c));background:-webkit-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:-moz-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:-ms-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:-o-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:linear-gradient(to bottom, #2b2b2b 0%, #0c0c0c 100%);box-shadow:inset 0 0 3px #111}.dataTables_wrapper .dataTables_paginate .ellipsis{padding:0 1em}.dataTables_wrapper .dataTables_processing{position:absolute;top:50%;left:50%;width:100%;height:40px;margin-left:-50%;margin-top:-25px;padding-top:20px;text-align:center;font-size:1.2em;background-color:white;background:-webkit-gradient(linear, left top, right top, color-stop(0%, rgba(255,255,255,0)), color-stop(25%, rgba(255,255,255,0.9)), color-stop(75%, rgba(255,255,255,0.9)), color-stop(100%, rgba(255,255,255,0)));background:-webkit-linear-gradient(left, rgba(255,255,255,0) 0%, rgba(255,255,255,0.9) 25%, rgba(255,255,255,0.9) 75%, rgba(255,255,255,0) 100%);background:-moz-linear-gradient(left, rgba(255,255,255,0) 0%, rgba(255,255,255,0.9) 25%, rgba(255,255,255,0.9) 75%, rgba(255,255,255,0) 100%);background:-ms-linear-gradient(left, rgba(255,255,255,0) 0%, rgba(255,255,255,0.9) 25%, rgba(255,255,255,0.9) 75%, rgba(255,255,255,0) 100%);background:-o-linear-gradient(left, rgba(255,255,255,0) 0%, rgba(255,255,255,0.9) 25%, rgba(255,255,255,0.9) 75%, rgba(255,255,255,0) 100%);background:linear-gradient(to right, rgba(255,255,255,0) 0%, rgba(255,255,255,0.9) 25%, rgba(255,255,255,0.9) 75%, rgba(255,255,255,0) 100%)}.dataTables_wrapper .dataTables_length,.dataTables_wrapper .dataTables_filter,.dataTables_wrapper .dataTables_info,.dataTables_wrapper .dataTables_processing,.dataTables_wrapper .dataTables_paginate{color:#333}.dataTables_wrapper .dataTables_scroll{clear:both}.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody{*margin-top:-1px;-webkit-overflow-scrolling:touch}.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>thead>tr>th,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>thead>tr>td,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>tbody>tr>th,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>tbody>tr>td{vertical-align:middle}.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>thead>tr>th>div.dataTables_sizing,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>thead>tr>td>div.dataTables_sizing,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>tbody>tr>th>div.dataTables_sizing,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>tbody>tr>td>div.dataTables_sizing{height:0;overflow:hidden;margin:0 !important;padding:0 !important}.dataTables_wrapper.no-footer .dataTables_scrollBody{border-bottom:1px solid #111}.dataTables_wrapper.no-footer div.dataTables_scrollHead table.dataTable,.dataTables_wrapper.no-footer div.dataTables_scrollBody>table{border-bottom:none}.dataTables_wrapper:after{visibility:hidden;display:block;content:"";clear:both;height:0}@media screen and (max-width: 767px){.dataTables_wrapper .dataTables_info,.dataTables_wrapper .dataTables_paginate{float:none;text-align:center}.dataTables_wrapper .dataTables_paginate{margin-top:0.5em}}@media screen and (max-width: 640px){.dataTables_wrapper .dataTables_length,.dataTables_wrapper .dataTables_filter{float:none;text-align:center}.dataTables_wrapper .dataTables_filter{margin-top:0.5em}} diff --git a/develop_test/libs/dt-core-1.10.16/js/jquery.dataTables.min.js b/develop_test/libs/dt-core-1.10.16/js/jquery.dataTables.min.js deleted file mode 100644 index 162da3478..000000000 --- a/develop_test/libs/dt-core-1.10.16/js/jquery.dataTables.min.js +++ /dev/null @@ -1,164 +0,0 @@ -/*! - DataTables 1.10.16 - ©2008-2017 SpryMedia Ltd - datatables.net/license -*/ -(function(h){"function"===typeof define&&define.amd?define(["jquery"],function(E){return h(E,window,document)}):"object"===typeof exports?module.exports=function(E,G){E||(E=window);G||(G="undefined"!==typeof window?require("jquery"):require("jquery")(E));return h(G,E,E.document)}:h(jQuery,window,document)})(function(h,E,G,k){function X(a){var b,c,d={};h.each(a,function(e){if((b=e.match(/^([^A-Z]+?)([A-Z])/))&&-1!=="a aa ai ao as b fn i m o s ".indexOf(b[1]+" "))c=e.replace(b[0],b[2].toLowerCase()), -d[c]=e,"o"===b[1]&&X(a[e])});a._hungarianMap=d}function I(a,b,c){a._hungarianMap||X(a);var d;h.each(b,function(e){d=a._hungarianMap[e];if(d!==k&&(c||b[d]===k))"o"===d.charAt(0)?(b[d]||(b[d]={}),h.extend(!0,b[d],b[e]),I(a[d],b[d],c)):b[d]=b[e]})}function Ca(a){var b=m.defaults.oLanguage,c=a.sZeroRecords;!a.sEmptyTable&&(c&&"No data available in table"===b.sEmptyTable)&&F(a,a,"sZeroRecords","sEmptyTable");!a.sLoadingRecords&&(c&&"Loading..."===b.sLoadingRecords)&&F(a,a,"sZeroRecords","sLoadingRecords"); -a.sInfoThousands&&(a.sThousands=a.sInfoThousands);(a=a.sDecimal)&&cb(a)}function db(a){A(a,"ordering","bSort");A(a,"orderMulti","bSortMulti");A(a,"orderClasses","bSortClasses");A(a,"orderCellsTop","bSortCellsTop");A(a,"order","aaSorting");A(a,"orderFixed","aaSortingFixed");A(a,"paging","bPaginate");A(a,"pagingType","sPaginationType");A(a,"pageLength","iDisplayLength");A(a,"searching","bFilter");"boolean"===typeof a.sScrollX&&(a.sScrollX=a.sScrollX?"100%":"");"boolean"===typeof a.scrollX&&(a.scrollX= -a.scrollX?"100%":"");if(a=a.aoSearchCols)for(var b=0,c=a.length;b").css({position:"fixed",top:0,left:-1*h(E).scrollLeft(),height:1,width:1,overflow:"hidden"}).append(h("
").css({position:"absolute", -top:1,left:1,width:100,overflow:"scroll"}).append(h("
").css({width:"100%",height:10}))).appendTo("body"),d=c.children(),e=d.children();b.barWidth=d[0].offsetWidth-d[0].clientWidth;b.bScrollOversize=100===e[0].offsetWidth&&100!==d[0].clientWidth;b.bScrollbarLeft=1!==Math.round(e.offset().left);b.bBounding=c[0].getBoundingClientRect().width?!0:!1;c.remove()}h.extend(a.oBrowser,m.__browser);a.oScroll.iBarWidth=m.__browser.barWidth}function gb(a,b,c,d,e,f){var g,j=!1;c!==k&&(g=c,j=!0);for(;d!== -e;)a.hasOwnProperty(d)&&(g=j?b(g,a[d],d,a):a[d],j=!0,d+=f);return g}function Da(a,b){var c=m.defaults.column,d=a.aoColumns.length,c=h.extend({},m.models.oColumn,c,{nTh:b?b:G.createElement("th"),sTitle:c.sTitle?c.sTitle:b?b.innerHTML:"",aDataSort:c.aDataSort?c.aDataSort:[d],mData:c.mData?c.mData:d,idx:d});a.aoColumns.push(c);c=a.aoPreSearchCols;c[d]=h.extend({},m.models.oSearch,c[d]);ja(a,d,h(b).data())}function ja(a,b,c){var b=a.aoColumns[b],d=a.oClasses,e=h(b.nTh);if(!b.sWidthOrig){b.sWidthOrig= -e.attr("width")||null;var f=(e.attr("style")||"").match(/width:\s*(\d+[pxem%]+)/);f&&(b.sWidthOrig=f[1])}c!==k&&null!==c&&(eb(c),I(m.defaults.column,c),c.mDataProp!==k&&!c.mData&&(c.mData=c.mDataProp),c.sType&&(b._sManualType=c.sType),c.className&&!c.sClass&&(c.sClass=c.className),c.sClass&&e.addClass(c.sClass),h.extend(b,c),F(b,c,"sWidth","sWidthOrig"),c.iDataSort!==k&&(b.aDataSort=[c.iDataSort]),F(b,c,"aDataSort"));var g=b.mData,j=Q(g),i=b.mRender?Q(b.mRender):null,c=function(a){return"string"=== -typeof a&&-1!==a.indexOf("@")};b._bAttrSrc=h.isPlainObject(g)&&(c(g.sort)||c(g.type)||c(g.filter));b._setter=null;b.fnGetData=function(a,b,c){var d=j(a,b,k,c);return i&&b?i(d,b,a,c):d};b.fnSetData=function(a,b,c){return R(g)(a,b,c)};"number"!==typeof g&&(a._rowReadObject=!0);a.oFeatures.bSort||(b.bSortable=!1,e.addClass(d.sSortableNone));a=-1!==h.inArray("asc",b.asSorting);c=-1!==h.inArray("desc",b.asSorting);!b.bSortable||!a&&!c?(b.sSortingClass=d.sSortableNone,b.sSortingClassJUI=""):a&&!c?(b.sSortingClass= -d.sSortableAsc,b.sSortingClassJUI=d.sSortJUIAscAllowed):!a&&c?(b.sSortingClass=d.sSortableDesc,b.sSortingClassJUI=d.sSortJUIDescAllowed):(b.sSortingClass=d.sSortable,b.sSortingClassJUI=d.sSortJUI)}function Y(a){if(!1!==a.oFeatures.bAutoWidth){var b=a.aoColumns;Ea(a);for(var c=0,d=b.length;cq[f])d(l.length+q[f],n);else if("string"===typeof q[f]){j=0;for(i=l.length;j< -i;j++)("_all"==q[f]||h(l[j].nTh).hasClass(q[f]))&&d(j,n)}}if(c){e=0;for(a=c.length;eb&&a[e]--; -1!=d&&c===k&&a.splice(d,1)}function ca(a,b,c,d){var e=a.aoData[b],f,g=function(c,d){for(;c.childNodes.length;)c.removeChild(c.firstChild); -c.innerHTML=B(a,b,d,"display")};if("dom"===c||(!c||"auto"===c)&&"dom"===e.src)e._aData=Ha(a,e,d,d===k?k:e._aData).data;else{var j=e.anCells;if(j)if(d!==k)g(j[d],d);else{c=0;for(f=j.length;c").appendTo(g));b=0;for(c=l.length;btr").attr("role","row");h(g).find(">tr>th, >tr>td").addClass(n.sHeaderTH);h(j).find(">tr>th, >tr>td").addClass(n.sFooterTH); -if(null!==j){a=a.aoFooter[0];b=0;for(c=a.length;b=a.fnRecordsDisplay()?0:g,a.iInitDisplayStart= --1);var g=a._iDisplayStart,n=a.fnDisplayEnd();if(a.bDeferLoading)a.bDeferLoading=!1,a.iDraw++,C(a,!1);else if(j){if(!a.bDestroying&&!kb(a))return}else a.iDraw++;if(0!==i.length){f=j?a.aoData.length:n;for(j=j?0:g;j",{"class":e?d[0]:""}).append(h("",{valign:"top",colSpan:aa(a),"class":a.oClasses.sRowEmpty}).html(c))[0];r(a,"aoHeaderCallback","header",[h(a.nTHead).children("tr")[0],Ja(a),g,n,i]);r(a,"aoFooterCallback","footer",[h(a.nTFoot).children("tr")[0],Ja(a),g,n,i]);d=h(a.nTBody);d.children().detach();d.append(h(b));r(a,"aoDrawCallback","draw",[a]);a.bSorted=!1;a.bFiltered=!1;a.bDrawing=!1}}function S(a,b){var c=a.oFeatures,d=c.bFilter; -c.bSort&&lb(a);d?fa(a,a.oPreviousSearch):a.aiDisplay=a.aiDisplayMaster.slice();!0!==b&&(a._iDisplayStart=0);a._drawHold=b;N(a);a._drawHold=!1}function mb(a){var b=a.oClasses,c=h(a.nTable),c=h("
").insertBefore(c),d=a.oFeatures,e=h("
",{id:a.sTableId+"_wrapper","class":b.sWrapper+(a.nTFoot?"":" "+b.sNoFooter)});a.nHolding=c[0];a.nTableWrapper=e[0];a.nTableReinsertBefore=a.nTable.nextSibling;for(var f=a.sDom.split(""),g,j,i,n,l,q,k=0;k")[0]; -n=f[k+1];if("'"==n||'"'==n){l="";for(q=2;f[k+q]!=n;)l+=f[k+q],q++;"H"==l?l=b.sJUIHeader:"F"==l&&(l=b.sJUIFooter);-1!=l.indexOf(".")?(n=l.split("."),i.id=n[0].substr(1,n[0].length-1),i.className=n[1]):"#"==l.charAt(0)?i.id=l.substr(1,l.length-1):i.className=l;k+=q}e.append(i);e=h(i)}else if(">"==j)e=e.parent();else if("l"==j&&d.bPaginate&&d.bLengthChange)g=nb(a);else if("f"==j&&d.bFilter)g=ob(a);else if("r"==j&&d.bProcessing)g=pb(a);else if("t"==j)g=qb(a);else if("i"==j&&d.bInfo)g=rb(a);else if("p"== -j&&d.bPaginate)g=sb(a);else if(0!==m.ext.feature.length){i=m.ext.feature;q=0;for(n=i.length;q',j=d.sSearch,j=j.match(/_INPUT_/)?j.replace("_INPUT_",g):j+g,b=h("
",{id:!f.f?c+"_filter":null,"class":b.sFilter}).append(h("
").addClass(b.sLength);a.aanFeatures.l||(i[0].id=c+"_length");i.children().append(a.oLanguage.sLengthMenu.replace("_MENU_",e[0].outerHTML));h("select",i).val(a._iDisplayLength).on("change.DT",function(){Qa(a,h(this).val());N(a)});h(a.nTable).on("length.dt.DT",function(b,c,d){a===c&&h("select",i).val(d)});return i[0]}function sb(a){var b=a.sPaginationType,c=m.ext.pager[b],d="function"===typeof c,e=function(a){N(a)}, -b=h("
").addClass(a.oClasses.sPaging+b)[0],f=a.aanFeatures;d||c.fnInit(a,b,e);f.p||(b.id=a.sTableId+"_paginate",a.aoDrawCallback.push({fn:function(a){if(d){var b=a._iDisplayStart,i=a._iDisplayLength,h=a.fnRecordsDisplay(),l=-1===i,b=l?0:Math.ceil(b/i),i=l?1:Math.ceil(h/i),h=c(b,i),k,l=0;for(k=f.p.length;lf&&(d=0)):"first"==b?d=0:"previous"==b?(d=0<=e?d-e:0,0>d&&(d=0)):"next"==b?d+e",{id:!a.aanFeatures.r?a.sTableId+"_processing":null,"class":a.oClasses.sProcessing}).html(a.oLanguage.sProcessing).insertBefore(a.nTable)[0]}function C(a,b){a.oFeatures.bProcessing&&h(a.aanFeatures.r).css("display", -b?"block":"none");r(a,null,"processing",[a,b])}function qb(a){var b=h(a.nTable);b.attr("role","grid");var c=a.oScroll;if(""===c.sX&&""===c.sY)return a.nTable;var d=c.sX,e=c.sY,f=a.oClasses,g=b.children("caption"),j=g.length?g[0]._captionSide:null,i=h(b[0].cloneNode(!1)),n=h(b[0].cloneNode(!1)),l=b.children("tfoot");l.length||(l=null);i=h("
",{"class":f.sScrollWrapper}).append(h("
",{"class":f.sScrollHead}).css({overflow:"hidden",position:"relative",border:0,width:d?!d?null:v(d):"100%"}).append(h("
", -{"class":f.sScrollHeadInner}).css({"box-sizing":"content-box",width:c.sXInner||"100%"}).append(i.removeAttr("id").css("margin-left",0).append("top"===j?g:null).append(b.children("thead"))))).append(h("
",{"class":f.sScrollBody}).css({position:"relative",overflow:"auto",width:!d?null:v(d)}).append(b));l&&i.append(h("
",{"class":f.sScrollFoot}).css({overflow:"hidden",border:0,width:d?!d?null:v(d):"100%"}).append(h("
",{"class":f.sScrollFootInner}).append(n.removeAttr("id").css("margin-left", -0).append("bottom"===j?g:null).append(b.children("tfoot")))));var b=i.children(),k=b[0],f=b[1],t=l?b[2]:null;if(d)h(f).on("scroll.DT",function(){var a=this.scrollLeft;k.scrollLeft=a;l&&(t.scrollLeft=a)});h(f).css(e&&c.bCollapse?"max-height":"height",e);a.nScrollHead=k;a.nScrollBody=f;a.nScrollFoot=t;a.aoDrawCallback.push({fn:ka,sName:"scrolling"});return i[0]}function ka(a){var b=a.oScroll,c=b.sX,d=b.sXInner,e=b.sY,b=b.iBarWidth,f=h(a.nScrollHead),g=f[0].style,j=f.children("div"),i=j[0].style,n=j.children("table"), -j=a.nScrollBody,l=h(j),q=j.style,t=h(a.nScrollFoot).children("div"),m=t.children("table"),o=h(a.nTHead),p=h(a.nTable),s=p[0],r=s.style,u=a.nTFoot?h(a.nTFoot):null,x=a.oBrowser,T=x.bScrollOversize,Xb=D(a.aoColumns,"nTh"),O,K,P,w,Ta=[],y=[],z=[],A=[],B,C=function(a){a=a.style;a.paddingTop="0";a.paddingBottom="0";a.borderTopWidth="0";a.borderBottomWidth="0";a.height=0};K=j.scrollHeight>j.clientHeight;if(a.scrollBarVis!==K&&a.scrollBarVis!==k)a.scrollBarVis=K,Y(a);else{a.scrollBarVis=K;p.children("thead, tfoot").remove(); -u&&(P=u.clone().prependTo(p),O=u.find("tr"),P=P.find("tr"));w=o.clone().prependTo(p);o=o.find("tr");K=w.find("tr");w.find("th, td").removeAttr("tabindex");c||(q.width="100%",f[0].style.width="100%");h.each(ra(a,w),function(b,c){B=Z(a,b);c.style.width=a.aoColumns[B].sWidth});u&&H(function(a){a.style.width=""},P);f=p.outerWidth();if(""===c){r.width="100%";if(T&&(p.find("tbody").height()>j.offsetHeight||"scroll"==l.css("overflow-y")))r.width=v(p.outerWidth()-b);f=p.outerWidth()}else""!==d&&(r.width= -v(d),f=p.outerWidth());H(C,K);H(function(a){z.push(a.innerHTML);Ta.push(v(h(a).css("width")))},K);H(function(a,b){if(h.inArray(a,Xb)!==-1)a.style.width=Ta[b]},o);h(K).height(0);u&&(H(C,P),H(function(a){A.push(a.innerHTML);y.push(v(h(a).css("width")))},P),H(function(a,b){a.style.width=y[b]},O),h(P).height(0));H(function(a,b){a.innerHTML='
'+z[b]+"
";a.style.width=Ta[b]},K);u&&H(function(a,b){a.innerHTML='
'+ -A[b]+"
";a.style.width=y[b]},P);if(p.outerWidth()j.offsetHeight||"scroll"==l.css("overflow-y")?f+b:f;if(T&&(j.scrollHeight>j.offsetHeight||"scroll"==l.css("overflow-y")))r.width=v(O-b);(""===c||""!==d)&&J(a,1,"Possible column misalignment",6)}else O="100%";q.width=v(O);g.width=v(O);u&&(a.nScrollFoot.style.width=v(O));!e&&T&&(q.height=v(s.offsetHeight+b));c=p.outerWidth();n[0].style.width=v(c);i.width=v(c);d=p.height()>j.clientHeight||"scroll"==l.css("overflow-y");e="padding"+ -(x.bScrollbarLeft?"Left":"Right");i[e]=d?b+"px":"0px";u&&(m[0].style.width=v(c),t[0].style.width=v(c),t[0].style[e]=d?b+"px":"0px");p.children("colgroup").insertBefore(p.children("thead"));l.scroll();if((a.bSorted||a.bFiltered)&&!a._drawHold)j.scrollTop=0}}function H(a,b,c){for(var d=0,e=0,f=b.length,g,j;e").appendTo(j.find("tbody")); -j.find("thead, tfoot").remove();j.append(h(a.nTHead).clone()).append(h(a.nTFoot).clone());j.find("tfoot th, tfoot td").css("width","");n=ra(a,j.find("thead")[0]);for(m=0;m").css({width:o.sWidthOrig,margin:0,padding:0,border:0,height:1}));if(a.aoData.length)for(m=0;m").css(f||e?{position:"absolute",top:0,left:0,height:1,right:0,overflow:"hidden"}:{}).append(j).appendTo(k);f&&g?j.width(g):f?(j.css("width","auto"),j.removeAttr("width"),j.width()").css("width",v(a)).appendTo(b||G.body),d=c[0].offsetWidth;c.remove();return d}function Eb(a,b){var c=Fb(a,b);if(0>c)return null;var d=a.aoData[c];return!d.nTr?h("").html(B(a,c,b,"display"))[0]:d.anCells[b]}function Fb(a,b){for(var c,d=-1,e=-1,f=0,g=a.aoData.length;fd&&(d=c.length,e=f);return e}function v(a){return null===a?"0px":"number"==typeof a?0>a?"0px":a+"px":a.match(/\d$/)?a+"px":a}function V(a){var b,c,d=[],e=a.aoColumns,f,g,j,i;b=a.aaSortingFixed;c=h.isPlainObject(b);var n=[];f=function(a){a.length&&!h.isArray(a[0])?n.push(a):h.merge(n,a)};h.isArray(b)&&f(b);c&&b.pre&&f(b.pre);f(a.aaSorting);c&&b.post&&f(b.post);for(a=0;ae?1:0,0!==c)return"asc"===j.dir?c:-c;c=d[a];e=d[b];return ce?1:0}):i.sort(function(a,b){var c,g,j,i,k=h.length,m=f[a]._aSortData,o=f[b]._aSortData;for(j=0;jg?1:0})}a.bSorted=!0}function Hb(a){for(var b,c,d=a.aoColumns,e=V(a),a=a.oLanguage.oAria,f=0,g=d.length;f/g, -"");var i=c.nTh;i.removeAttribute("aria-sort");c.bSortable&&(0e?e+1:3));e=0;for(f=d.length;ee?e+1:3))}a.aLastSort=d}function Gb(a,b){var c=a.aoColumns[b],d=m.ext.order[c.sSortDataType],e;d&&(e=d.call(a.oInstance,a,b,$(a,b)));for(var f,g=m.ext.type.order[c.sType+"-pre"],j=0,i=a.aoData.length;j=f.length?[0,c[1]]:c)}));b.search!== -k&&h.extend(a.oPreviousSearch,Ab(b.search));if(b.columns){d=0;for(e=b.columns.length;d=c&&(b=c-d);b-=b%d;if(-1===d||0>b)b=0;a._iDisplayStart=b}function Ma(a,b){var c=a.renderer,d=m.ext.renderer[b];return h.isPlainObject(c)&&c[b]?d[c[b]]||d._:"string"===typeof c?d[c]||d._:d._}function y(a){return a.oFeatures.bServerSide?"ssp":a.ajax||a.sAjaxSource?"ajax":"dom"}function ha(a,b){var c=[],c=Kb.numbers_length,d=Math.floor(c/2);b<=c?c=W(0,b):a<=d?(c=W(0, -c-2),c.push("ellipsis"),c.push(b-1)):(a>=b-1-d?c=W(b-(c-2),b):(c=W(a-d+2,a+d-1),c.push("ellipsis"),c.push(b-1)),c.splice(0,0,"ellipsis"),c.splice(0,0,0));c.DT_el="span";return c}function cb(a){h.each({num:function(b){return za(b,a)},"num-fmt":function(b){return za(b,a,Wa)},"html-num":function(b){return za(b,a,Aa)},"html-num-fmt":function(b){return za(b,a,Aa,Wa)}},function(b,c){x.type.order[b+a+"-pre"]=c;b.match(/^html\-/)&&(x.type.search[b+a]=x.type.search.html)})}function Lb(a){return function(){var b= -[ya(this[m.ext.iApiIndex])].concat(Array.prototype.slice.call(arguments));return m.ext.internal[a].apply(this,b)}}var m=function(a){this.$=function(a,b){return this.api(!0).$(a,b)};this._=function(a,b){return this.api(!0).rows(a,b).data()};this.api=function(a){return a?new s(ya(this[x.iApiIndex])):new s(this)};this.fnAddData=function(a,b){var c=this.api(!0),d=h.isArray(a)&&(h.isArray(a[0])||h.isPlainObject(a[0]))?c.rows.add(a):c.row.add(a);(b===k||b)&&c.draw();return d.flatten().toArray()};this.fnAdjustColumnSizing= -function(a){var b=this.api(!0).columns.adjust(),c=b.settings()[0],d=c.oScroll;a===k||a?b.draw(!1):(""!==d.sX||""!==d.sY)&&ka(c)};this.fnClearTable=function(a){var b=this.api(!0).clear();(a===k||a)&&b.draw()};this.fnClose=function(a){this.api(!0).row(a).child.hide()};this.fnDeleteRow=function(a,b,c){var d=this.api(!0),a=d.rows(a),e=a.settings()[0],h=e.aoData[a[0][0]];a.remove();b&&b.call(this,e,h);(c===k||c)&&d.draw();return h};this.fnDestroy=function(a){this.api(!0).destroy(a)};this.fnDraw=function(a){this.api(!0).draw(a)}; -this.fnFilter=function(a,b,c,d,e,h){e=this.api(!0);null===b||b===k?e.search(a,c,d,h):e.column(b).search(a,c,d,h);e.draw()};this.fnGetData=function(a,b){var c=this.api(!0);if(a!==k){var d=a.nodeName?a.nodeName.toLowerCase():"";return b!==k||"td"==d||"th"==d?c.cell(a,b).data():c.row(a).data()||null}return c.data().toArray()};this.fnGetNodes=function(a){var b=this.api(!0);return a!==k?b.row(a).node():b.rows().nodes().flatten().toArray()};this.fnGetPosition=function(a){var b=this.api(!0),c=a.nodeName.toUpperCase(); -return"TR"==c?b.row(a).index():"TD"==c||"TH"==c?(a=b.cell(a).index(),[a.row,a.columnVisible,a.column]):null};this.fnIsOpen=function(a){return this.api(!0).row(a).child.isShown()};this.fnOpen=function(a,b,c){return this.api(!0).row(a).child(b,c).show().child()[0]};this.fnPageChange=function(a,b){var c=this.api(!0).page(a);(b===k||b)&&c.draw(!1)};this.fnSetColumnVis=function(a,b,c){a=this.api(!0).column(a).visible(b);(c===k||c)&&a.columns.adjust().draw()};this.fnSettings=function(){return ya(this[x.iApiIndex])}; -this.fnSort=function(a){this.api(!0).order(a).draw()};this.fnSortListener=function(a,b,c){this.api(!0).order.listener(a,b,c)};this.fnUpdate=function(a,b,c,d,e){var h=this.api(!0);c===k||null===c?h.row(b).data(a):h.cell(b,c).data(a);(e===k||e)&&h.columns.adjust();(d===k||d)&&h.draw();return 0};this.fnVersionCheck=x.fnVersionCheck;var b=this,c=a===k,d=this.length;c&&(a={});this.oApi=this.internal=x.internal;for(var e in m.ext.internal)e&&(this[e]=Lb(e));this.each(function(){var e={},g=1").appendTo(q));p.nTHead=b[0];b=q.children("tbody");b.length===0&&(b=h("").appendTo(q));p.nTBody=b[0];b=q.children("tfoot");if(b.length===0&&a.length>0&&(p.oScroll.sX!==""||p.oScroll.sY!==""))b=h("").appendTo(q);if(b.length===0||b.children().length===0)q.addClass(u.sNoFooter); -else if(b.length>0){p.nTFoot=b[0];da(p.aoFooter,p.nTFoot)}if(g.aaData)for(j=0;j/g,Zb=/^\d{2,4}[\.\/\-]\d{1,2}[\.\/\-]\d{1,2}([T ]{1}\d{1,2}[:\.]\d{2}([\.:]\d{2})?)?$/,$b=RegExp("(\\/|\\.|\\*|\\+|\\?|\\||\\(|\\)|\\[|\\]|\\{|\\}|\\\\|\\$|\\^|\\-)", -"g"),Wa=/[',$£€¥%\u2009\u202F\u20BD\u20a9\u20BArfk]/gi,L=function(a){return!a||!0===a||"-"===a?!0:!1},Nb=function(a){var b=parseInt(a,10);return!isNaN(b)&&isFinite(a)?b:null},Ob=function(a,b){Xa[b]||(Xa[b]=RegExp(Pa(b),"g"));return"string"===typeof a&&"."!==b?a.replace(/\./g,"").replace(Xa[b],"."):a},Ya=function(a,b,c){var d="string"===typeof a;if(L(a))return!0;b&&d&&(a=Ob(a,b));c&&d&&(a=a.replace(Wa,""));return!isNaN(parseFloat(a))&&isFinite(a)},Pb=function(a,b,c){return L(a)?!0:!(L(a)||"string"=== -typeof a)?null:Ya(a.replace(Aa,""),b,c)?!0:null},D=function(a,b,c){var d=[],e=0,f=a.length;if(c!==k)for(;ea.length)){b=a.slice().sort();for(var c=b[0],d=1,e=b.length;d")[0],Wb=va.textContent!==k,Yb=/<.*?>/g,Na=m.util.throttle,Rb=[],w=Array.prototype,ac=function(a){var b,c,d=m.settings,e=h.map(d,function(a){return a.nTable});if(a){if(a.nTable&&a.oApi)return[a];if(a.nodeName&&"table"===a.nodeName.toLowerCase())return b=h.inArray(a,e),-1!==b?[d[b]]:null;if(a&&"function"===typeof a.settings)return a.settings().toArray();"string"===typeof a?c=h(a):a instanceof -h&&(c=a)}else return[];if(c)return c.map(function(){b=h.inArray(this,e);return-1!==b?d[b]:null}).toArray()};s=function(a,b){if(!(this instanceof s))return new s(a,b);var c=[],d=function(a){(a=ac(a))&&(c=c.concat(a))};if(h.isArray(a))for(var e=0,f=a.length;ea?new s(b[a],this[a]):null},filter:function(a){var b=[];if(w.filter)b=w.filter.call(this,a,this);else for(var c=0,d=this.length;c").addClass(b),h("td",c).addClass(b).html(a)[0].colSpan=aa(d),e.push(c[0]))};f(a,b);c._details&&c._details.detach();c._details=h(e);c._detailsShow&& -c._details.insertAfter(c.nTr)}return this});o(["row().child.show()","row().child().show()"],function(){Tb(this,!0);return this});o(["row().child.hide()","row().child().hide()"],function(){Tb(this,!1);return this});o(["row().child.remove()","row().child().remove()"],function(){bb(this);return this});o("row().child.isShown()",function(){var a=this.context;return a.length&&this.length?a[0].aoData[this[0]]._detailsShow||!1:!1});var bc=/^([^:]+):(name|visIdx|visible)$/,Ub=function(a,b,c,d,e){for(var c= -[],d=0,f=e.length;d=0?b:g.length+b];if(typeof a==="function"){var e=Ba(c,f);return h.map(g,function(b,f){return a(f,Ub(c,f,0,0,e),i[f])?f:null})}var k=typeof a==="string"?a.match(bc):"";if(k)switch(k[2]){case "visIdx":case "visible":b= -parseInt(k[1],10);if(b<0){var m=h.map(g,function(a,b){return a.bVisible?b:null});return[m[m.length+b]]}return[Z(c,b)];case "name":return h.map(j,function(a,b){return a===k[1]?b:null});default:return[]}if(a.nodeName&&a._DT_CellIndex)return[a._DT_CellIndex.column];b=h(i).filter(a).map(function(){return h.inArray(this,i)}).toArray();if(b.length||!a.nodeName)return b;b=h(a).closest("*[data-dt-column]");return b.length?[b.data("dt-column")]:[]},c,f)},1);c.selector.cols=a;c.selector.opts=b;return c});u("columns().header()", -"column().header()",function(){return this.iterator("column",function(a,b){return a.aoColumns[b].nTh},1)});u("columns().footer()","column().footer()",function(){return this.iterator("column",function(a,b){return a.aoColumns[b].nTf},1)});u("columns().data()","column().data()",function(){return this.iterator("column-rows",Ub,1)});u("columns().dataSrc()","column().dataSrc()",function(){return this.iterator("column",function(a,b){return a.aoColumns[b].mData},1)});u("columns().cache()","column().cache()", -function(a){return this.iterator("column-rows",function(b,c,d,e,f){return ia(b.aoData,f,"search"===a?"_aFilterData":"_aSortData",c)},1)});u("columns().nodes()","column().nodes()",function(){return this.iterator("column-rows",function(a,b,c,d,e){return ia(a.aoData,e,"anCells",b)},1)});u("columns().visible()","column().visible()",function(a,b){var c=this.iterator("column",function(b,c){if(a===k)return b.aoColumns[c].bVisible;var f=b.aoColumns,g=f[c],j=b.aoData,i,n,l;if(a!==k&&g.bVisible!==a){if(a){var m= -h.inArray(!0,D(f,"bVisible"),c+1);i=0;for(n=j.length;id;return!0};m.isDataTable=m.fnIsDataTable=function(a){var b=h(a).get(0),c=!1;if(a instanceof m.Api)return!0;h.each(m.settings,function(a,e){var f=e.nScrollHead?h("table",e.nScrollHead)[0]:null,g=e.nScrollFoot? -h("table",e.nScrollFoot)[0]:null;if(e.nTable===b||f===b||g===b)c=!0});return c};m.tables=m.fnTables=function(a){var b=!1;h.isPlainObject(a)&&(b=a.api,a=a.visible);var c=h.map(m.settings,function(b){if(!a||a&&h(b.nTable).is(":visible"))return b.nTable});return b?new s(c):c};m.camelToHungarian=I;o("$()",function(a,b){var c=this.rows(b).nodes(),c=h(c);return h([].concat(c.filter(a).toArray(),c.find(a).toArray()))});h.each(["on","one","off"],function(a,b){o(b+"()",function(){var a=Array.prototype.slice.call(arguments); -a[0]=h.map(a[0].split(/\s/),function(a){return!a.match(/\.dt\b/)?a+".dt":a}).join(" ");var d=h(this.tables().nodes());d[b].apply(d,a);return this})});o("clear()",function(){return this.iterator("table",function(a){na(a)})});o("settings()",function(){return new s(this.context,this.context)});o("init()",function(){var a=this.context;return a.length?a[0].oInit:null});o("data()",function(){return this.iterator("table",function(a){return D(a.aoData,"_aData")}).flatten()});o("destroy()",function(a){a=a|| -!1;return this.iterator("table",function(b){var c=b.nTableWrapper.parentNode,d=b.oClasses,e=b.nTable,f=b.nTBody,g=b.nTHead,j=b.nTFoot,i=h(e),f=h(f),k=h(b.nTableWrapper),l=h.map(b.aoData,function(a){return a.nTr}),o;b.bDestroying=!0;r(b,"aoDestroyCallback","destroy",[b]);a||(new s(b)).columns().visible(!0);k.off(".DT").find(":not(tbody *)").off(".DT");h(E).off(".DT-"+b.sInstance);e!=g.parentNode&&(i.children("thead").detach(),i.append(g));j&&e!=j.parentNode&&(i.children("tfoot").detach(),i.append(j)); -b.aaSorting=[];b.aaSortingFixed=[];wa(b);h(l).removeClass(b.asStripeClasses.join(" "));h("th, td",g).removeClass(d.sSortable+" "+d.sSortableAsc+" "+d.sSortableDesc+" "+d.sSortableNone);f.children().detach();f.append(l);g=a?"remove":"detach";i[g]();k[g]();!a&&c&&(c.insertBefore(e,b.nTableReinsertBefore),i.css("width",b.sDestroyWidth).removeClass(d.sTable),(o=b.asDestroyStripes.length)&&f.children().each(function(a){h(this).addClass(b.asDestroyStripes[a%o])}));c=h.inArray(b,m.settings);-1!==c&&m.settings.splice(c, -1)})});h.each(["column","row","cell"],function(a,b){o(b+"s().every()",function(a){var d=this.selector.opts,e=this;return this.iterator(b,function(f,g,h,i,n){a.call(e[b](g,"cell"===b?h:d,"cell"===b?d:k),g,h,i,n)})})});o("i18n()",function(a,b,c){var d=this.context[0],a=Q(a)(d.oLanguage);a===k&&(a=b);c!==k&&h.isPlainObject(a)&&(a=a[c]!==k?a[c]:a._);return a.replace("%d",c)});m.version="1.10.16";m.settings=[];m.models={};m.models.oSearch={bCaseInsensitive:!0,sSearch:"",bRegex:!1,bSmart:!0};m.models.oRow= -{nTr:null,anCells:null,_aData:[],_aSortData:null,_aFilterData:null,_sFilterRow:null,_sRowStripe:"",src:null,idx:-1};m.models.oColumn={idx:null,aDataSort:null,asSorting:null,bSearchable:null,bSortable:null,bVisible:null,_sManualType:null,_bAttrSrc:!1,fnCreatedCell:null,fnGetData:null,fnSetData:null,mData:null,mRender:null,nTh:null,nTf:null,sClass:null,sContentPadding:null,sDefaultContent:null,sName:null,sSortDataType:"std",sSortingClass:null,sSortingClassJUI:null,sTitle:null,sType:null,sWidth:null, -sWidthOrig:null};m.defaults={aaData:null,aaSorting:[[0,"asc"]],aaSortingFixed:[],ajax:null,aLengthMenu:[10,25,50,100],aoColumns:null,aoColumnDefs:null,aoSearchCols:[],asStripeClasses:null,bAutoWidth:!0,bDeferRender:!1,bDestroy:!1,bFilter:!0,bInfo:!0,bLengthChange:!0,bPaginate:!0,bProcessing:!1,bRetrieve:!1,bScrollCollapse:!1,bServerSide:!1,bSort:!0,bSortMulti:!0,bSortCellsTop:!1,bSortClasses:!0,bStateSave:!1,fnCreatedRow:null,fnDrawCallback:null,fnFooterCallback:null,fnFormatNumber:function(a){return a.toString().replace(/\B(?=(\d{3})+(?!\d))/g, -this.oLanguage.sThousands)},fnHeaderCallback:null,fnInfoCallback:null,fnInitComplete:null,fnPreDrawCallback:null,fnRowCallback:null,fnServerData:null,fnServerParams:null,fnStateLoadCallback:function(a){try{return JSON.parse((-1===a.iStateDuration?sessionStorage:localStorage).getItem("DataTables_"+a.sInstance+"_"+location.pathname))}catch(b){}},fnStateLoadParams:null,fnStateLoaded:null,fnStateSaveCallback:function(a,b){try{(-1===a.iStateDuration?sessionStorage:localStorage).setItem("DataTables_"+a.sInstance+ -"_"+location.pathname,JSON.stringify(b))}catch(c){}},fnStateSaveParams:null,iStateDuration:7200,iDeferLoading:null,iDisplayLength:10,iDisplayStart:0,iTabIndex:0,oClasses:{},oLanguage:{oAria:{sSortAscending:": activate to sort column ascending",sSortDescending:": activate to sort column descending"},oPaginate:{sFirst:"First",sLast:"Last",sNext:"Next",sPrevious:"Previous"},sEmptyTable:"No data available in table",sInfo:"Showing _START_ to _END_ of _TOTAL_ entries",sInfoEmpty:"Showing 0 to 0 of 0 entries", -sInfoFiltered:"(filtered from _MAX_ total entries)",sInfoPostFix:"",sDecimal:"",sThousands:",",sLengthMenu:"Show _MENU_ entries",sLoadingRecords:"Loading...",sProcessing:"Processing...",sSearch:"Search:",sSearchPlaceholder:"",sUrl:"",sZeroRecords:"No matching records found"},oSearch:h.extend({},m.models.oSearch),sAjaxDataProp:"data",sAjaxSource:null,sDom:"lfrtip",searchDelay:null,sPaginationType:"simple_numbers",sScrollX:"",sScrollXInner:"",sScrollY:"",sServerMethod:"GET",renderer:null,rowId:"DT_RowId"}; -X(m.defaults);m.defaults.column={aDataSort:null,iDataSort:-1,asSorting:["asc","desc"],bSearchable:!0,bSortable:!0,bVisible:!0,fnCreatedCell:null,mData:null,mRender:null,sCellType:"td",sClass:"",sContentPadding:"",sDefaultContent:null,sName:"",sSortDataType:"std",sTitle:null,sType:null,sWidth:null};X(m.defaults.column);m.models.oSettings={oFeatures:{bAutoWidth:null,bDeferRender:null,bFilter:null,bInfo:null,bLengthChange:null,bPaginate:null,bProcessing:null,bServerSide:null,bSort:null,bSortMulti:null, -bSortClasses:null,bStateSave:null},oScroll:{bCollapse:null,iBarWidth:0,sX:null,sXInner:null,sY:null},oLanguage:{fnInfoCallback:null},oBrowser:{bScrollOversize:!1,bScrollbarLeft:!1,bBounding:!1,barWidth:0},ajax:null,aanFeatures:[],aoData:[],aiDisplay:[],aiDisplayMaster:[],aIds:{},aoColumns:[],aoHeader:[],aoFooter:[],oPreviousSearch:{},aoPreSearchCols:[],aaSorting:null,aaSortingFixed:[],asStripeClasses:null,asDestroyStripes:[],sDestroyWidth:0,aoRowCallback:[],aoHeaderCallback:[],aoFooterCallback:[], -aoDrawCallback:[],aoRowCreatedCallback:[],aoPreDrawCallback:[],aoInitComplete:[],aoStateSaveParams:[],aoStateLoadParams:[],aoStateLoaded:[],sTableId:"",nTable:null,nTHead:null,nTFoot:null,nTBody:null,nTableWrapper:null,bDeferLoading:!1,bInitialised:!1,aoOpenRows:[],sDom:null,searchDelay:null,sPaginationType:"two_button",iStateDuration:0,aoStateSave:[],aoStateLoad:[],oSavedState:null,oLoadedState:null,sAjaxSource:null,sAjaxDataProp:null,bAjaxDataGet:!0,jqXHR:null,json:k,oAjaxData:k,fnServerData:null, -aoServerParams:[],sServerMethod:null,fnFormatNumber:null,aLengthMenu:null,iDraw:0,bDrawing:!1,iDrawError:-1,_iDisplayLength:10,_iDisplayStart:0,_iRecordsTotal:0,_iRecordsDisplay:0,oClasses:{},bFiltered:!1,bSorted:!1,bSortCellsTop:null,oInit:null,aoDestroyCallback:[],fnRecordsTotal:function(){return"ssp"==y(this)?1*this._iRecordsTotal:this.aiDisplayMaster.length},fnRecordsDisplay:function(){return"ssp"==y(this)?1*this._iRecordsDisplay:this.aiDisplay.length},fnDisplayEnd:function(){var a=this._iDisplayLength, -b=this._iDisplayStart,c=b+a,d=this.aiDisplay.length,e=this.oFeatures,f=e.bPaginate;return e.bServerSide?!1===f||-1===a?b+d:Math.min(b+a,this._iRecordsDisplay):!f||c>d||-1===a?d:c},oInstance:null,sInstance:null,iTabIndex:0,nScrollHead:null,nScrollFoot:null,aLastSort:[],oPlugins:{},rowIdFn:null,rowId:null};m.ext=x={buttons:{},classes:{},builder:"-source-",errMode:"alert",feature:[],search:[],selector:{cell:[],column:[],row:[]},internal:{},legacy:{ajax:null},pager:{},renderer:{pageButton:{},header:{}}, -order:{},type:{detect:[],search:{},order:{}},_unique:0,fnVersionCheck:m.fnVersionCheck,iApiIndex:0,oJUIClasses:{},sVersion:m.version};h.extend(x,{afnFiltering:x.search,aTypes:x.type.detect,ofnSearch:x.type.search,oSort:x.type.order,afnSortData:x.order,aoFeatures:x.feature,oApi:x.internal,oStdClasses:x.classes,oPagination:x.pager});h.extend(m.ext.classes,{sTable:"dataTable",sNoFooter:"no-footer",sPageButton:"paginate_button",sPageButtonActive:"current",sPageButtonDisabled:"disabled",sStripeOdd:"odd", -sStripeEven:"even",sRowEmpty:"dataTables_empty",sWrapper:"dataTables_wrapper",sFilter:"dataTables_filter",sInfo:"dataTables_info",sPaging:"dataTables_paginate paging_",sLength:"dataTables_length",sProcessing:"dataTables_processing",sSortAsc:"sorting_asc",sSortDesc:"sorting_desc",sSortable:"sorting",sSortableAsc:"sorting_asc_disabled",sSortableDesc:"sorting_desc_disabled",sSortableNone:"sorting_disabled",sSortColumn:"sorting_",sFilterInput:"",sLengthSelect:"",sScrollWrapper:"dataTables_scroll",sScrollHead:"dataTables_scrollHead", -sScrollHeadInner:"dataTables_scrollHeadInner",sScrollBody:"dataTables_scrollBody",sScrollFoot:"dataTables_scrollFoot",sScrollFootInner:"dataTables_scrollFootInner",sHeaderTH:"",sFooterTH:"",sSortJUIAsc:"",sSortJUIDesc:"",sSortJUI:"",sSortJUIAscAllowed:"",sSortJUIDescAllowed:"",sSortJUIWrapper:"",sSortIcon:"",sJUIHeader:"",sJUIFooter:""});var Kb=m.ext.pager;h.extend(Kb,{simple:function(){return["previous","next"]},full:function(){return["first","previous","next","last"]},numbers:function(a,b){return[ha(a, -b)]},simple_numbers:function(a,b){return["previous",ha(a,b),"next"]},full_numbers:function(a,b){return["first","previous",ha(a,b),"next","last"]},first_last_numbers:function(a,b){return["first",ha(a,b),"last"]},_numbers:ha,numbers_length:7});h.extend(!0,m.ext.renderer,{pageButton:{_:function(a,b,c,d,e,f){var g=a.oClasses,j=a.oLanguage.oPaginate,i=a.oLanguage.oAria.paginate||{},n,l,m=0,o=function(b,d){var k,s,u,r,v=function(b){Sa(a,b.data.action,true)};k=0;for(s=d.length;k").appendTo(b);o(u,r)}else{n=null;l="";switch(r){case "ellipsis":b.append('');break;case "first":n=j.sFirst;l=r+(e>0?"":" "+g.sPageButtonDisabled);break;case "previous":n=j.sPrevious;l=r+(e>0?"":" "+g.sPageButtonDisabled);break;case "next":n=j.sNext;l=r+(e",{"class":g.sPageButton+ -" "+l,"aria-controls":a.sTableId,"aria-label":i[r],"data-dt-idx":m,tabindex:a.iTabIndex,id:c===0&&typeof r==="string"?a.sTableId+"_"+r:null}).html(n).appendTo(b);Va(u,{action:r},v);m++}}}},s;try{s=h(b).find(G.activeElement).data("dt-idx")}catch(u){}o(h(b).empty(),d);s!==k&&h(b).find("[data-dt-idx="+s+"]").focus()}}});h.extend(m.ext.type.detect,[function(a,b){var c=b.oLanguage.sDecimal;return Ya(a,c)?"num"+c:null},function(a){if(a&&!(a instanceof Date)&&!Zb.test(a))return null;var b=Date.parse(a); -return null!==b&&!isNaN(b)||L(a)?"date":null},function(a,b){var c=b.oLanguage.sDecimal;return Ya(a,c,!0)?"num-fmt"+c:null},function(a,b){var c=b.oLanguage.sDecimal;return Pb(a,c)?"html-num"+c:null},function(a,b){var c=b.oLanguage.sDecimal;return Pb(a,c,!0)?"html-num-fmt"+c:null},function(a){return L(a)||"string"===typeof a&&-1!==a.indexOf("<")?"html":null}]);h.extend(m.ext.type.search,{html:function(a){return L(a)?a:"string"===typeof a?a.replace(Mb," ").replace(Aa,""):""},string:function(a){return L(a)? -a:"string"===typeof a?a.replace(Mb," "):a}});var za=function(a,b,c,d){if(0!==a&&(!a||"-"===a))return-Infinity;b&&(a=Ob(a,b));a.replace&&(c&&(a=a.replace(c,"")),d&&(a=a.replace(d,"")));return 1*a};h.extend(x.type.order,{"date-pre":function(a){return Date.parse(a)||-Infinity},"html-pre":function(a){return L(a)?"":a.replace?a.replace(/<.*?>/g,"").toLowerCase():a+""},"string-pre":function(a){return L(a)?"":"string"===typeof a?a.toLowerCase():!a.toString?"":a.toString()},"string-asc":function(a,b){return a< -b?-1:a>b?1:0},"string-desc":function(a,b){return ab?-1:0}});cb("");h.extend(!0,m.ext.renderer,{header:{_:function(a,b,c,d){h(a.nTable).on("order.dt.DT",function(e,f,g,h){if(a===f){e=c.idx;b.removeClass(c.sSortingClass+" "+d.sSortAsc+" "+d.sSortDesc).addClass(h[e]=="asc"?d.sSortAsc:h[e]=="desc"?d.sSortDesc:c.sSortingClass)}})},jqueryui:function(a,b,c,d){h("
").addClass(d.sSortJUIWrapper).append(b.contents()).append(h("").addClass(d.sSortIcon+" "+c.sSortingClassJUI)).appendTo(b); -h(a.nTable).on("order.dt.DT",function(e,f,g,h){if(a===f){e=c.idx;b.removeClass(d.sSortAsc+" "+d.sSortDesc).addClass(h[e]=="asc"?d.sSortAsc:h[e]=="desc"?d.sSortDesc:c.sSortingClass);b.find("span."+d.sSortIcon).removeClass(d.sSortJUIAsc+" "+d.sSortJUIDesc+" "+d.sSortJUI+" "+d.sSortJUIAscAllowed+" "+d.sSortJUIDescAllowed).addClass(h[e]=="asc"?d.sSortJUIAsc:h[e]=="desc"?d.sSortJUIDesc:c.sSortingClassJUI)}})}}});var Vb=function(a){return"string"===typeof a?a.replace(//g,">").replace(/"/g, -"""):a};m.render={number:function(a,b,c,d,e){return{display:function(f){if("number"!==typeof f&&"string"!==typeof f)return f;var g=0>f?"-":"",h=parseFloat(f);if(isNaN(h))return Vb(f);h=h.toFixed(c);f=Math.abs(h);h=parseInt(f,10);f=c?b+(f-h).toFixed(c).substring(2):"";return g+(d||"")+h.toString().replace(/\B(?=(\d{3})+(?!\d))/g,a)+f+(e||"")}}},text:function(){return{display:Vb}}};h.extend(m.ext.internal,{_fnExternApiFunc:Lb,_fnBuildAjax:sa,_fnAjaxUpdate:kb,_fnAjaxParameters:tb,_fnAjaxUpdateDraw:ub, -_fnAjaxDataSrc:ta,_fnAddColumn:Da,_fnColumnOptions:ja,_fnAdjustColumnSizing:Y,_fnVisibleToColumnIndex:Z,_fnColumnIndexToVisible:$,_fnVisbleColumns:aa,_fnGetColumns:la,_fnColumnTypes:Fa,_fnApplyColumnDefs:hb,_fnHungarianMap:X,_fnCamelToHungarian:I,_fnLanguageCompat:Ca,_fnBrowserDetect:fb,_fnAddData:M,_fnAddTr:ma,_fnNodeToDataIndex:function(a,b){return b._DT_RowIndex!==k?b._DT_RowIndex:null},_fnNodeToColumnIndex:function(a,b,c){return h.inArray(c,a.aoData[b].anCells)},_fnGetCellData:B,_fnSetCellData:ib, -_fnSplitObjNotation:Ia,_fnGetObjectDataFn:Q,_fnSetObjectDataFn:R,_fnGetDataMaster:Ja,_fnClearTable:na,_fnDeleteIndex:oa,_fnInvalidate:ca,_fnGetRowElements:Ha,_fnCreateTr:Ga,_fnBuildHead:jb,_fnDrawHead:ea,_fnDraw:N,_fnReDraw:S,_fnAddOptionsHtml:mb,_fnDetectHeader:da,_fnGetUniqueThs:ra,_fnFeatureHtmlFilter:ob,_fnFilterComplete:fa,_fnFilterCustom:xb,_fnFilterColumn:wb,_fnFilter:vb,_fnFilterCreateSearch:Oa,_fnEscapeRegex:Pa,_fnFilterData:yb,_fnFeatureHtmlInfo:rb,_fnUpdateInfo:Bb,_fnInfoMacros:Cb,_fnInitialise:ga, -_fnInitComplete:ua,_fnLengthChange:Qa,_fnFeatureHtmlLength:nb,_fnFeatureHtmlPaginate:sb,_fnPageChange:Sa,_fnFeatureHtmlProcessing:pb,_fnProcessingDisplay:C,_fnFeatureHtmlTable:qb,_fnScrollDraw:ka,_fnApplyToChildren:H,_fnCalculateColumnWidths:Ea,_fnThrottle:Na,_fnConvertToWidth:Db,_fnGetWidestNode:Eb,_fnGetMaxLenString:Fb,_fnStringToCss:v,_fnSortFlatten:V,_fnSort:lb,_fnSortAria:Hb,_fnSortListener:Ua,_fnSortAttachListener:La,_fnSortingClasses:wa,_fnSortData:Gb,_fnSaveState:xa,_fnLoadState:Ib,_fnSettingsFromNode:ya, -_fnLog:J,_fnMap:F,_fnBindAction:Va,_fnCallbackReg:z,_fnCallbackFire:r,_fnLengthOverflow:Ra,_fnRenderer:Ma,_fnDataSource:y,_fnRowAttributes:Ka,_fnCalculateEnd:function(){}});h.fn.dataTable=m;m.$=h;h.fn.dataTableSettings=m.settings;h.fn.dataTableExt=m.ext;h.fn.DataTable=function(a){return h(this).dataTable(a).api()};h.each(m,function(a,b){h.fn.DataTable[a]=b});return h.fn.dataTable}); diff --git a/develop_test/libs/dt-ext-buttons-1.10.16/css/buttons.dataTables.min.css b/develop_test/libs/dt-ext-buttons-1.10.16/css/buttons.dataTables.min.css deleted file mode 100644 index 112078b3b..000000000 --- a/develop_test/libs/dt-ext-buttons-1.10.16/css/buttons.dataTables.min.css +++ /dev/null @@ -1 +0,0 @@ -@keyframes dtb-spinner{100%{transform:rotate(360deg)}}@-o-keyframes dtb-spinner{100%{-o-transform:rotate(360deg);transform:rotate(360deg)}}@-ms-keyframes dtb-spinner{100%{-ms-transform:rotate(360deg);transform:rotate(360deg)}}@-webkit-keyframes dtb-spinner{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@-moz-keyframes dtb-spinner{100%{-moz-transform:rotate(360deg);transform:rotate(360deg)}}div.dt-button-info{position:fixed;top:50%;left:50%;width:400px;margin-top:-100px;margin-left:-200px;background-color:white;border:2px solid #111;box-shadow:3px 3px 8px rgba(0,0,0,0.3);border-radius:3px;text-align:center;z-index:21}div.dt-button-info h2{padding:0.5em;margin:0;font-weight:normal;border-bottom:1px solid #ddd;background-color:#f3f3f3}div.dt-button-info>div{padding:1em}button.dt-button,div.dt-button,a.dt-button{position:relative;display:inline-block;box-sizing:border-box;margin-right:0.333em;padding:0.5em 1em;border:1px solid #999;border-radius:2px;cursor:pointer;font-size:0.88em;color:black;white-space:nowrap;overflow:hidden;background-color:#e9e9e9;background-image:-webkit-linear-gradient(top, #fff 0%, #e9e9e9 100%);background-image:-moz-linear-gradient(top, #fff 0%, #e9e9e9 100%);background-image:-ms-linear-gradient(top, #fff 0%, #e9e9e9 100%);background-image:-o-linear-gradient(top, #fff 0%, #e9e9e9 100%);background-image:linear-gradient(to bottom, #fff 0%, #e9e9e9 100%);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='white', EndColorStr='#e9e9e9');-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;text-decoration:none;outline:none}button.dt-button.disabled,div.dt-button.disabled,a.dt-button.disabled{color:#999;border:1px solid #d0d0d0;cursor:default;background-color:#f9f9f9;background-image:-webkit-linear-gradient(top, #fff 0%, #f9f9f9 100%);background-image:-moz-linear-gradient(top, #fff 0%, #f9f9f9 100%);background-image:-ms-linear-gradient(top, #fff 0%, #f9f9f9 100%);background-image:-o-linear-gradient(top, #fff 0%, #f9f9f9 100%);background-image:linear-gradient(to bottom, #fff 0%, #f9f9f9 100%);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='#ffffff', EndColorStr='#f9f9f9')}button.dt-button:active:not(.disabled),button.dt-button.active:not(.disabled),div.dt-button:active:not(.disabled),div.dt-button.active:not(.disabled),a.dt-button:active:not(.disabled),a.dt-button.active:not(.disabled){background-color:#e2e2e2;background-image:-webkit-linear-gradient(top, #f3f3f3 0%, #e2e2e2 100%);background-image:-moz-linear-gradient(top, #f3f3f3 0%, #e2e2e2 100%);background-image:-ms-linear-gradient(top, #f3f3f3 0%, #e2e2e2 100%);background-image:-o-linear-gradient(top, #f3f3f3 0%, #e2e2e2 100%);background-image:linear-gradient(to bottom, #f3f3f3 0%, #e2e2e2 100%);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='#f3f3f3', EndColorStr='#e2e2e2');box-shadow:inset 1px 1px 3px #999999}button.dt-button:active:not(.disabled):hover:not(.disabled),button.dt-button.active:not(.disabled):hover:not(.disabled),div.dt-button:active:not(.disabled):hover:not(.disabled),div.dt-button.active:not(.disabled):hover:not(.disabled),a.dt-button:active:not(.disabled):hover:not(.disabled),a.dt-button.active:not(.disabled):hover:not(.disabled){box-shadow:inset 1px 1px 3px #999999;background-color:#cccccc;background-image:-webkit-linear-gradient(top, #eaeaea 0%, #ccc 100%);background-image:-moz-linear-gradient(top, #eaeaea 0%, #ccc 100%);background-image:-ms-linear-gradient(top, #eaeaea 0%, #ccc 100%);background-image:-o-linear-gradient(top, #eaeaea 0%, #ccc 100%);background-image:linear-gradient(to bottom, #eaeaea 0%, #ccc 100%);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='#eaeaea', EndColorStr='#cccccc')}button.dt-button:hover,div.dt-button:hover,a.dt-button:hover{text-decoration:none}button.dt-button:hover:not(.disabled),div.dt-button:hover:not(.disabled),a.dt-button:hover:not(.disabled){border:1px solid #666;background-color:#e0e0e0;background-image:-webkit-linear-gradient(top, #f9f9f9 0%, #e0e0e0 100%);background-image:-moz-linear-gradient(top, #f9f9f9 0%, #e0e0e0 100%);background-image:-ms-linear-gradient(top, #f9f9f9 0%, #e0e0e0 100%);background-image:-o-linear-gradient(top, #f9f9f9 0%, #e0e0e0 100%);background-image:linear-gradient(to bottom, #f9f9f9 0%, #e0e0e0 100%);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='#f9f9f9', EndColorStr='#e0e0e0')}button.dt-button:focus:not(.disabled),div.dt-button:focus:not(.disabled),a.dt-button:focus:not(.disabled){border:1px solid #426c9e;text-shadow:0 1px 0 #c4def1;outline:none;background-color:#79ace9;background-image:-webkit-linear-gradient(top, #bddef4 0%, #79ace9 100%);background-image:-moz-linear-gradient(top, #bddef4 0%, #79ace9 100%);background-image:-ms-linear-gradient(top, #bddef4 0%, #79ace9 100%);background-image:-o-linear-gradient(top, #bddef4 0%, #79ace9 100%);background-image:linear-gradient(to bottom, #bddef4 0%, #79ace9 100%);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='#bddef4', EndColorStr='#79ace9')}.dt-button embed{outline:none}div.dt-buttons{position:relative;float:left}div.dt-buttons.buttons-right{float:right}div.dt-button-collection{position:absolute;top:0;left:0;width:150px;margin-top:3px;padding:8px 8px 4px 8px;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.4);background-color:white;overflow:hidden;z-index:2002;border-radius:5px;box-shadow:3px 3px 5px rgba(0,0,0,0.3);z-index:2002;-webkit-column-gap:8px;-moz-column-gap:8px;-ms-column-gap:8px;-o-column-gap:8px;column-gap:8px}div.dt-button-collection button.dt-button,div.dt-button-collection div.dt-button,div.dt-button-collection a.dt-button{position:relative;left:0;right:0;display:block;float:none;margin-bottom:4px;margin-right:0}div.dt-button-collection button.dt-button:active:not(.disabled),div.dt-button-collection button.dt-button.active:not(.disabled),div.dt-button-collection div.dt-button:active:not(.disabled),div.dt-button-collection div.dt-button.active:not(.disabled),div.dt-button-collection a.dt-button:active:not(.disabled),div.dt-button-collection a.dt-button.active:not(.disabled){background-color:#dadada;background-image:-webkit-linear-gradient(top, #f0f0f0 0%, #dadada 100%);background-image:-moz-linear-gradient(top, #f0f0f0 0%, #dadada 100%);background-image:-ms-linear-gradient(top, #f0f0f0 0%, #dadada 100%);background-image:-o-linear-gradient(top, #f0f0f0 0%, #dadada 100%);background-image:linear-gradient(to bottom, #f0f0f0 0%, #dadada 100%);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='#f0f0f0', EndColorStr='#dadada');box-shadow:inset 1px 1px 3px #666}div.dt-button-collection.fixed{position:fixed;top:50%;left:50%;margin-left:-75px;border-radius:0}div.dt-button-collection.fixed.two-column{margin-left:-150px}div.dt-button-collection.fixed.three-column{margin-left:-225px}div.dt-button-collection.fixed.four-column{margin-left:-300px}div.dt-button-collection>*{-webkit-column-break-inside:avoid;break-inside:avoid}div.dt-button-collection.two-column{width:300px;padding-bottom:1px;-webkit-column-count:2;-moz-column-count:2;-ms-column-count:2;-o-column-count:2;column-count:2}div.dt-button-collection.three-column{width:450px;padding-bottom:1px;-webkit-column-count:3;-moz-column-count:3;-ms-column-count:3;-o-column-count:3;column-count:3}div.dt-button-collection.four-column{width:600px;padding-bottom:1px;-webkit-column-count:4;-moz-column-count:4;-ms-column-count:4;-o-column-count:4;column-count:4}div.dt-button-background{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.7);background:-ms-radial-gradient(center, ellipse farthest-corner, rgba(0,0,0,0.3) 0%, rgba(0,0,0,0.7) 100%);background:-moz-radial-gradient(center, ellipse farthest-corner, rgba(0,0,0,0.3) 0%, rgba(0,0,0,0.7) 100%);background:-o-radial-gradient(center, ellipse farthest-corner, rgba(0,0,0,0.3) 0%, rgba(0,0,0,0.7) 100%);background:-webkit-gradient(radial, center center, 0, center center, 497, color-stop(0, rgba(0,0,0,0.3)), color-stop(1, rgba(0,0,0,0.7)));background:-webkit-radial-gradient(center, ellipse farthest-corner, rgba(0,0,0,0.3) 0%, rgba(0,0,0,0.7) 100%);background:radial-gradient(ellipse farthest-corner at center, rgba(0,0,0,0.3) 0%, rgba(0,0,0,0.7) 100%);z-index:2001}@media screen and (max-width: 640px){div.dt-buttons{float:none !important;text-align:center}}button.dt-button.processing,div.dt-button.processing,a.dt-button.processing{color:rgba(0,0,0,0.2)}button.dt-button.processing:after,div.dt-button.processing:after,a.dt-button.processing:after{position:absolute;top:50%;left:50%;width:16px;height:16px;margin:-8px 0 0 -8px;box-sizing:border-box;display:block;content:' ';border:2px solid #282828;border-radius:50%;border-left-color:transparent;border-right-color:transparent;animation:dtb-spinner 1500ms infinite linear;-o-animation:dtb-spinner 1500ms infinite linear;-ms-animation:dtb-spinner 1500ms infinite linear;-webkit-animation:dtb-spinner 1500ms infinite linear;-moz-animation:dtb-spinner 1500ms infinite linear} diff --git a/develop_test/libs/dt-ext-buttons-1.10.16/js/buttons.colVis.min.js b/develop_test/libs/dt-ext-buttons-1.10.16/js/buttons.colVis.min.js deleted file mode 100644 index 9ea693121..000000000 --- a/develop_test/libs/dt-ext-buttons-1.10.16/js/buttons.colVis.min.js +++ /dev/null @@ -1,6 +0,0 @@ -(function(g){"function"===typeof define&&define.amd?define(["jquery","datatables.net","datatables.net-buttons"],function(d){return g(d,window,document)}):"object"===typeof exports?module.exports=function(d,e){d||(d=window);if(!e||!e.fn.dataTable)e=require("datatables.net")(d,e).$;e.fn.dataTable.Buttons||require("datatables.net-buttons")(d,e);return g(e,d,d.document)}:g(jQuery,window,document)})(function(g,d,e,h){d=g.fn.dataTable;g.extend(d.ext.buttons,{colvis:function(b,a){return{extend:"collection", -text:function(a){return a.i18n("buttons.colvis","Column visibility")},className:"buttons-colvis",buttons:[{extend:"columnsToggle",columns:a.columns,columnText:a.columnText}]}},columnsToggle:function(b,a){return b.columns(a.columns).indexes().map(function(b){return{extend:"columnToggle",columns:b,columnText:a.columnText}}).toArray()},columnToggle:function(b,a){return{extend:"columnVisibility",columns:a.columns,columnText:a.columnText}},columnsVisibility:function(b,a){return b.columns(a.columns).indexes().map(function(b){return{extend:"columnVisibility", -columns:b,visibility:a.visibility,columnText:a.columnText}}).toArray()},columnVisibility:{columns:h,text:function(b,a,c){return c._columnText(b,c)},className:"buttons-columnVisibility",action:function(b,a,c,f){b=a.columns(f.columns);a=b.visible();b.visible(f.visibility!==h?f.visibility:!(a.length&&a[0]))},init:function(b,a,c){var f=this;b.on("column-visibility.dt"+c.namespace,function(a,d){!d.bDestroying&&d.nTable==b.settings()[0].nTable&&f.active(b.column(c.columns).visible())}).on("column-reorder.dt"+ -c.namespace,function(a,d,e){1===b.columns(c.columns).count()&&("number"===typeof c.columns&&(c.columns=e.mapping[c.columns]),a=b.column(c.columns),f.text(c._columnText(b,c)),f.active(a.visible()))});this.active(b.column(c.columns).visible())},destroy:function(b,a,c){b.off("column-visibility.dt"+c.namespace).off("column-reorder.dt"+c.namespace)},_columnText:function(b,a){var c=b.column(a.columns).index(),f=b.settings()[0].aoColumns[c].sTitle.replace(/\n/g," ").replace(//gi," ").replace(/<.*?>/g, -"").replace(/^\s+|\s+$/g,"");return a.columnText?a.columnText(b,c,f):f}},colvisRestore:{className:"buttons-colvisRestore",text:function(b){return b.i18n("buttons.colvisRestore","Restore visibility")},init:function(b,a,c){c._visOriginal=b.columns().indexes().map(function(a){return b.column(a).visible()}).toArray()},action:function(b,a,c,d){a.columns().every(function(b){b=a.colReorder&&a.colReorder.transpose?a.colReorder.transpose(b,"toOriginal"):b;this.visible(d._visOriginal[b])})}},colvisGroup:{className:"buttons-colvisGroup", -action:function(b,a,c,d){a.columns(d.show).visible(!0,!1);a.columns(d.hide).visible(!1,!1);a.columns.adjust()},show:[],hide:[]}});return d.Buttons}); diff --git a/develop_test/libs/dt-ext-buttons-1.10.16/js/buttons.flash.min.js b/develop_test/libs/dt-ext-buttons-1.10.16/js/buttons.flash.min.js deleted file mode 100644 index 06846dbab..000000000 --- a/develop_test/libs/dt-ext-buttons-1.10.16/js/buttons.flash.min.js +++ /dev/null @@ -1,32 +0,0 @@ -(function(h){"function"===typeof define&&define.amd?define(["jquery","datatables.net","datatables.net-buttons"],function(j){return h(j,window,document)}):"object"===typeof exports?module.exports=function(j,l){j||(j=window);if(!l||!l.fn.dataTable)l=require("datatables.net")(j,l).$;l.fn.dataTable.Buttons||require("datatables.net-buttons")(j,l);return h(l,j,j.document)}:h(jQuery,window,document)})(function(h,j,l,p){function v(a){for(var b="";0<=a;)b=String.fromCharCode(a%26+65)+b,a=Math.floor(a/26)- -1;return b}function o(a,b,d){var c=a.createElement(b);d&&(d.attr&&h(c).attr(d.attr),d.children&&h.each(d.children,function(a,b){c.appendChild(b)}),null!==d.text&&d.text!==p&&c.appendChild(a.createTextNode(d.text)));return c}function B(a,b){var d=a.header[b].length,c;a.footer&&a.footer[b].length>d&&(d=a.footer[b].length);for(var e=0,f=a.body.length;ed&&(d=c),40'+c),c=c.replace(/_dt_b_namespace_token_/g,":"));c=c.replace(/<([^<>]*?) xmlns=""([^<>]*?)>/g,"<$1 $2>");a[b]=c}})}var g=h.fn.dataTable,i={version:"1.0.4-TableTools2",clients:{},moviePath:"",nextId:1,$:function(a){"string"==typeof a&&(a=l.getElementById(a));a.addClass||(a.hide=function(){this.style.display="none"},a.show=function(){this.style.display= -""},a.addClass=function(a){this.removeClass(a);this.className+=" "+a},a.removeClass=function(a){this.className=this.className.replace(RegExp("\\s*"+a+"\\s*")," ").replace(/^\s+/,"").replace(/\s+$/,"")},a.hasClass=function(a){return!!this.className.match(RegExp("\\s*"+a+"\\s*"))});return a},setMoviePath:function(a){this.moviePath=a},dispatch:function(a,b,d){(a=this.clients[a])&&a.receiveEvent(b,d)},log:function(a){console.log("Flash: "+a)},register:function(a,b){this.clients[a]=b},getDOMObjectPosition:function(a){var b= -{left:0,top:0,width:a.width?a.width:a.offsetWidth,height:a.height?a.height:a.offsetHeight};""!==a.style.width&&(b.width=a.style.width.replace("px",""));""!==a.style.height&&(b.height=a.style.height.replace("px",""));for(;a;)b.left+=a.offsetLeft,b.top+=a.offsetTop,a=a.offsetParent;return b},Client:function(a){this.handlers={};this.id=i.nextId++;this.movieId="ZeroClipboard_TableToolsMovie_"+this.id;i.register(this.id,this);a&&this.glue(a)}};i.Client.prototype={id:0,ready:!1,movie:null,clipText:"",fileName:"", -action:"copy",handCursorEnabled:!0,cssEffects:!0,handlers:null,sized:!1,sheetName:"",glue:function(a,b){this.domElement=i.$(a);var d=99;this.domElement.style.zIndex&&(d=parseInt(this.domElement.style.zIndex,10)+1);var c=i.getDOMObjectPosition(this.domElement);this.div=l.createElement("div");var e=this.div.style;e.position="absolute";e.left="0px";e.top="0px";e.width=c.width+"px";e.height=c.height+"px";e.zIndex=d;"undefined"!=typeof b&&""!==b&&(this.div.title=b);0!==c.width&&0!==c.height&&(this.sized= -!0);this.domElement&&(this.domElement.appendChild(this.div),this.div.innerHTML=this.getHTML(c.width,c.height).replace(/&/g,"&"))},positionElement:function(){var a=i.getDOMObjectPosition(this.domElement),b=this.div.style;b.position="absolute";b.width=a.width+"px";b.height=a.height+"px";0!==a.width&&0!==a.height&&(this.sized=!0,b=this.div.childNodes[0],b.width=a.width,b.height=a.height)},getHTML:function(a,b){var d="",c="id="+this.id+"&width="+a+"&height="+b;if(navigator.userAgent.match(/MSIE/))var e= -location.href.match(/^https/i)?"https://":"http://",d=d+('');else d+='';return d},hide:function(){this.div&&(this.div.style.left="-2000px")}, -show:function(){this.reposition()},destroy:function(){var a=this;this.domElement&&this.div&&(h(this.div).remove(),this.div=this.domElement=null,h.each(i.clients,function(b,d){d===a&&delete i.clients[b]}))},reposition:function(a){a&&((this.domElement=i.$(a))||this.hide());if(this.domElement&&this.div){var a=i.getDOMObjectPosition(this.domElement),b=this.div.style;b.left=""+a.left+"px";b.top=""+a.top+"px"}},clearText:function(){this.clipText="";this.ready&&this.movie.clearText()},appendText:function(a){this.clipText+= -a;this.ready&&this.movie.appendText(a)},setText:function(a){this.clipText=a;this.ready&&this.movie.setText(a)},setFileName:function(a){this.fileName=a;this.ready&&this.movie.setFileName(a)},setSheetData:function(a){this.ready&&this.movie.setSheetData(JSON.stringify(a))},setAction:function(a){this.action=a;this.ready&&this.movie.setAction(a)},addEventListener:function(a,b){a=a.toString().toLowerCase().replace(/^on/,"");this.handlers[a]||(this.handlers[a]=[]);this.handlers[a].push(b)},setHandCursor:function(a){this.handCursorEnabled= -a;this.ready&&this.movie.setHandCursor(a)},setCSSEffects:function(a){this.cssEffects=!!a},receiveEvent:function(a,b){var d,a=a.toString().toLowerCase().replace(/^on/,"");switch(a){case "load":this.movie=l.getElementById(this.movieId);if(!this.movie){d=this;setTimeout(function(){d.receiveEvent("load",null)},1);return}if(!this.ready&&navigator.userAgent.match(/Firefox/)&&navigator.userAgent.match(/Windows/)){d=this;setTimeout(function(){d.receiveEvent("load",null)},100);this.ready=!0;return}this.ready= -!0;this.movie.clearText();this.movie.appendText(this.clipText);this.movie.setFileName(this.fileName);this.movie.setAction(this.action);this.movie.setHandCursor(this.handCursorEnabled);break;case "mouseover":this.domElement&&this.cssEffects&&this.recoverActive&&this.domElement.addClass("active");break;case "mouseout":this.domElement&&this.cssEffects&&(this.recoverActive=!1,this.domElement.hasClass("active")&&(this.domElement.removeClass("active"),this.recoverActive=!0));break;case "mousedown":this.domElement&& -this.cssEffects&&this.domElement.addClass("active");break;case "mouseup":this.domElement&&this.cssEffects&&(this.domElement.removeClass("active"),this.recoverActive=!1)}if(this.handlers[a])for(var c=0,e=this.handlers[a].length;c',"xl/_rels/workbook.xml.rels":'', -"[Content_Types].xml":'', -"xl/workbook.xml":'', -"xl/worksheets/sheet1.xml":'',"xl/styles.xml":''}, -A=[{match:/^\-?\d+\.\d%$/,style:60,fmt:function(a){return a/100}},{match:/^\-?\d+\.?\d*%$/,style:56,fmt:function(a){return a/100}},{match:/^\-?\$[\d,]+.?\d*$/,style:57},{match:/^\-?£[\d,]+.?\d*$/,style:58},{match:/^\-?€[\d,]+.?\d*$/,style:59},{match:/^\([\d,]+\)$/,style:61,fmt:function(a){return-1*a.replace(/[\(\)]/g,"")}},{match:/^\([\d,]+\.\d{2}\)$/,style:62,fmt:function(a){return-1*a.replace(/[\(\)]/g,"")}},{match:/^[\d,]+$/,style:63},{match:/^[\d,]+\.\d{2}$/,style:64}];g.Buttons.swfPath="//cdn.datatables.net/buttons/"+ -g.Buttons.version+"/swf/flashExport.swf";g.Api.register("buttons.resize()",function(){h.each(i.clients,function(a,b){b.domElement!==p&&b.domElement.parentNode&&b.positionElement()})});g.ext.buttons.copyFlash=h.extend({},t,{className:"buttons-copy buttons-flash",text:function(a){return a.i18n("buttons.copy","Copy")},action:function(a,b,d,c){if(c._fromFlash){this.processing(!0);var a=c._flash,e=z(b,c),d=b.buttons.exportInfo(c),f=y(c),e=e.str;d.title&&(e=d.title+f+f+e);d.messageTop&&(e=d.messageTop+ -f+f+e);d.messageBottom&&(e=e+f+f+d.messageBottom);c.customize&&(e=c.customize(e,c));a.setAction("copy");s(a,e);this.processing(!1);b.buttons.info(b.i18n("buttons.copyTitle","Copy to clipboard"),b.i18n("buttons.copySuccess",{_:"Copied %d rows to clipboard",1:"Copied 1 row to clipboard"},data.rows),3E3)}},fieldSeparator:"\t",fieldBoundary:""});g.ext.buttons.csvFlash=h.extend({},t,{className:"buttons-csv buttons-flash",text:function(a){return a.i18n("buttons.csv","CSV")},action:function(a,b,d,c){a=c._flash; -b=z(b,c);b=c.customize?c.customize(b.str,c):b.str;a.setAction("csv");a.setFileName(_filename(c));s(a,b)},escapeChar:'"'});g.ext.buttons.excelFlash=h.extend({},t,{className:"buttons-excel buttons-flash",text:function(a){return a.i18n("buttons.excel","Excel")},action:function(a,b,d,c){this.processing(!0);var a=c._flash,e=0,f=h.parseXML(m["xl/worksheets/sheet1.xml"]),i=f.getElementsByTagName("sheetData")[0],d={_rels:{".rels":h.parseXML(m["_rels/.rels"])},xl:{_rels:{"workbook.xml.rels":h.parseXML(m["xl/_rels/workbook.xml.rels"])}, -"workbook.xml":h.parseXML(m["xl/workbook.xml"]),"styles.xml":h.parseXML(m["xl/styles.xml"]),worksheets:{"sheet1.xml":f}},"[Content_Types].xml":h.parseXML(m["[Content_Types].xml"])},k=b.buttons.exportData(c.exportOptions),j,l,g=function(a){j=e+1;l=o(f,"row",{attr:{r:j}});for(var b=0,c=a.length;b'+e),e=e.replace(/_dt_b_namespace_token_/g,":"));e=e.replace(/<([^<>]*?) xmlns=""([^<>]*?)>/g,"<$1 $2>");a.file(c,e)}})}function p(a,c,d){var b=a.createElement(c);d&&(d.attr&&j(b).attr(d.attr),d.children&&j.each(d.children,function(a,c){b.appendChild(c)}),null!==d.text&&d.text!==q&&b.appendChild(a.createTextNode(d.text)));return b}function J(a,c){var d= -a.header[c].length,b;a.footer&&a.footer[c].length>d&&(d=a.footer[c].length);for(var e=0,f=a.body.length;ed&&(d=b),401*a[1]?!0:!1};try{var w=new XMLSerializer,u}catch(O){}var z={"_rels/.rels":'',"xl/_rels/workbook.xml.rels":'', -"[Content_Types].xml":'', -"xl/workbook.xml":'', -"xl/worksheets/sheet1.xml":'',"xl/styles.xml":''}, -I=[{match:/^\-?\d+\.\d%$/,style:60,fmt:function(a){return a/100}},{match:/^\-?\d+\.?\d*%$/,style:56,fmt:function(a){return a/100}},{match:/^\-?\$[\d,]+.?\d*$/,style:57},{match:/^\-?£[\d,]+.?\d*$/,style:58},{match:/^\-?€[\d,]+.?\d*$/,style:59},{match:/^\-?\d+$/,style:65},{match:/^\-?\d+\.\d{2}$/,style:66},{match:/^\([\d,]+\)$/,style:61,fmt:function(a){return-1*a.replace(/[\(\)]/g,"")}},{match:/^\([\d,]+\.\d{2}\)$/,style:62,fmt:function(a){return-1*a.replace(/[\(\)]/g,"")}},{match:/^\-?[\d,]+$/,style:63}, -{match:/^\-?[\d,]+\.\d{2}$/,style:64}];m.ext.buttons.copyHtml5={className:"buttons-copy buttons-html5",text:function(a){return a.i18n("buttons.copy","Copy")},action:function(a,c,d,b){this.processing(!0);var e=this,a=G(c,b),f=c.buttons.exportInfo(b),g=F(b),n=a.str,d=j("
").css({height:1,width:1,overflow:"hidden",position:"fixed",top:0,left:0});f.title&&(n=f.title+g+g+n);f.messageTop&&(n=f.messageTop+g+g+n);f.messageBottom&&(n=n+g+g+f.messageBottom);b.customize&&(n=b.customize(n,b));b=j("",l.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var da=/^key/,ea=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,fa=/^([^.]*)(?:\.(.+)|)/;function ga(){return!0}function ha(){return!1}function ia(){try{return d.activeElement}catch(a){}}function ja(a,b,c,d,e,f){var g,h;if("object"==typeof b){"string"!=typeof c&&(d=d||c,c=void 0);for(h in b)ja(a,h,c,d,b[h],f);return a}if(null==d&&null==e?(e=c,d=c=void 0):null==e&&("string"==typeof c?(e=d,d=void 0):(e=d,d=c,c=void 0)),e===!1)e=ha;else if(!e)return a;return 1===f&&(g=e,e=function(a){return n().off(a),g.apply(this,arguments)},e.guid=g.guid||(g.guid=n.guid++)),a.each(function(){n.event.add(this,b,e,d,c)})}n.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=N.get(a);if(r){c.handler&&(f=c,c=f.handler,e=f.selector),c.guid||(c.guid=n.guid++),(i=r.events)||(i=r.events={}),(g=r.handle)||(g=r.handle=function(b){return"undefined"!=typeof n&&n.event.triggered!==b.type?n.event.dispatch.apply(a,arguments):void 0}),b=(b||"").match(G)||[""],j=b.length;while(j--)h=fa.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o&&(l=n.event.special[o]||{},o=(e?l.delegateType:l.bindType)||o,l=n.event.special[o]||{},k=n.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&n.expr.match.needsContext.test(e),namespace:p.join(".")},f),(m=i[o])||(m=i[o]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,p,g)!==!1||a.addEventListener&&a.addEventListener(o,g)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),n.event.global[o]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=N.hasData(a)&&N.get(a);if(r&&(i=r.events)){b=(b||"").match(G)||[""],j=b.length;while(j--)if(h=fa.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=n.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,m=i[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),g=f=m.length;while(f--)k=m[f],!e&&q!==k.origType||c&&c.guid!==k.guid||h&&!h.test(k.namespace)||d&&d!==k.selector&&("**"!==d||!k.selector)||(m.splice(f,1),k.selector&&m.delegateCount--,l.remove&&l.remove.call(a,k));g&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||n.removeEvent(a,o,r.handle),delete i[o])}else for(o in i)n.event.remove(a,o+b[j],c,d,!0);n.isEmptyObject(i)&&N.remove(a,"handle events")}},dispatch:function(a){a=n.event.fix(a);var b,c,d,f,g,h=[],i=e.call(arguments),j=(N.get(this,"events")||{})[a.type]||[],k=n.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=n.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,c=0;while((g=f.handlers[c++])&&!a.isImmediatePropagationStopped())a.rnamespace&&!a.rnamespace.test(g.namespace)||(a.handleObj=g,a.data=g.data,d=((n.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==d&&(a.result=d)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&("click"!==a.type||isNaN(a.button)||a.button<1))for(;i!==this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(d=[],c=0;h>c;c++)f=b[c],e=f.selector+" ",void 0===d[e]&&(d[e]=f.needsContext?n(e,this).index(i)>-1:n.find(e,this,null,[i]).length),d[e]&&d.push(f);d.length&&g.push({elem:i,handlers:d})}return h]*)\/>/gi,la=/\s*$/g;function pa(a,b){return n.nodeName(a,"table")&&n.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function qa(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function ra(a){var b=na.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function sa(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(N.hasData(a)&&(f=N.access(a),g=N.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;d>c;c++)n.event.add(b,e,j[e][c])}O.hasData(a)&&(h=O.access(a),i=n.extend({},h),O.set(b,i))}}function ta(a,b){var c=b.nodeName.toLowerCase();"input"===c&&X.test(a.type)?b.checked=a.checked:"input"!==c&&"textarea"!==c||(b.defaultValue=a.defaultValue)}function ua(a,b,c,d){b=f.apply([],b);var e,g,h,i,j,k,m=0,o=a.length,p=o-1,q=b[0],r=n.isFunction(q);if(r||o>1&&"string"==typeof q&&!l.checkClone&&ma.test(q))return a.each(function(e){var f=a.eq(e);r&&(b[0]=q.call(this,e,f.html())),ua(f,b,c,d)});if(o&&(e=ca(b,a[0].ownerDocument,!1,a,d),g=e.firstChild,1===e.childNodes.length&&(e=g),g||d)){for(h=n.map(_(e,"script"),qa),i=h.length;o>m;m++)j=e,m!==p&&(j=n.clone(j,!0,!0),i&&n.merge(h,_(j,"script"))),c.call(a[m],j,m);if(i)for(k=h[h.length-1].ownerDocument,n.map(h,ra),m=0;i>m;m++)j=h[m],Z.test(j.type||"")&&!N.access(j,"globalEval")&&n.contains(k,j)&&(j.src?n._evalUrl&&n._evalUrl(j.src):n.globalEval(j.textContent.replace(oa,"")))}return a}function va(a,b,c){for(var d,e=b?n.filter(b,a):a,f=0;null!=(d=e[f]);f++)c||1!==d.nodeType||n.cleanData(_(d)),d.parentNode&&(c&&n.contains(d.ownerDocument,d)&&aa(_(d,"script")),d.parentNode.removeChild(d));return a}n.extend({htmlPrefilter:function(a){return a.replace(ka,"<$1>")},clone:function(a,b,c){var d,e,f,g,h=a.cloneNode(!0),i=n.contains(a.ownerDocument,a);if(!(l.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||n.isXMLDoc(a)))for(g=_(h),f=_(a),d=0,e=f.length;e>d;d++)ta(f[d],g[d]);if(b)if(c)for(f=f||_(a),g=g||_(h),d=0,e=f.length;e>d;d++)sa(f[d],g[d]);else sa(a,h);return g=_(h,"script"),g.length>0&&aa(g,!i&&_(a,"script")),h},cleanData:function(a){for(var b,c,d,e=n.event.special,f=0;void 0!==(c=a[f]);f++)if(L(c)){if(b=c[N.expando]){if(b.events)for(d in b.events)e[d]?n.event.remove(c,d):n.removeEvent(c,d,b.handle);c[N.expando]=void 0}c[O.expando]&&(c[O.expando]=void 0)}}}),n.fn.extend({domManip:ua,detach:function(a){return va(this,a,!0)},remove:function(a){return va(this,a)},text:function(a){return K(this,function(a){return void 0===a?n.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=a)})},null,a,arguments.length)},append:function(){return ua(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=pa(this,a);b.appendChild(a)}})},prepend:function(){return ua(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=pa(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return ua(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return ua(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)1===a.nodeType&&(n.cleanData(_(a,!1)),a.textContent="");return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return n.clone(this,a,b)})},html:function(a){return K(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a&&1===b.nodeType)return b.innerHTML;if("string"==typeof a&&!la.test(a)&&!$[(Y.exec(a)||["",""])[1].toLowerCase()]){a=n.htmlPrefilter(a);try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(n.cleanData(_(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=[];return ua(this,arguments,function(b){var c=this.parentNode;n.inArray(this,a)<0&&(n.cleanData(_(this)),c&&c.replaceChild(b,this))},a)}}),n.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){n.fn[a]=function(a){for(var c,d=[],e=n(a),f=e.length-1,h=0;f>=h;h++)c=h===f?this:this.clone(!0),n(e[h])[b](c),g.apply(d,c.get());return this.pushStack(d)}});var wa,xa={HTML:"block",BODY:"block"};function ya(a,b){var c=n(b.createElement(a)).appendTo(b.body),d=n.css(c[0],"display");return c.detach(),d}function za(a){var b=d,c=xa[a];return c||(c=ya(a,b),"none"!==c&&c||(wa=(wa||n(" -
-
-

12.1 Read Settings

-

(TODO: Under construction…)

-
-
-

12.2 Input Conversions

-
-
-

12.3 Input Data

-

Models require input data as drivers, parameters, and boundary conditions. In order to make a variety of data sources that have unique formats compatible with models, conversion scripts are written to convert them into a PEcAn standard format. That format is a netcdf file with variables names and specified to our standard variable table.

-

Within the PEcAn repository, code pertaining to input conversion is in the MODULES directory under the data.atmosphere and data.land directories.

-
-
-

12.4 Initial Conditions

-

(TODO: Under construction)

-
-
-

12.5 Meteorological Data

-

To convert meterological data into the PEcAn Standard and then into model formats we follow four main steps:

-
    -
  1. Downloading raw data -- Currently supported products -- Example Code
  2. -
  3. Converting raw data into a CF standard -- Example Code
  4. -
  5. Downscaling and gapfilling -- Example Code
  6. -
  7. Coverting to Model Specific format -- Example Code
  8. -
-

Common Questions regarding Met Data:

-

How do I add my Meterological data product to PEcAn? -How do I use PEcAn to convert Met data outide the workflow?

-

The main script that handles Met Processing, is met.process. It acts as a wrapper function that calls individual modules to facilitate the processing of meteorological data from it’s original form to a pecan standard, and then from that standard to model specific formats. It also handles recording these processes in the BETY database.

-
    -
  1. Downloading raw data -- Available Meteorological Drivers -- Example Code to download Ameriflux data
  2. -
  3. Converting raw data into a CF standard (if needed) -- Example Code to convert from raw csv to CF standard
  4. -
  5. Downscaling and gapfilling(if needed) -- Example Code to gapfill
  6. -
  7. Coverting to Model Specific format -- Example Code to convert Standard into Sipnet format
  8. -
-
-

12.5.1 Downloading Raw data (Description of Process)

-

Given the information passed from the pecan.xml met.process will call the download.raw.met.module to facilitate the execution of the necessary functions to download raw data.

- -
-
-

12.5.2 Converting raw data to PEcAn standard

-
-
-

12.5.3 Downscaling and gapfilling (optional)

-
-
-

12.5.4 Converting from PEcAn standard to model-specific format

-
-
-
-

12.6 Traits

-

(TODO: Under construction)

-
-
-

12.7 Meta Analysis

-

(TODO: Under construction)

-
-
-

12.8 Model Configuration

-

(TODO: Under construction)

-
-
-

12.9 Run Execution

-

(TODO: Under construction)

-
-
-

12.10 Post Run Analysis

-

(TODO: Under construction) -## Advanced Analysis {#workflow-advanced}

-

(TODO: Under construction)

- -
-
- - -
-
-
- - -
-
- - - - - - - - - - - - - - - - diff --git a/develop_test/working-with-vm.html b/develop_test/working-with-vm.html deleted file mode 100644 index 247b218d0..000000000 --- a/develop_test/working-with-vm.html +++ /dev/null @@ -1,914 +0,0 @@ - - - - - - - 9 VM configuration and maintenance | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

9 VM configuration and maintenance

-
-

9.1 Updating the VM

- -

The PEcAn VM is distributed with specific versions of PEcAn compiled. However, you do not need to constantly download the VM in order to update your code and version of BETY. To update and maintain your code you can follow the steps found in the Developer section in Updating PecAn and Code and BETY Database. However, if you are using the latest version of the PEcAn VM (>=1.7) you have the Dockerized version of PEcAn and need to follow the instructions under the DOCKER section to update your PEcAn and BETY containers.

-
-
-

9.2 Connecting to the VM via SSH

-

Once the VM is running anywhere on your machine, you can connect to it from a separate terminal via SSH as follows:

- -

You will be prompted for a password. Like everywhere else in PEcAn, the username is carya and the password is illinois. The same password is used for any system maintenance you wish to do on the VM via sudo.

-

As a shortcut, you can add the following to your ~/.ssh/config file (or create one if it does not exist).

-
Host pecan-vm
-    Hostname localhost
-    Port 6422
-    user carya
-    ForwardX11Trusted yes
-

This will allow you to SSH into the VM with the simplified command, ssh pecan-vm.

-
-
-

9.3 Connecting to BETYdb on the VM via SSH

-

Sometimes, you may want to develop code locally but connect to an instance of BETYdb on the VM. -To do this, first open a new terminal and connect to the VM while enabling port forwarding (with the -L flag) and setting the port number. Using 5433 does not conflict with the postgres default port of 5432, the forwarded port will not conflict with a postgres database server running locally.

-
ssh -L 5433:localhost:5432 carya@localhost:6422
-

This makes port 5433 on the local machine match port 5432 on the VM. -This means that connecting to localhost:5433 will give you access to BETYdb on the VM.

-

To test this on the command line, try the following command, which, if successful, will drop you into the psql console.

-
psql -d bety -U bety -h localhost -p 5433
-

To test this in R, open a Postgres using the analogous parameters:

-
library(RPostgres)
-con <- dbConnect(
-  Postgres(),
-  user = "bety",
-  password = "bety",
-  dbname = "bety",
-  host = "localhost",
-  port = 5433
-  )
-dbListTables(con)   # This should return a vector of bety tables
-

Note that the same general approach will work on any BETYdb server where port forwarding is enabled, but it requires ssh access.

-
-

9.3.1 Using Amazon Web Services for a VM (AWS)

-

Login to Amazon Web Services (AWS) and select the EC2 Dashboard. If this is your first time using AWS you will need to set up an account before you are able to access the EC2 Dashboard. Important: You will need a credit card number and access to a phone to be able to verify AWS account registration. AWS is free for one year.

-
    -
  1. Choose AMI
  2. -
-
    -
  • On the top right next to your name, make sure the location setting is on U.S. East (N. Virginia), not U.S. West (Oregon)
  • -
  • On the left click, click on EC2 (Virtual servers), then click on “AMIs”, also on the left
  • -
  • In the search window toggle to change “Owned by me” to “Public images”
  • -
  • Type “pecan” into the search window
  • -
  • Click on the toggle button on the left next to PEcAn1.4.6
  • -
  • Click on the “Launch” button at the top
  • -
-
    -
  1. Choose an Instance Type
  2. -
-
    -
  • Select what type of machine you want to run. For this demo the default, t2.micro, will be adequate. Be aware that different machine types incur very different costs, from 1.3 cents/hour to over $5/hr https://aws.amazon.com/ec2/pricing/
    -
  • -
  • Select t2.micro, then click “Next: Configure Instance Details”
  • -
-
    -
  1. Configure Instance Details
  2. -
-
    -
  • The defaults are OK. Click “Next: Add Storage”
  • -
-
    -
  1. Add Storage
  2. -
-
    -
  • The defaults are OK. Click “Next: Tag Instance”
  • -
-
    -
  1. Tag Instance
  2. -
-
    -
  • You can name your instance if you want. Click “Next: Configure Security Group”
  • -
-
    -
  1. Configure Security Group
  2. -
-
    -
  • You will need to add two new rules:
  • -
  • Click “Add Rule” then select “HTTP” from the pull down menu. This rule allows you to access the webserver on PEcAn.
  • -
  • Click “Add Rule”, leave the pull down on “Custom TCP Rule”, and then change the Port Range from 0 to 8787. Set “Source” to Anywhere. This rule allows you to access RStudio Server on PEcAn.
  • -
  • Click “Review and Launch” . You will then see this pop-up:
  • -
-

-

Select the default drive volume type and click Next

-
    -
  1. Review and Launch
  2. -
-
    -
  • Review the settings and then click “Launch”, which will pop up a select/create Key Pair window.
  • -
-
    -
  1. Key Pair
  2. -
-
    -
  • Select “Create a new key pair” and give it a name. You won’t actually need this key unless you need to SSH into your PEcAn server, but AWS requires you to create one. Click on “Download Key Pair” then on “Launch Instances”. Next click on “View Instances” at the bottom of the following page.
  • -
-

-
    -
  1. Instances
  2. -
-
    -
  • You will see the status of your PEcAn VM, which will take a minute to boot up. Wait until the Instance State reads “running”. The most important piece of information here is the Public IP, which is the URL you will need in order to access your PEcAn instance from within your web browser (see Demo 1 below).
  • -
  • Be aware that it often takes ~1 hr for AWS instances to become fully operational, so if you get an error when you put the Public IP in you web browser, most of the time you just need to wait a bit longer. -Congratulations! You just started a PEcAn server in the “cloud”!
  • -
-
    -
  1. When you are done using PEcAn, you will want to return to the “Instances” menu to turn off your VM.
  2. -
-
    -
  • To STOP the instance (which will turn the machine off but keep your work), select your PEcAn instance and click Actions > Instance state > Stop. Be aware that a stopped instance will still accrue a small storage cost on AWS. To restart this instance at any point in the future you do not want to repeat all the steps above, but instead you just need to select your instance and then click Actions > Instance state > Start
  • -
  • To TERMINATE the instance (which will DELETE your PEcAn machine), select your instance and click Actions > Instance state > Terminate. Terminated instances will not incur costs. In most cases you will also want to go to the Volumes menu and delete the storage associated with your PEcAn VM.Remember, AWS is free for one year, but will automatically charge a fee in second year if account is not cancelled.
  • -
-
-
-

9.3.2 Creating a Virtual Machine

-

First create virtual machine

-
# ----------------------------------------------------------------------
-# CREATE VM USING FOLLOWING:
-# - VM NAME  = PEcAn
-# - CPU      = 2
-# - MEMORY   = 2GB 
-# - DISK     = 100GB
-# - HOSTNAME = pecan
-# - FULLNAME = PEcAn Demo User
-# - USERNAME = xxxxxxx
-# - PASSWORD = yyyyyyy
-# - PACKAGE  = openssh
-# ----------------------------------------------------------------------
-

To enable tunnels run the following on the host machine:

- -

Make sure machine is up to date.

-

UBUNTU

- -

CENTOS/REDHAT

- -

Install compiler and other packages needed and install the tools.

-

UBUNTU

- -

CENTOS/REDHAT

- -

Install Virtual Box additions for better integration

- -

Finishing up the machine

-

Add a message to the login:

- -

Finishing up

-

Script to clean the VM and remove as much as possible history cleanvm.sh

- -

Make sure machine has SSH keys rc.local

- -

Change the resolution of the console

- -

Once all done, stop the virtual machine

- - -
-
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - - diff --git a/master/02_demos_tutorials_workflows/02_user_demos/05_advanced_user_guide/images/Input_ID_name.png b/master/02_demos_tutorials_workflows/02_user_demos/05_advanced_user_guide/images/Input_ID_name.png deleted file mode 100644 index 522387163..000000000 Binary files a/master/02_demos_tutorials_workflows/02_user_demos/05_advanced_user_guide/images/Input_ID_name.png and /dev/null differ diff --git a/master/02_demos_tutorials_workflows/02_user_demos/05_advanced_user_guide/images/data-ingest/D1Ingest-1.gif b/master/02_demos_tutorials_workflows/02_user_demos/05_advanced_user_guide/images/data-ingest/D1Ingest-1.gif deleted file mode 100644 index ee022c53a..000000000 Binary files a/master/02_demos_tutorials_workflows/02_user_demos/05_advanced_user_guide/images/data-ingest/D1Ingest-1.gif and /dev/null differ diff --git a/master/02_demos_tutorials_workflows/02_user_demos/05_advanced_user_guide/images/data-ingest/D1Ingest-9_sm.gif b/master/02_demos_tutorials_workflows/02_user_demos/05_advanced_user_guide/images/data-ingest/D1Ingest-9_sm.gif deleted file mode 100644 index ffc950afa..000000000 Binary files a/master/02_demos_tutorials_workflows/02_user_demos/05_advanced_user_guide/images/data-ingest/D1Ingest-9_sm.gif and /dev/null differ diff --git a/master/02_demos_tutorials_workflows/02_user_demos/05_advanced_user_guide/images/data-ingest/DateTime.gif b/master/02_demos_tutorials_workflows/02_user_demos/05_advanced_user_guide/images/data-ingest/DateTime.gif deleted file mode 100644 index a6c14005b..000000000 Binary files a/master/02_demos_tutorials_workflows/02_user_demos/05_advanced_user_guide/images/data-ingest/DateTime.gif and /dev/null differ diff --git a/master/02_demos_tutorials_workflows/02_user_demos/05_advanced_user_guide/images/data-ingest/Local_loader_sm.gif b/master/02_demos_tutorials_workflows/02_user_demos/05_advanced_user_guide/images/data-ingest/Local_loader_sm.gif deleted file mode 100644 index 33f248ec2..000000000 Binary files a/master/02_demos_tutorials_workflows/02_user_demos/05_advanced_user_guide/images/data-ingest/Local_loader_sm.gif and /dev/null differ diff --git a/master/02_demos_tutorials_workflows/02_user_demos/05_advanced_user_guide/images/data-ingest/Selectize_Input_sm.gif b/master/02_demos_tutorials_workflows/02_user_demos/05_advanced_user_guide/images/data-ingest/Selectize_Input_sm.gif deleted file mode 100644 index e5c0a3786..000000000 Binary files a/master/02_demos_tutorials_workflows/02_user_demos/05_advanced_user_guide/images/data-ingest/Selectize_Input_sm.gif and /dev/null differ diff --git a/master/02_demos_tutorials_workflows/02_user_demos/05_advanced_user_guide/images/data-ingest/local_browse.gif b/master/02_demos_tutorials_workflows/02_user_demos/05_advanced_user_guide/images/data-ingest/local_browse.gif deleted file mode 100644 index 6f2cff7c1..000000000 Binary files a/master/02_demos_tutorials_workflows/02_user_demos/05_advanced_user_guide/images/data-ingest/local_browse.gif and /dev/null differ diff --git a/master/02_demos_tutorials_workflows/02_user_demos/05_advanced_user_guide/images/data-ingest/new_format_record.gif b/master/02_demos_tutorials_workflows/02_user_demos/05_advanced_user_guide/images/data-ingest/new_format_record.gif deleted file mode 100644 index 53e7b0de2..000000000 Binary files a/master/02_demos_tutorials_workflows/02_user_demos/05_advanced_user_guide/images/data-ingest/new_format_record.gif and /dev/null differ diff --git a/master/02_demos_tutorials_workflows/02_user_demos/05_advanced_user_guide/images/example_data.png b/master/02_demos_tutorials_workflows/02_user_demos/05_advanced_user_guide/images/example_data.png deleted file mode 100644 index 7677021d1..000000000 Binary files a/master/02_demos_tutorials_workflows/02_user_demos/05_advanced_user_guide/images/example_data.png and /dev/null differ diff --git a/master/02_demos_tutorials_workflows/02_user_demos/05_advanced_user_guide/images/format_record_1.png b/master/02_demos_tutorials_workflows/02_user_demos/05_advanced_user_guide/images/format_record_1.png deleted file mode 100644 index edea276a9..000000000 Binary files a/master/02_demos_tutorials_workflows/02_user_demos/05_advanced_user_guide/images/format_record_1.png and /dev/null differ diff --git a/master/02_demos_tutorials_workflows/02_user_demos/05_advanced_user_guide/images/format_record_2.png b/master/02_demos_tutorials_workflows/02_user_demos/05_advanced_user_guide/images/format_record_2.png deleted file mode 100644 index f3362db18..000000000 Binary files a/master/02_demos_tutorials_workflows/02_user_demos/05_advanced_user_guide/images/format_record_2.png and /dev/null differ diff --git a/master/03_topical_pages/11_images/bety_main_page.png b/master/03_topical_pages/11_images/bety_main_page.png deleted file mode 100644 index 5b268b414..000000000 Binary files a/master/03_topical_pages/11_images/bety_main_page.png and /dev/null differ diff --git a/master/03_topical_pages/11_images/bety_modeltype_1.png b/master/03_topical_pages/11_images/bety_modeltype_1.png deleted file mode 100644 index cec1a21ff..000000000 Binary files a/master/03_topical_pages/11_images/bety_modeltype_1.png and /dev/null differ diff --git a/master/03_topical_pages/11_images/bety_modeltype_2.png b/master/03_topical_pages/11_images/bety_modeltype_2.png deleted file mode 100644 index fd3fbb516..000000000 Binary files a/master/03_topical_pages/11_images/bety_modeltype_2.png and /dev/null differ diff --git a/master/03_topical_pages/11_images/bety_new_model.png b/master/03_topical_pages/11_images/bety_new_model.png deleted file mode 100644 index 24860308e..000000000 Binary files a/master/03_topical_pages/11_images/bety_new_model.png and /dev/null differ diff --git a/master/03_topical_pages/11_images/bety_pft_1.png b/master/03_topical_pages/11_images/bety_pft_1.png deleted file mode 100644 index a5226b4b9..000000000 Binary files a/master/03_topical_pages/11_images/bety_pft_1.png and /dev/null differ diff --git a/master/03_topical_pages/11_images/bety_pft_2.png b/master/03_topical_pages/11_images/bety_pft_2.png deleted file mode 100644 index 705fc5d0b..000000000 Binary files a/master/03_topical_pages/11_images/bety_pft_2.png and /dev/null differ diff --git a/master/03_topical_pages/11_images/bety_pft_3.png b/master/03_topical_pages/11_images/bety_pft_3.png deleted file mode 100644 index b09ce8708..000000000 Binary files a/master/03_topical_pages/11_images/bety_pft_3.png and /dev/null differ diff --git a/master/03_topical_pages/11_images/bety_priors_1.png b/master/03_topical_pages/11_images/bety_priors_1.png deleted file mode 100644 index 0202d4b49..000000000 Binary files a/master/03_topical_pages/11_images/bety_priors_1.png and /dev/null differ diff --git a/master/03_topical_pages/11_images/bety_priors_2.png b/master/03_topical_pages/11_images/bety_priors_2.png deleted file mode 100644 index bef439213..000000000 Binary files a/master/03_topical_pages/11_images/bety_priors_2.png and /dev/null differ diff --git a/master/03_topical_pages/11_images/bety_priors_3.png b/master/03_topical_pages/11_images/bety_priors_3.png deleted file mode 100644 index f9241fe70..000000000 Binary files a/master/03_topical_pages/11_images/bety_priors_3.png and /dev/null differ diff --git a/master/03_topical_pages/11_images/bety_priors_4.png b/master/03_topical_pages/11_images/bety_priors_4.png deleted file mode 100644 index c7a9109ba..000000000 Binary files a/master/03_topical_pages/11_images/bety_priors_4.png and /dev/null differ diff --git a/master/03_topical_pages/11_images/bety_priors_5.png b/master/03_topical_pages/11_images/bety_priors_5.png deleted file mode 100644 index 67f5d8e78..000000000 Binary files a/master/03_topical_pages/11_images/bety_priors_5.png and /dev/null differ diff --git a/master/03_topical_pages/11_images/remotemodule.png b/master/03_topical_pages/11_images/remotemodule.png deleted file mode 100644 index 2d6f18309..000000000 Binary files a/master/03_topical_pages/11_images/remotemodule.png and /dev/null differ diff --git a/master/03_topical_pages/11_images/var_record.png b/master/03_topical_pages/11_images/var_record.png deleted file mode 100644 index a58996876..000000000 Binary files a/master/03_topical_pages/11_images/var_record.png and /dev/null differ diff --git a/master/03_topical_pages/94_docker/pecan-docker.png b/master/03_topical_pages/94_docker/pecan-docker.png deleted file mode 100644 index eb44a8928..000000000 Binary files a/master/03_topical_pages/94_docker/pecan-docker.png and /dev/null differ diff --git a/master/404.html b/master/404.html deleted file mode 100644 index 957550138..000000000 --- a/master/404.html +++ /dev/null @@ -1,864 +0,0 @@ - - - - - - - Page not found | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

Page not found

-

The page you requested cannot be found (perhaps it was moved or renamed).

-

You may want to try searching to find the page's new location, or use -the table of contents to find the page you are looking for.

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/LoadData.html b/master/LoadData.html deleted file mode 100644 index 387a50c4a..000000000 --- a/master/LoadData.html +++ /dev/null @@ -1,1045 +0,0 @@ - - - - - - - 18.1 Loading Data in PEcAn | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

18.1 Loading Data in PEcAn

-

If you are loading data in to PEcAn for benchmarking, using the Benchmarking shiny app [provide link?] is recommended.

-

Data can be loaded manually using the load_data function which in turn requires providing data format information using query.format.vars and the path to the data using query.file.path.

-

Below is a description of the load_data function an a simple example of loading data manually.

-
-

18.1.1 Inputs

-

Required

-
    -
  • data.path: path to the data that is the output of the function query.file.path (see example below)
  • -
  • format: R list object that is the output of the function query.format.vars (see example below)
  • -
-

Optional

-
    -
  • start_year = NA:
  • -
  • end_year = NA:
  • -
  • site = NA
  • -
  • vars.used.index=NULL
  • -
-
-
-

18.1.2 Output

-
    -
  • R data frame containing the requested variables converted in to PEcAn standard name and units and time steps in POSIX format.
  • -
-
-
-

18.1.3 Example

-

The data for this example has already been entered in to the database. To add new data go to new data documentation.

-

To load the Ameriflux data for the Harvard Forest (US-Ha1) site.

-
    -
  1. Create a connection to the BETY database. This can be done using R function
  2. -
-
bety = PEcAn.DB::betyConnect(php.config = "pecan/web/config.php")
-

where the complete path to the config.php is specified. See here for an example config.php file.

-
    -
  1. Look up the inputs record for the data in BETY.
  2. -
-

-

To find the input ID, either look at

-
    -
  • The url of the record (see image above)

    -
      -
    • In R run
    • -
  • -
-
library(dplyr)
-input_name = "AmerifluxLBL_site_0-758" #copied directly from online
-input.id = tbl(bety,"inputs") %>% filter(name == input_name) %>% pull(id)
-
    -
  1. Additional arguments to query.format.vars are optional

    -
      -
    1. If you only want to load a subset of dates in the data, specify start and end year, otherwise all data will be loaded.
    2. -
    3. If you only want to load a select list of variables from the data, look up their IDs in BETY, otherwise all variables will be loaded.
    4. -
  2. -
  3. In R run

  4. -
-
   format = PEcAn.DB::query.format.vars(bety, input.id)
-

Examine the resulting R list object to make sure it returned the correct information.

-

The example format contains the following objects:

-
   $file_name
-   [1] "AMERIFLUX_BASE_HH"
-
-   $mimetype
-   [1] "csv"
-
-   $skip
-   [1] 2
-
-   $header
-   [1] 1
-
-   $na.strings
-   [1] "-9999" "-6999" "9999"  "NA"   
-
-   $time.row
-   [1] 4
-
-   $site
-   [1] 758
-
-   $lat
-   [1] 42.5378
-
-   $lon
-   [1] -72.1715
-
-   $time_zone
-   [1] "America/New_York"
-

The first 4 rows of the table format$vars looks like this:

- ------------- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bety_namevariable_idinput_nameinput_unitsstorage_typecolumn_numberbety_unitsmstmip_namemstmip_unitspecan_namepecan_units
air_pressure554PAkPa19PaPsurfPaPsurfPa
airT86TAcelsius4degrees CTairKTairK
co2atm135CO2_1umol mol-120umol mol-1CO2airmicromol mol-1CO2airmicromol mol-1
datetime5000000001TIMESTAMP_STARTymd_hms%Y%m%d%H%M1ymd_hmsNANAdatetimeymd_hms
-
    -
  1. Get the path to the data
  2. -
-
   data.path = PEcAn.DB::query.file.path(
-     input.id = input.id, 
-     host_name = PEcAn.remote::fqdn(), 
-     con = bety)
-
    -
  1. Load the data
  2. -
-
   data = PEcAn.benchmark::load_data(data.path = data.path, format = format)
-
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/NewBenchmark.html b/master/NewBenchmark.html deleted file mode 100644 index 3cb86b31c..000000000 --- a/master/NewBenchmark.html +++ /dev/null @@ -1,865 +0,0 @@ - - - - - - - 20.6 Creating a new benchmark reference run | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

20.6 Creating a new benchmark reference run

-

The purpose of the reference run record in BETY is to store all the settings from a run that are necessary in exactly recreating it.

-

The pecan.xml file is the home of absolutely all the settings for a particular run in pecan. However, much of the information in the pecan.xml file is server and user specific and more importantly, the pecan.xml files are stored on individual servers and may not be available to the public.

-

When a run that is performed using pecan is registered as a reference run, the settings that were used to make that run are made available to all users through the database.

-

All completed runs are not automatically registered as reference runs. To register a run, navigate to the benchmarking section of the workflow visualizations Shiny app.

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/NewFormat.html b/master/NewFormat.html deleted file mode 100644 index d466d0db8..000000000 --- a/master/NewFormat.html +++ /dev/null @@ -1,1023 +0,0 @@ - - - - - - - 20.5 Creating a new format | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

20.5 Creating a new format

-
-

20.5.1 Formats in BETY

-

The PEcAn database keeps track of all the input files passed to models, as well as any data used in model validation or data assimilation. Before we start to register these files with PEcAn we need to define the format these files will be in.

-

The main goal is to take all the meta-data we have about a data file and create a record of it that pecan can use as a guide when parsing the data file.

-

This information is stored in a Format record in the bety database. Make sure to read through the current Formats before deciding to make a new one.

-
-
-

20.5.2 Creating a new format in BETY

-

If the Format you are looking for is not available, you will need to create a new record. Before entering information into the database, you need to be able to answer the following questions about your data:

-
    -
  • What is the file MIME type? -
      -
    • We have a suit of functions for loading in data in open formats such as CSV, txt, netCDF, etc.
    • -
    • PEcAn has partnered with the NCSA BrownDog project to create a service that can read and convert as many data formats as possible. If your file type is less common or a proprietary type, you can use the BrownDog DAP to convert it to a format that can be used with PEcAn.
    • -
    • If BrownDog cannot convert your data, you will need to contact us about writing a data specific load function.
    • -
  • -
  • What variables does the file contain? -
      -
    • What are the variables named?
    • -
    • What are the variable units?
    • -
    • How do the variable names and units in the data map to PEcAn variables in the BETY database? See below for an example. It is most likely that you will NOT need to add variables to BETY. However, identifying the appropriate variables matches in the database may require some work. We are always available to help answer your questions.
    • -
  • -
  • Is there a timestamp on the data? -
      -
    • What are the units of time?
    • -
  • -
-

Here is an example using a fake dataset:

-
- -

example_data

-
-

This data started out as an excel document, but was saved as a CSV file.

-

To create a Formats record for this data, in the web interface of BETY, select Runs > Formats and click New Format.

-

You will need to fill out the following fields:

-
    -
  • MIME type: File type (you can search for other formats in the text field)
  • -
  • Name: The name of your format (this can be whatever you want)
  • -
  • Header: Boolean that denotes whether or not your data contains a header as the first line of the data. (1 = TRUE, 0 = FALSE)
  • -
  • Skip: The number of lines above the data that should be skipped. For example, metadata that should not be included when reading in the data or blank spaces.
  • -
  • Notes: Any additional information about the data such as sources and citations.
  • -
-

Here is the Formats record for the example data:

-
- -

format_record_1

-
-

When you have finished this section, hit Create. The final record will be displayed on the screen.

-
-

20.5.2.1 Formats -> Variables

-

After a Format entry has been created, you are encouraged to edit the entry to add relationships between the file’s variables and the Variables table in PEcAn. Not only do these relationships provide meta-data describing the file format, but they also allow PEcAn to search and (for some MIME types) read files.

-

To enter this data, select Edit Record and on the edit screen select View Related Variable.

-

Here is the record for the example data after adding related variables:

-
- -

format_record_2

-
-
-
20.5.2.1.1 Name and Unit
-

For each variable in the file you will want at a minimum to specify the NAME of the variable within your file and match that to the equivalent Variable in the pulldown.

-

Make sure to search for your variables under Data > Variables before suggesting that we create a new variable record. This may not always be a straightforward process.

-

For example bety contains a record for Net Primary Productivity:

-
- -

var_record

-
-

This record does not have the same variable name or the same units as NPP in the example data. -You may have to do some reading to confirm that they are the same variable. -In this case -- Both the data and the record are for Net Primary Productivity (the notes section provides additional resources for interpreting the variable.) -- The units of the data can be converted to those of the vairiable record (this can be checked by running udunits2::ud.are.convertible("g C m-2 yr-1", "Mg C ha-1 yr-1"))

-

Differences between the data and the variable record can be accounted for in the data Formats record.

-
    -
  • Under Variable, select the variable as it is recorded in bety.
  • -
  • Under Name, write the name the variable has in your data file.
  • -
  • Under Unit, write the units the variable has in your data file.
  • -
-

NOTE: All units must be written in a udunits compliant format. To check that your units can be read by udunits, in R, load the udunits2 package and run udunits2::is.parseable("g C m-2 yr-1")

-

If the name or the units are the same, you can leave the Name and Unit fields blank. This is can be seen with the variable LAI.

-
-
-
20.5.2.1.2 Storage Type
-

Storage Type only needs to be specified if the variable is stored in a format other than what would be expected (e.g. if numeric values are stored as quoted character strings).

-

One such example is time variables.

-

PEcAn converts all dates into POSIX format using R functions such as strptime. These functions require that the user specify the format in which the date is written.

-

The default is "%Y-%m-%d %H:%M:%S" which would look like "2017-01-01 00:00:00"

-

A list of date formats can be found in the R documentation for the function strptime

-

Below are some commonly used codes:

- ---- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
%dDay of the month as decimal number (01–31).
%DDate format such as %m/%d/%y.
%HHours as decimal number (00–23).
%mMonth as decimal number (01–12).
%MMinute as decimal number (00–59).
%SSecond as integer (00–61), allowing for up to two leap-seconds (but POSIX-compliant implementations will ignore leap seconds).
%TEquivalent to %H:%M:%S.
%yYear without century (00–99). On input, values 00 to 68 are prefixed by 20 and 69 to 99 by 19 – that is the behaviour specified by the 2004 and 2008 POSIX standards, but they do also say ‘it is expected that in a future version the default century inferred from a 2-digit year will change’.
%YYear with century.
-
-
-
20.5.2.1.3 Column Number
-

If your data is in text format with variables in a standard order then you can specify the Column Number for the variable. This is required for text files that lack headers.

-
-
-
-

20.5.2.2 Retrieving Format Information

-

To acquire Format information from a Format record, use the R function query.format.vars

-
-
20.5.2.2.1 Inputs
-
    -
  • bety: connection to BETY
  • -
  • input.id=NA and/or format.id=NA: Input or Format record ID from BETY -
      -
    • At least one must be specified. Defaults to format.id if both provided.
    • -
  • -
  • var.ids=NA: optional vector of variable IDs. If provided, limits results to these variables.
  • -
-
-
-
20.5.2.2.2 Output
-
    -
  • R list object containing many things. Fill this in.
  • -
-
-
-
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/NewInput.html b/master/NewInput.html deleted file mode 100644 index ea6897741..000000000 --- a/master/NewInput.html +++ /dev/null @@ -1,1163 +0,0 @@ - - - - - - - 20.3 Adding input data | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

20.3 Adding input data

-
-

20.3.1 Input records in BETY

-

All model input data or data used for model calibration/validation must be registered in the BETY database.

-

Before creating a new Input record, you must make sure that the format type of your data is registered in the database. If you need to make a new format record, see Creating a new format record in BETY.

-
-
-

20.3.2 Create a database file record for the input data

-

An input record contains all the metadata required to identify the data, however, this record does not include the location of the data file. Since the same data may be stored in multiple places, every file has its own dbfile record.

-

From your BETY interface:

-
    -
  • Create a DBFILES entry for the path to the file -
      -
    • From the menu click RUNS then FILES
    • -
    • Click “New File”
    • -
    • Select the machine your file is located at
    • -
    • Fill in the File Path where your file is located (aka folder or directory) NOT including the name of the file itself
    • -
    • Fill in the File Name with the name of the file itself. Note that some types of input records will refer to be ALL the files in a directory and thus File Name can be blank
    • -
    • Click Update
    • -
  • -
-
-
-

20.3.3 Creating a new Input record in BETY

-

From your BETY interface:

-
    -
  • Create an INPUT entry for your data -
      -
    • From the menu click RUNS then INPUTS
    • -
    • Click “New Input”
    • -
    • Select the SITE that this data is associated with the input data set
    • -
    • Other required fields are a unique name for the input, the start and end dates of the data set, and the format of the data. If the data is not in a currently known format you will need to create a NEW FORMAT and possibly a new input converter. Instructions on how to do add a converter can be found here Input conversion. Instructions on how to add a format record can be found here
    • -
    • Parent ID is an optional variable to indicated that one dataset was derived from another.
    • -
    • Click “Create”
    • -
  • -
  • Associate the DBFILE with the INPUT -
      -
    • In the RUNS -> INPUTS table, search and find the input record you just created
    • -
    • Click on the EDIT icon
    • -
    • Select “View related Files”
    • -
    • In the Search window, search for the DBFILE you just created
    • -
  • -
  • Once you have found the DBFILE, click on the “+” icon to add the file
  • -
  • Click on “Update” at the bottom when you are done.
  • -
-
-
-

20.3.4 Adding a new input converter

-

Three Types of data conversions are discussed below: Meteorological data, Vegetation data, and Soil data. Each section provides instructions on how to convert data from their raw formats into a PEcAn standard format, whether it be from a database or if you have raw data in hand.

-

Also, see PEcAn standard formats.

-
-

20.3.4.1 Meterological Data

-
-
20.3.4.1.1 Adding a function to PEcAn to convert a met data source
-

In general, you will need to write a function to download the raw met data and one to convert it to the PEcAn standard.

-

Downloading raw data function are named download.<source>.R. These functions are stored within the PEcAn directory: /modules/data.atmosphere/R.

-

Conversion function from raw to standard are named met2CF.<source>.R. These functions are stored within the PEcAn directory: /modules/data.atmosphere/R.

-

Current Meteorological products that are coupled to PEcAn can be found in our Available Meteorological Drivers page.

-

Note: Unless you are also adding a new model, you will not need to write a script to convert from PEcAn standard to PEcAn models. Those conversion scripts are written when a model is added and can be found within each model’s PEcAn directory.

-

Standards dimesion, names, nad units can be found here: Input Standards

-
-
-
20.3.4.1.2 Adding Single-Site Specific Meteorological Data
-

Perhaps you have meteorological data specific to one site, with a unique format that you would like to add to PEcAn. Your steps would be to: -1. write a script or function to convert your files into the netcdf PEcAn standard -2. insert that file as an input record for your site following these instructions

-
-
-
20.3.4.1.3 Processing Met data outside of the workflow using PEcAn functions
-

Perhaps you would like to obtain data from one of the sources coupled to PEcAn on its own. To do so you can run PEcAn functions on their own.

-
-
20.3.4.1.3.1 Example 1: Processing data from a database
-

Download Amerifluxlbl from Niwot Ridge for the year 2004:

-
raw.file <-PEcAn.data.atmosphere::download.AmerifluxLBL(sitename = "US-NR1", 
-                                             outfolder = ".", 
-                                             start_date = "2004-01-01", 
-                                             end_date = "2004-12-31")
-

Using the information returned as the object raw.file you will then convert the raw files into a standard file.

-

Open a connection with BETY. You may need to change the host name depending on what machine you are hosting BETY. You can find the hostname listed in the machines table of BETY.

-

-con <- PEcAn.DB::db.open(
-  params = list(
-    driver = RPostgres::Postgres(),
-    dbname   = 'bety',
-    host ='localhost',
-    user     = "bety",
-    password = "bety")
-)
-
-

Next you will set up the arguments for the function

-
in.path <- '.'
-in.prefix <- raw.file$dbfile.name
-outfolder <- '.'
-format.id <- 5000000002
-format <- PEcAn.DB::query.format.vars(format.id=format.id,bety = con)
-lon <- -105.54
-lat <- 40.03
-format$time_zone <- "America/Chicago"
-

Note: The format.id can be pulled from the BETY database if you know the format of the raw data.

-

Once these arguments are defined you can execute the met2CF.csv function

-
PEcAn.data.atmosphere::met2CF.csv(in.path = in.path, 
-                                  in.prefix =in.prefix,
-                                  outfolder = ".", 
-                                  start_date ="2004-01-01",
-                                  end_date = "2004-12-01",
-                                  lat= lat,
-                                  lon = lon,
-                                  format = format) 
-
-
-
20.3.4.1.3.2 Example 2: Processing data from data already in hand
-

If you have Met data already in hand and you would like to convert into the PEcAn standard follow these instructions.

-

Update BETY with file record, format record and input record according to this page How to Insert new Input Data

-

If your data is in a csv format you can use the met2CF.csvfunction to convert your data into a PEcAn standard file.

-

Open a connection with BETY. You may need to change the host name depending on what machine you are hosting BETY. You can find the hostname listed in the machines table of BETY.

-
con <- PEcAn.DB::db.open(
-  params = list(
-    driver = RPostgres::Postgres(),
-    dbname = 'bety',
-    host ='localhost',
-    user = "bety",
-    password = "bety")
-)
-

Prepare the arguments you need to execute the met2CF.csv function

-
in.path <- 'path/where/the/raw/file/lives'
-in.prefix <- 'prefix_of_the_raw_file'
-outfolder <- 'path/to/where/you/want/to/output/thecsv/'
-format.id <- formatid of the format your created
-format <- PEcAn.DB::query.format.vars(format.id=format.id, bety = con)
-lon <- longitude of your site
-lat <- latitude of your site
-format$time_zone <- time zone of your site
-start_date <- Start date of your data in "y-m-d"
-end_date <- End date of your data in "y-m-d"
-

Next you can execute the function:

-
PEcAn.data.atmosphere::met2CF.csv(in.path = in.path, 
-                                  in.prefix =in.prefix, 
-                                  outfolder = ".", 
-                                  start_date = start_date,
-                                  end_date = end_date,
-                                  lat= lat,
-                                  lon = lon,
-                                  format = format)
-
-
-
-
-

20.3.4.2 Vegetation Data

-

Vegetation data will be required to parameterize your model. In these examples we will go over how to produce a standard initial condition file.

-

The main function to process cohort data is the ic_process.R function. As of now however, if you require pool data you will run a separate function, pool_ic_list2netcdf.R.

-
-
20.3.4.2.0.1 Example 1: Processing Veg data from data in hand.
-

In the following example we will process vegetation data that you have in hand using PEcAn.

-

First, you’ll need to create a input record in BETY that will have a file record and format record reflecting the location and format of your file. Instructions can be found in our How to Insert new Input Data page.

-

Once you have created an input record you must take note of the input id of your record. An easy way to take note of this is in the URL of the BETY webpage that shows your input record. In this example we use an input record with the id 1000013064 which can be found at this url: https://psql-pecan.bu.edu/bety/inputs/1000013064# . Note that this is the Boston University BETY database. If you are on a different machine, your url will be different.

-

With the input id in hand you can now edit a pecan XML so that the PEcAn function ic_process will know where to look in order to process your data. The inputs section of your pecan XML will look like this. As of now ic_process is set up to work with the ED2 model so we will use ED2 settings and then grab the intermediary Rds data file that is created as the standard PEcAn file. For your Inputs section you will need to input your input id wherever you see the useic flag.

-
<inputs>
-      <css>
-        <source>FFT</source>
-        <output>css</output>
-        <username>pecan</username>
-        <id>1000013064</id>
-        <useic>TRUE</useic>
-        <metadata>
-          <trk>1</trk>
-          <age>70</age>
-          <area>400</area>
-        </metadata>
-      </css>
-      <pss>
-        <source>FFT</source>
-        <output>pss</output>
-        <username>pecan</username>
-        <id>1000013064</id>
-        <useic>TRUE</useic>
-      </pss>
-      <site>
-        <source>FFT</source>
-        <output>site</output>
-        <username>pecan</username>
-        <id>1000013064</id>
-        <useic>TRUE</useic>
-      </site>
-      <met>
-        <source>CRUNCEP</source>
-        <output>ED2</output>
-      </met>
-      <lu>
-        <id>294</id>
-      </lu>
-      <soil>
-        <id>297</id>
-      </soil>
-      <thsum>
-        <id>295</id>
-      </thsum>
-      <veg>
-        <id>296</id>
-      </veg>
-    </inputs>
-

This IC workflow also supports generating ensembles of initial conditions from posterior estimates of DBH. To do this the tags below can be inserted to the pecan.xml:

-
       <css>
-        <source>PalEON</source>
-        <output>css</output>
-        <id>1000015682</id>
-        <useic>TRUE</useic>
-        <ensemble>20</ensemble>
-        <metadata>
-          <area>1256.637</area>
-          <n.patch>3</n.patch>
-        </metadata>
-      </css>
-

Here the id should point to a file that has MCMC samples to generate the ensemble from. The number between the <ensemble> tag defines the number of ensembles requested. The workflow will populate the settings list run$inputs tag with ensemble member information. E.g.:

-
  <inputs>
-   <css>
-    <path1>...</path1>
-    <path2>...</path2>
-    <path3>...</path3>
-    ...
-    <pathN>...</pathN>
-   </css>
-   <pss>
-    <path>
-     <path1>...</path1>
-     <path2>...</path2>
-     <path3>...</path3>
-      ...
-     <pathN>...</pathN>
-    </path>
-   </pss>
-   <site>
-    <path>
-     <path1>...</path1>
-     <path2>...</path2>
-     <path3>...</path3>
-      ...
-     <pathN>...</pathN>
-    </path>
-   </site>
-   <met>...</met>
-   <lu>...</lu>
-   <soil>...</soil>
-   <thsum>...</thsum>
-   <veg>...</veg>
-  </inputs>
-

Once you edit your PEcAn.xml you can than create a settings object using PEcAn functions. Your pecan.xml must be in your working directory.

-
settings <- PEcAn.settings::read.settings("pecan.xml")
-settings <- PEcAn.settings::prepare.settings(settings, force=FALSE)
-

You can then execute the ic_process function to convert data into a standard Rds file:

-
input <- settings$run$inputs
-dir <- "."
-ic_process(settings, input, dir, overwrite = FALSE)
-

Note that the argument dir is set to the current directory. You will find the final ED2 file there. More importantly though you will find the .Rds file within the same directory.

-
-
-
20.3.4.2.0.2 Example 3 Pool Initial Condition files
-

If you have pool vegetation data, you’ll need the pool_ic_list2netcdf.R function to convert the pool data into PEcAn -standard.

-

The function stands alone and requires that you provide a named list of netcdf dimensions and values, and a named list of variables and values. Names and units need to match the standard_vars.csv table found here.

-
#Create a list object with necessary dimensions for your site
-input<-list()
-dims<- list(lat=-115,lon=45, time= 1)
-variables<- list(SoilResp=8,TotLivBiom=295)
-input$dims <- dims
-input$vals <- variables
-

Once this is done, set outdir to where you’d like the file to write out to and a siteid. Siteid in this can be used as an file name identifier. Once part of the automated workflow siteid will reflect the site id within the BET db.

-
outdir  <- "."
-siteid <- 772
-pool_ic_list2netcdf(input = input, outdir = outdir, siteid = siteid)
-

You should now have a netcdf file with initial conditions.

-
-
-
-

20.3.4.3 Soil Data

-
-
20.3.4.3.0.1 Example 1: Converting Data in hand
-

Local data that has the correct names and units can easily be written out in PEcAn standard using the function soil2netcdf.

-
soil.data <- list(volume_fraction_of_sand_in_soil = c(0.3,0.4,0.5),
-                  volume_fraction_of_clay_in_soil = c(0.3,0.3,0.3),
-                  soil_depth = c(0.2,0.5,1.0))
-                         
-soil2netcdf(soil.data,"soil.nc")
-

At the moment this file would need to be inserted into Inputs manually. By default, this function also calls soil_params, which will estimate a number of hydraulic and thermal parameters from texture. Be aware that at the moment not all model couplers are yet set up to read this file and/or convert it to model-specific formats.

-
-
-
20.3.4.3.0.2 Example 2: Converting PalEON data
-

In addition to location-specific soil data, PEcAn can extract soil texture information from the PalEON regional soil product, which itself is a subset of the MsTMIP Unified North American Soil Map. If this product is installed on your machine, the appropriate step in the do_conversions workflow is enabled by adding the following tag under <inputs> in your pecan.xml

-
   <soil>
-     <id>1000012896</id>
-   </soil>
-

In the future we aim to extend this extraction to a wider range of soil products.

-
-
-
20.3.4.3.0.3 Example 3: Extracting soil properties from gSSURGO database
-

In addition to location-specific soil data, PEcAn can extract soil texture information from the gSSURGO data product. This product needs no installation and it extract soil proeprties for the lower 48 states in U.S. In order to let the pecan know that you’re planning to use gSSURGO, you can the following XML tag under input in your pecan xml file.

-
<inputs>
-   <soil>
-     <source>gSSURGO</source>
-   </soil>
-</inputs>
-
-
-
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/about-the-pecan-book.html b/master/about-the-pecan-book.html deleted file mode 100644 index bb46372c9..000000000 --- a/master/about-the-pecan-book.html +++ /dev/null @@ -1,867 +0,0 @@ - - - - - - - 3 About the PEcAn Book | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

3 About the PEcAn Book

-

This book serves as documentation for the PEcAn Project. It contains descriptions of topics necessary to inform a beginner and advanced user as well as requisite materials for developers. It does not contain low-level descriptions of functions within PEcAn. Our aim for this documentation is to educate you about the PEcAn software, the possibilities of its usage, and the standards,expectations, and core workflows for developers.

-

This book is organized four main topics:

-

Introduction - Brief explanation of PEcAn, how to obtain the PEcAn VM, and explanation of basic web interface functions.

-

Tutorials/Demos/Workflows - All User and Developer tutorials/demos/workflows to explain how to use and add to PEcAn in different ways.

-

Topical Pages - Explanation of main PEcAn components and how they fit together.

-

Appendix - External documentation and sources of information and a FAQ section.

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/adding-data-web.html b/master/adding-data-web.html deleted file mode 100644 index 69ba521c9..000000000 --- a/master/adding-data-web.html +++ /dev/null @@ -1,933 +0,0 @@ - - - - - - - 20.4 Pecan Data Ingest via Web Interface | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

20.4 Pecan Data Ingest via Web Interface

-

This tutorial explains the process of ingesting data into PEcAn via our Data-Ingest Application. In order to ingest data, the users must first select data that they wish to upload. Then, they enter metadata to help PEcAn parse and load the data into the main PEcAn workflow.

-
-

20.4.1 Loading Data

-
-

20.4.1.1 Selecting Ingest Method

-

The Data-Ingest application is capable of loading data from the DataONE data federation and from the user’s local machine. The first step in the workflow is therefore to select an upload method. The application defaults to uploading from DataONE. To upload data from a local device, simply select the radio button titled Local Files.

-
-
-

20.4.1.2 DataONE Upload Example

-


-

-
-The DataONE download feature allows the user to download data at a given doi or DataONE specific package id. To do so, enter the doi or identifier in the Import From DataONE field and select download. The download process may take a couple of minutes to run depending on the number of files in the dataONE package. This may be a convenient option if the user does not wish to download files directly to their local machine. Once the files have been successfully downloaded from DataONE, they are displayed in a table. Before proceeding to the next step, the user can select a file to ingest by clicking on the corresponding row in the data table. -

-
-
-
-

20.4.2 Local Upload Example

-


-To upload local files, the user should first select the Local Files button. From there, the user can upload files from their local machines by selecting Browse or by dragging and dropping files into the text box. The files will begin uploading automatically. From there, the user should select a file to ingest and then select the Next Step button. -
-After this step, the workflow is identical for both methods. However, please note that if it becomes necessary to switch from loading data via DataONE to uploading local files after the first step, please restart the application. -

-

-
- -### 2. Creating an Input Record -Creating an input record requires some basic metadata about the file that is being ingested. Each entry field is briefly explained below. -

-
    -
  • Site: To link the selected file with a site, the user can scroll or type to search all the sites in PEcAn. See Example: -
    - -

  • -
  • Parent: To link the selected file with another dataset, type to search existing datasets in the Parent field.

  • -
  • Name: this field should be autofilled by selecting a file in step 1.

  • -
  • Format: If the selected file has an existing format name, the user can search and select in the Format field. If the selected file’s format is not already in pecan, the user can create a new format by selecting Create New Format. Once this new format is created, it will automatically populate the Format box and the Current Mimetype box (See Section 3).

  • -
  • Mimetype: If the format already exists, select an existing mimetype.

  • -
  • Start and End Date and Time: Inputs can be entered manually or by using the user interface. See example

  • -
-


-

-
    -
  • Notes: Describe the data that is being uploaded. Please include any citations or references.
  • -
-
-
-

20.4.3 3. Creating a format record

-

If it is necessary to add a new format to PEcAn, the user should fill out the form attached to the Create New Format button. The inputs to this form are described below:

-
    -
  • Mimetype: type to search existing mimetypes. If the mimetype is not in that list, please click on the link Create New Mimetype and create a new mimetype via the BETY website.

  • -
  • New Format Name: Add the name of the new format. Please exclude spaces from the name. Instead please use underscores “_“.

  • -
  • Header: If there is space before the first line of data in the dataset, please select Yes

  • -
  • Skip: The number of lines in the header that should be skipped before the data.

  • -
  • Please enter notes that describe the format.

  • -
-

Example: -
- -### 4. Formats_Variables Record -The final step in the ingest process is to register a formats-variables record. This record links pecan variables with variables from the selected data.

-
    -
  • Variable: PEcAn variable that is equivalent to variable in selected file.

  • -
  • Name: The variable name in the imported data need only be specified if it differs from the BETY variable name.

  • -
  • Unit: Should be in a format parseable by the udunits library and need only be secified if the units of the data in the file differ from the BETY standard.

  • -
  • Storage Type: Storage type need only be specified if the variable is stored in a format other than would be expected (e.g. if numeric values are stored as quoted character strings). Additionally, storage_type stores POSIX codes that are used to store any time variables (e.g. a column with a 4-digit year would be %Y).

  • -
  • Column Number: Vector of integers that list the column numbers associated with variables in a dataset. Required for text files that lack headers. -
    -

  • -
-

Finally, the path to the ingest data is displayed in the Select Files box.

-
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/adding-model.html b/master/adding-model.html deleted file mode 100644 index 29877fbe9..000000000 --- a/master/adding-model.html +++ /dev/null @@ -1,964 +0,0 @@ - - - - - - - 20.1 Adding An Ecosystem Model | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

20.1 Adding An Ecosystem Model

-

Adding a model to PEcAn involves two activities:

-
    -
  1. Updating the PEcAn database to register the model
  2. -
  3. Writing the interface modules between the model and PEcAn
  4. -
-

Note that coupling a model to PEcAn should not require any changes to the model code itself. A key aspect of our design philosophy is that we want it to be easy to add models to the system and we want to using the working version of the code that is used by all other model users, not a special branch (which would rapidly end up out-of-date).

-
-

20.1.1 Using PEcAn Database

-

To run a model within PEcAn requires that the PEcAn database has sufficient information about the model. This includes a MODEL_TYPE designation, the types of inputs the model requires, the location of the model executable, and the plant functional types used by the model.

-

The instructions in this section assume that you will be specifying this information using the BETYdb web-based interface. This can be done either on your local VM (localhost:3280/bety or localhost:6480/bety) or on a server installation of BETYdb. However you interact with BETYdb, we encourage you to set up your PEcAn instance to support database syncs so that these changes can be shared and backed-up across the PEcAn network.

-

-

The figure below summarizes the relevant database tables that need to be updated to add a new model and the primary variables that define each table.

-

-
-
-

20.1.2 Define MODEL_TYPE

-

The first step to adding a model is to create a new MODEL_TYPE, which defines the abstract model class. This MODEL_TYPE is used to specify input requirements, define plant functional types, and keep track of different model versions.

-

The MODEL_TYPE is created by selecting Runs > Model Type and then clicking on New Model Type. The MODEL_TYPE name should be identical to the MODEL package name (see Interface Module below) and is case sensitive.

-

-

-
-
-

20.1.3 MACHINE

-

The PEcAn design acknowledges that the same model executables and input files may exist on multiple computers. Therefore, we need to define the machine that that we are using. If you are running on the VM then the local machine is already defined as pecan. Otherwise, you will need to select Runs > Machines, click New Machine, and enter the URL of your server (e.g. pecan2.bu.edu).

-
-
-

20.1.4 MODEL

-

Next we are going to tell PEcAn where the model executable is. Select Runs > Files, and click ADD. Use the pull down menu to specify the machine you just defined above and fill in the path and name for the executable. For example, if SIPNET is installed at /usr/local/bin/sipnet then the path is /usr/local/bin/ and the file (executable) is sipnet.

-

Now we will create the model record and associate this with the File we just registered. The first time you do this select Runs > Models and click New Model. Specify a descriptive name of the model (which doesn’t have to be the same as MODEL_TYPE), select the MODEL_TYPE from the pull down, and provide a revision identifier for the model (e.g. v3.2.1). Once the record is created select it from the Models table and click EDIT RECORD. Click on “View Related Files” and when the search window appears search for the model executable you just added (if you are unsure which file to choose you can go back to the Files menu and look up the unique ID number). You can then associate this Model record with the File by clicking on the +/- symbol. By contrast, clicking on the name itself will take you to the File record.

-

In the future, if you set up the SAME MODEL VERSION on a different computer you can add that Machine and File to PEcAn and then associate this new File with this same Model record. A single version of a model should only be entered into PEcAn once.

-

If a new version of the model is developed that is derived from the current version you should add this as a new Model record but with the same MODEL_TYPE as the original. Furthermore, you should set the previous version of the model as Parent of this new version.

-
-
-

20.1.5 FORMATS

-

The PEcAn database keep track of all the input files passed to models, as well as any data used in model validation or data assimilation. Before we start to register these files with PEcAn we need to define the format these files will be in. To create a new format see Formats Documentation.

-
-
-

20.1.6 MODEL_TYPE -> Formats

-

For each of the input formats you specify for your model, you will need to edit your MODEL_TYPE record to add an association between the format and the MODEL_TYPE. Go to Runs > Model Type, select your record and click on the Edit button. Next, click on “Edit Associated Formats” and choose the Format you just defined from the pull down menu. If the Input box is checked then all matching Input records will be displayed in the PEcAn site run selection page when you are defining a model run. In other words, the set of model inputs available through the PEcAn web interface is model-specific and dynamically generated from the associations between MODEL_TYPEs and Formats. If you also check the Required box, then the Input will be treated as required and PEcAn will not run the model if that input is not available. Furthermore, on the site selection webpage, PEcAn will filter the available sites and only display pins on the Google Map for sites that have a full set of required inputs (or where those inputs could be generated using PEcAn’s workflows). Similarly, to make a site appear on the Google Map, all you need to do is specify Inputs, as described in the next section, and the point should automatically appear on the map.

-
-
-

20.1.7 INPUTS

-

After a file Format has been created then input files can be registered with the database. Creating Inputs can be found under How to insert new Input data.

-
-
-

20.1.8 Add Plant Functional Types (PFTs)

-

Since many of the PEcAn tools are designed to keep track of parameter uncertainties and assimilate data into models, to use PEcAn with a model it is important to define Plant Functional Types for the sites or regions that you will be running the model.

-

Create a new PFT entry by selecting Data > PFTs and then clicking on New PFT.

-

-

-

Give the PFT a descriptive name (e.g., temperate deciduous). PFTs are MODEL_TYPE specific, so choose your MODEL_TYPE from the pull down menu.

-

-
-

20.1.8.1 Species

-

Within PEcAn there are no predefined PFTs and user can create new PFTs very easily at whatever taxonomic level is most appropriate, from PFTs for individual species up to one PFT for all plants globally. To allow PEcAn to query its trait database for information about a PFT, you will want to associate species with the PFT record by choosing Edit and then “View Related Species”. Species can be searched for by common or scientific name and then added to a PFT using the +/- button.

-
-
-

20.1.8.2 Cultivars

-

You can also define PFTs whose members are cultivars instead of species. This is designed for analyses where you want to want to perform meta-analysis on within-species comparisons (e.g. cultivar evaluation in an agricultural model) but may be useful for other cases when you want to specify different priors for some member of a species. You cannot associate both species and cultivars with the same PFT, but the cultivars in a cultivar PFT may come from different species, potentially including all known cultivars from some of the species, if you wish to and have thought about how to interpret the results.

-

It is not yet possible to add a cultivar PFT through the BETYdb web interface. See this GithHub comment for an example of how to define one manually in PostgreSQL.

-
-
-
-

20.1.9 Adding Priors for Each Variable

-

In addition to adding species, a PFT is defined in PEcAn by the list of variables associated with the PFT. PEcAn takes a fundamentally Bayesian approach to representing model parameters, so variables are not entered as fixed constants but as prior probability distributions.

-

There are a wide variety of priors already defined in the PEcAn database that often range from very diffuse and generic to very informative priors for specific PFTs.

-

These pre-existing prior distributions can be added to a PFT. Navigate to the PFT from Data > PFTs and selecting the edit button in the Actions column for the chosen PFT.

-

-

Click on “View Related Priors” button and search through the list for desired prior distributions. The list can be filtered by adding terms into the search box. Add a prior to the PFT by clicking on the far left button for the desired prior, changing it to an X.

-

-

Save this by scrolling to the bottom of the PFT page and hitting the Update button.

-

-
-

20.1.9.1 Creating new prior distributions

-

A new prior distribution can be created for a pre-existing variable, if a more constrained or specific one is known.

-
    -
  • Select Data > Priors then “New Prior”
  • -
  • In the Citation box, type in or select an existing reference that indicates how the prior was defined. There are a number of unpublished citations in current use that simply state the expert opinion of an individual
  • -
  • Fill the Variable box by typing in part or all of a pre-existing variable’s name and selecting it
  • -
  • The Phylogeny box allows one to specify what taxonomic grouping the prior is defined for, at it is important to note that this is just for reference and doesn’t have to be specified in any standard way nor does it have to be monophyletic (i.e. it can be a functional grouping)
  • -
  • The prior distribution is defined by choosing an option from the drop-down Distribution box, and then specifying values for both Parameter a and Parameter b. The exact meaning of the two parameters depends on the distribution chosen. For example, for the Normal distribution a and b are the mean and standard deviation while for the Uniform they are the minimum and maximum. All parameters are defined based on their standard parameterization in the R language
  • -
  • Specify the prior sample size in N if the prior is based on observed data (independent of data in the PEcAn database)
  • -
  • When this is done, scroll down and hit the Create button
  • -
-

-

The new prior distribution can then be added a PFT as described in the “Adding Priors for Each Variable” section.

-
-
-

20.1.9.2 Creating new variables

-

It is important to note that the priors are defined for the variable name and units as specified in the Variables table. If the variable name or units is different within the model it is the responsibility of write.configs.MODEL function to handle name and unit conversions (see Interface Modules below). This can also include common but nonlinear transformations, such as converting SLA to LMA or changing the reference temperature for respiration rates.

-

To add a new variable, select Data > Variables and click the New Variable button. Fill in the Name field with the desired name for the variable and the units in the Units field. There are additional fields, such as Standard Units, Notes, and Description, that can be filled out if desired. When done, hit the Create button.

-

-

The new variable can be used to create a prior distribution for it as in the “Creating new prior distributions” section.

-
-
-
-

20.1.10 Interface Modules

-
-

20.1.10.1 Setting up the module directory (required)

-

PEcAn assumes that the interface modules are available as an R package in the models directory named after the model in question. The simplest way to get started on that R package is to make a copy the template directory in the pecan/models folder and re-name it to the name of your model. In the code, filenames, and examples below you will want to substitute the word MODEL for the name of your model (note: R is case-sensitive).

-

If you do not want to write the interface modules in R then it is fairly simple to set up the R functions describe below to just call the script you want to run using R’s system command. Scripts that are not R functions should be placed in the inst folder and R can look up the location of these files using the function system.file which takes as arguments the local path of the file within the package folder and the name of the package (typically PEcAn.MODEL). For example

-
-
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/adding-to-pecan.html b/master/adding-to-pecan.html deleted file mode 100644 index 14f3334b7..000000000 --- a/master/adding-to-pecan.html +++ /dev/null @@ -1,890 +0,0 @@ - - - - - - - 20 Adding to PEcAn | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

20 Adding to PEcAn

-
    -
  • Case studies -
  • -
  • Reference (How to edit records in bety) -
      -
    • Models
    • -
    • Species
    • -
    • PFTs
    • -
    • Traits
    • -
    • Inputs
    • -
    • DB files
    • -
    • Variables
    • -
    • Formats
    • -
    • (Link each section to relevant Bety tables)
    • -
  • -
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/additional-web-configuration.html b/master/additional-web-configuration.html deleted file mode 100644 index 0a41ebccf..000000000 --- a/master/additional-web-configuration.html +++ /dev/null @@ -1,902 +0,0 @@ - - - - - - - 7.1 Additional web configuration | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

7.1 Additional web configuration

-

Additional settings for web configuration:

-
    -
  • Web interface setup
  • -
  • Brown Dog
  • -
  • Advanced setup -
      -
    • [Sensitivity analysis] (TODO)
    • -
    • [Uncertainty analysis] (TODO)
    • -
  • -
  • Editing model configuration files
  • -
-
-

7.1.1 Web interface setup

-

There are few options which you can change via web interface.

-

To visit the configuration page either you can just click on the setups link on the introduction page alternatively can type <host>/setups/.

-

The list of configuration available

-
    -
  1. Database configuration : BETYdb(Biofuel Ecophysiological Traits and Yields database) configuration details, can be edited according to need.

  2. -
  3. Browndog configuration : Browndog configuration details, Used to connect browndog. Its included by default in VM.

  4. -
  5. FIA Database : FIA(Forest Inventory and Analysis) Database configuration details, Can be used to add additional data to models.

  6. -
  7. Google MapKey : Google Map key, used to access the google map by PEcAn.

  8. -
  9. Change Password : A small infomation to change the VM user password. (if using Docker image it won’t work)

  10. -
  11. Automatic Sync : If ON then it will sync the database between local machine and the remote servers. Still unders testing part might be buggy.

  12. -
-

Still work on the adding other editing feature going on, this page will be updated as new configuration will be available.

-
-
-

7.1.2 Brown Dog

-

The Browndog service provides PEcAn with access to large and diverse sets of data at the click of a button in the format that PEcAn needs. By clicking the checkbox you will be using the Browndog Service to process data.

-

For more information regarding meteorological data check out Available Meteorological Drivers.

-

More information can be found at the Browndog website.

-
-
-

7.1.3 Advanced Setup

-

(TODO: Under construction…)

-
-
-

7.1.4 Editing model configurations

-

(TODO: Under construction…)

- -
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/advanced-user.html b/master/advanced-user.html deleted file mode 100644 index 506b12fb0..000000000 --- a/master/advanced-user.html +++ /dev/null @@ -1,928 +0,0 @@ - - - - - - - 5.6 Advanced User Guide | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

5.6 Advanced User Guide

- - -
-

5.6.1 Submitting Workflow from Command Line

-

This is how you can submit a workflow from the command line through the pecan web interface. This will use curl to submit all the requireed parameters to the web interface and trigger a run.

-
# the host where the model should run
-# never use remote sites since you will need to pass your username/password and that WILL be stored
-hostname=pecan.vm
-# the site id where to run the model (NIWOT in this case)
-siteid=772
-# start date and end date, / need to be replaced with %2F or use - (NOT TESTED)
-start=2004-01-01
-end=2004-12-31
-
-# if of model you want to run, rest of section parameters depend on the model selected (SIPNET 136)
-modelid=5000000002
-# PFT selected (we should just use a number here)
-# NOTE: the square brackets are needed and will need be escaped with a \ if you call this from command line
-pft[]=temperate.coniferous
-# initial pool condition (-1 means nothing is selected)
-input_poolinitcond=-1
-# met data
-input_met=99000000006
-
-# variables to collect
-variables=NPP,GPP
-# ensemble size
-runs=10
-# use sensitivity analysis
-sensitivity=-1,1
-
-# redirect to the edit pecan.xml file
-pecan_edit=on
-# redirect to edit the model configuration files
-model_edit=on
-# use browndog
-browndog=on
-

For example the following will run the above workflow. Using -v in curl will show verbose output (needed) and the grep will make sure it only shows the redirect. This will show the actual workflowid:

-
curl -s -v 'http://localhost:6480/pecan/04-runpecan.php?hostname=pecan.vm&siteid=772&start=2004-01-01&end=2004-12-31&modelid=5000000002&pft\[\]=temperate.coniferous&input_poolinitcond=-1&input_met=99000000006' 2>&1 | grep 'Location:'
-< Location: 05-running.php?workflowid=99000000004
-

In this case you can use the browser to see progress, or use the following to see the status:

-
curl -s 'http://localhost:6480/pecan/dataset.php?workflowid=99000000004&type=file&name=STATUS'
-TRAIT   2017-12-13 08:56:56 2017-12-13 08:56:57 DONE
-META    2017-12-13 08:56:57 2017-12-13 08:57:13 DONE
-CONFIG  2017-12-13 08:57:13 2017-12-13 08:57:14 DONE
-MODEL   2017-12-13 08:57:14 2017-12-13 08:57:15 DONE
-OUTPUT  2017-12-13 08:57:15 2017-12-13 08:57:15 DONE
-ENSEMBLE    2017-12-13 08:57:15 2017-12-13 08:57:16 DONE
-FINISHED    2017-12-13 08:57:16 2017-12-13 08:57:16 DONE
-

Or to show the output log:

-
curl -s 'http://localhost:6480/pecan/dataset.php?workflowid=99000000004&type=file&name=workflow.Rout'
-
-R version 3.4.3 (2017-11-30) -- "Kite-Eating Tree"
-Copyright (C) 2017 The R Foundation for Statistical Computing
-Platform: x86_64-pc-linux-gnu (64-bit)
-
-R is free software and comes with ABSOLUTELY NO WARRANTY.
-You are welcome to redistribute it under certain conditions.
-Type 'license()' or 'licence()' for distribution details.
-
-R is a collaborative project with many contributors.
-....
- -
-
- -
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/after-creating-a-new-pft-the-tag-for-pft-not-passed-to-config.xml-in-ed.html b/master/after-creating-a-new-pft-the-tag-for-pft-not-passed-to-config.xml-in-ed.html deleted file mode 100644 index 34e1cfc60..000000000 --- a/master/after-creating-a-new-pft-the-tag-for-pft-not-passed-to-config.xml-in-ed.html +++ /dev/null @@ -1,868 +0,0 @@ - - - - - - - 21.3 After creating a new PFT the tag for PFT not passed to config.xml in ED | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

21.3 After creating a new PFT the tag for PFT not passed to config.xml in ED

-

This is a result of the rather clunky way we currently have adding PFTs to PEcAn. This is happening because you need to edit the ./pecan/models/ed/data/pftmapping.csv file to include your new PFTs.

-

This is what the file looks like:

-
PEcAn;ED
-ebifarm.acru;11
-ebifarm.acsa3;11
-...
-

You just need to edit this file (in a text editor, no Excel) and add your PFT names and associated number to the end of the file. Once you do this, recompile PEcAn and it should then work for you. We currently need to reference this file in order to properly set the PFT number and maintain internal consistency between PEcAn and ED2.

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/ameriflux.html b/master/ameriflux.html deleted file mode 100644 index 4e70e7663..000000000 --- a/master/ameriflux.html +++ /dev/null @@ -1,865 +0,0 @@ - - - - - - - 15.1 Ameriflux | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

15.1 Ameriflux

-

Scale: site

-

Resolution: 30 or 60 min

-

Availability: varies by site http:\/\/ameriflux.lbl.gov\/data\/data-availability\/

-

Notes: Old ORNL server, use is deprecated

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/amerifluxlbl.html b/master/amerifluxlbl.html deleted file mode 100644 index 42fe7640a..000000000 --- a/master/amerifluxlbl.html +++ /dev/null @@ -1,865 +0,0 @@ - - - - - - - 15.2 AmerifluxLBL | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

15.2 AmerifluxLBL

-

Scale: site

-

Resolution: 30 or 60 min

-

Availability: varies by site http:\/\/ameriflux.lbl.gov\/data\/data-availability\/

-

Notes: new Lawrence Berkeley Lab server

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/appendix-testthat.html b/master/appendix-testthat.html deleted file mode 100644 index f5b03deed..000000000 --- a/master/appendix-testthat.html +++ /dev/null @@ -1,865 +0,0 @@ - - - - - - - 32 Testing with the testthat package | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

32 Testing with the testthat package

-

Tests are found in <package>/tests/testthat/ (for example, base/utils/inst/tests/)

-

See attached file and -http://r-pkgs.had.co.nz/tests.html -for details on how to use the testthat package.

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/assets/anchor-sections-1.1.0/anchor-sections-hash.css b/master/assets/anchor-sections-1.1.0/anchor-sections-hash.css deleted file mode 100644 index b563ec97e..000000000 --- a/master/assets/anchor-sections-1.1.0/anchor-sections-hash.css +++ /dev/null @@ -1,2 +0,0 @@ -/* Styles for section anchors */ -a.anchor-section::before {content: '#';font-size: 80%;} diff --git a/master/assets/anchor-sections-1.1.0/anchor-sections.css b/master/assets/anchor-sections-1.1.0/anchor-sections.css deleted file mode 100644 index 041905f8b..000000000 --- a/master/assets/anchor-sections-1.1.0/anchor-sections.css +++ /dev/null @@ -1,4 +0,0 @@ -/* Styles for section anchors */ -a.anchor-section {margin-left: 10px; visibility: hidden; color: inherit;} -.hasAnchor:hover a.anchor-section {visibility: visible;} -ul > li > .anchor-section {display: none;} diff --git a/master/assets/anchor-sections-1.1.0/anchor-sections.js b/master/assets/anchor-sections-1.1.0/anchor-sections.js deleted file mode 100644 index fee005d95..000000000 --- a/master/assets/anchor-sections-1.1.0/anchor-sections.js +++ /dev/null @@ -1,11 +0,0 @@ -document.addEventListener('DOMContentLoaded', function () { - // If section divs is used, we need to put the anchor in the child header - const headers = document.querySelectorAll("div.hasAnchor.section[class*='level'] > :first-child") - - headers.forEach(function (x) { - // Add to the header node - if (!x.classList.contains('hasAnchor')) x.classList.add('hasAnchor') - // Remove from the section or div created by Pandoc - x.parentElement.classList.remove('hasAnchor') - }) -}) diff --git a/master/assets/crosstalk-1.2.0/css/crosstalk.min.css b/master/assets/crosstalk-1.2.0/css/crosstalk.min.css deleted file mode 100644 index 6b4538284..000000000 --- a/master/assets/crosstalk-1.2.0/css/crosstalk.min.css +++ /dev/null @@ -1 +0,0 @@ -.container-fluid.crosstalk-bscols{margin-left:-30px;margin-right:-30px;white-space:normal}body>.container-fluid.crosstalk-bscols{margin-left:auto;margin-right:auto}.crosstalk-input-checkboxgroup .crosstalk-options-group .crosstalk-options-column{display:inline-block;padding-right:12px;vertical-align:top}@media only screen and (max-width: 480px){.crosstalk-input-checkboxgroup .crosstalk-options-group .crosstalk-options-column{display:block;padding-right:inherit}}.crosstalk-input{margin-bottom:15px}.crosstalk-input .control-label{margin-bottom:0;vertical-align:middle}.crosstalk-input input[type="checkbox"]{margin:4px 0 0;margin-top:1px;line-height:normal}.crosstalk-input .checkbox{position:relative;display:block;margin-top:10px;margin-bottom:10px}.crosstalk-input .checkbox>label{padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.crosstalk-input .checkbox input[type="checkbox"],.crosstalk-input .checkbox-inline input[type="checkbox"]{position:absolute;margin-top:2px;margin-left:-20px}.crosstalk-input .checkbox+.checkbox{margin-top:-5px}.crosstalk-input .checkbox-inline{position:relative;display:inline-block;padding-left:20px;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer}.crosstalk-input .checkbox-inline+.checkbox-inline{margin-top:0;margin-left:10px} diff --git a/master/assets/crosstalk-1.2.0/js/crosstalk.min.js b/master/assets/crosstalk-1.2.0/js/crosstalk.min.js deleted file mode 100644 index b7ec0ac9f..000000000 --- a/master/assets/crosstalk-1.2.0/js/crosstalk.min.js +++ /dev/null @@ -1,2 +0,0 @@ -!function o(u,a,l){function s(n,e){if(!a[n]){if(!u[n]){var t="function"==typeof require&&require;if(!e&&t)return t(n,!0);if(f)return f(n,!0);var r=new Error("Cannot find module '"+n+"'");throw r.code="MODULE_NOT_FOUND",r}var i=a[n]={exports:{}};u[n][0].call(i.exports,function(e){var t=u[n][1][e];return s(t||e)},i,i.exports,o,u,a,l)}return a[n].exports}for(var f="function"==typeof require&&require,e=0;e?@[\\\]^`{|}~])/g,"\\$1")+"']"),r=JSON.parse(n[0].innerText),i=e.factory(t,r);o(t).data("crosstalk-instance",i),o(t).addClass("crosstalk-input-bound")}if(t.Shiny){var e=new t.Shiny.InputBinding,u=t.jQuery;u.extend(e,{find:function(e){return u(e).find(".crosstalk-input")},initialize:function(e){var t,n;u(e).hasClass("crosstalk-input-bound")||(n=o(t=e),Object.keys(r).forEach(function(e){n.hasClass(e)&&!n.hasClass("crosstalk-input-bound")&&i(r[e],t)}))},getId:function(e){return e.id},getValue:function(e){},setValue:function(e,t){},receiveMessage:function(e,t){},subscribe:function(e,t){u(e).data("crosstalk-instance").resume()},unsubscribe:function(e){u(e).data("crosstalk-instance").suspend()}}),t.Shiny.inputBindings.register(e,"crosstalk.inputBinding")}}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}],7:[function(r,e,t){(function(e){"use strict";var t=function(e){{if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n]);return t.default=e,t}}(r("./input")),n=r("./filter");var a=e.jQuery;t.register({className:"crosstalk-input-checkboxgroup",factory:function(e,r){var i=new n.FilterHandle(r.group),o=void 0,u=a(e);return u.on("change","input[type='checkbox']",function(){var e=u.find("input[type='checkbox']:checked");if(0===e.length)o=null,i.clear();else{var t={};e.each(function(){r.map[this.value].forEach(function(e){t[e]=!0})});var n=Object.keys(t);n.sort(),o=n,i.set(n)}}),{suspend:function(){i.clear()},resume:function(){o&&i.set(o)}}}})}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{"./filter":2,"./input":6}],8:[function(r,e,t){(function(e){"use strict";var t=n(r("./input")),l=n(r("./util")),s=r("./filter");function n(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n]);return t.default=e,t}var f=e.jQuery;t.register({className:"crosstalk-input-select",factory:function(e,n){var t=l.dataframeToD3(n.items),r={options:[{value:"",label:"(All)"}].concat(t),valueField:"value",labelField:"label",searchField:"label"},i=f(e).find("select")[0],o=f(i).selectize(r)[0].selectize,u=new s.FilterHandle(n.group),a=void 0;return o.on("change",function(){if(0===o.items.length)a=null,u.clear();else{var t={};o.items.forEach(function(e){n.map[e].forEach(function(e){t[e]=!0})});var e=Object.keys(t);e.sort(),a=e,u.set(e)}}),{suspend:function(){u.clear()},resume:function(){a&&u.set(a)}}}})}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{"./filter":2,"./input":6,"./util":11}],9:[function(n,e,t){(function(e){"use strict";var d=function(e,t){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return function(e,t){var n=[],r=!0,i=!1,o=void 0;try{for(var u,a=e[Symbol.iterator]();!(r=(u=a.next()).done)&&(n.push(u.value),!t||n.length!==t);r=!0);}catch(e){i=!0,o=e}finally{try{!r&&a.return&&a.return()}finally{if(i)throw o}}return n}(e,t);throw new TypeError("Invalid attempt to destructure non-iterable instance")},t=function(e){{if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n]);return t.default=e,t}}(n("./input")),a=n("./filter");var v=e.jQuery,p=e.strftime;function y(e,t){for(var n=e.toString();n.length 123,456,666.7890 -var markInterval = function(d, digits, interval, mark, decMark, precision) { - x = precision ? d.toPrecision(digits) : d.toFixed(digits); - if (!/^-?[\d.]+$/.test(x)) return x; - var xv = x.split('.'); - if (xv.length > 2) return x; // should have at most one decimal point - xv[0] = xv[0].replace(new RegExp('\\B(?=(\\d{' + interval + '})+(?!\\d))', 'g'), mark); - return xv.join(decMark); -}; - -DTWidget.formatCurrency = function(data, currency, digits, interval, mark, decMark, before, zeroPrint) { - var d = parseFloat(data); - if (isNaN(d)) return ''; - if (zeroPrint !== null && d === 0.0) return zeroPrint; - var res = markInterval(d, digits, interval, mark, decMark); - res = before ? (/^-/.test(res) ? '-' + currency + res.replace(/^-/, '') : currency + res) : - res + currency; - return res; -}; - -DTWidget.formatString = function(data, prefix, suffix) { - var d = data; - if (d === null) return ''; - return prefix + d + suffix; -}; - -DTWidget.formatPercentage = function(data, digits, interval, mark, decMark, zeroPrint) { - var d = parseFloat(data); - if (isNaN(d)) return ''; - if (zeroPrint !== null && d === 0.0) return zeroPrint; - return markInterval(d * 100, digits, interval, mark, decMark) + '%'; -}; - -DTWidget.formatRound = function(data, digits, interval, mark, decMark, zeroPrint) { - var d = parseFloat(data); - if (isNaN(d)) return ''; - if (zeroPrint !== null && d === 0.0) return zeroPrint; - return markInterval(d, digits, interval, mark, decMark); -}; - -DTWidget.formatSignif = function(data, digits, interval, mark, decMark, zeroPrint) { - var d = parseFloat(data); - if (isNaN(d)) return ''; - if (zeroPrint !== null && d === 0.0) return zeroPrint; - return markInterval(d, digits, interval, mark, decMark, true); -}; - -DTWidget.formatDate = function(data, method, params) { - var d = data; - if (d === null) return ''; - // (new Date('2015-10-28')).toDateString() may return 2015-10-27 because the - // actual time created could be like 'Tue Oct 27 2015 19:00:00 GMT-0500 (CDT)', - // i.e. the date-only string is treated as UTC time instead of local time - if ((method === 'toDateString' || method === 'toLocaleDateString') && /^\d{4,}\D\d{2}\D\d{2}$/.test(d)) { - d = d.split(/\D/); - d = new Date(d[0], d[1] - 1, d[2]); - } else { - d = new Date(d); - } - return d[method].apply(d, params); -}; - -window.DTWidget = DTWidget; - -// A helper function to update the properties of existing filters -var setFilterProps = function(td, props) { - // Update enabled/disabled state - var $input = $(td).find('input').first(); - var searchable = $input.data('searchable'); - $input.prop('disabled', !searchable || props.disabled); - - // Based on the filter type, set its new values - var type = td.getAttribute('data-type'); - if (['factor', 'logical'].includes(type)) { - // Reformat the new dropdown options for use with selectize - var new_vals = props.params.options.map(function(item) { - return { text: item, value: item }; - }); - - // Find the selectize object - var dropdown = $(td).find('.selectized').eq(0)[0].selectize; - - // Note the current values - var old_vals = dropdown.getValue(); - - // Remove the existing values - dropdown.clearOptions(); - - // Add the new options - dropdown.addOption(new_vals); - - // Preserve the existing values - dropdown.setValue(old_vals); - - } else if (['number', 'integer', 'date', 'time'].includes(type)) { - // Apply internal scaling to new limits. Updating scale not yet implemented. - var slider = $(td).find('.noUi-target').eq(0); - var scale = Math.pow(10, Math.max(0, +slider.data('scale') || 0)); - var new_vals = [props.params.min * scale, props.params.max * scale]; - - // Note what the new limits will be just for this filter - var new_lims = new_vals.slice(); - - // Determine the current values and limits - var old_vals = slider.val().map(Number); - var old_lims = slider.noUiSlider('options').range; - old_lims = [old_lims.min, old_lims.max]; - - // Preserve the current values if filters have been applied; otherwise, apply no filtering - if (old_vals[0] != old_lims[0]) { - new_vals[0] = Math.max(old_vals[0], new_vals[0]); - } - - if (old_vals[1] != old_lims[1]) { - new_vals[1] = Math.min(old_vals[1], new_vals[1]); - } - - // Update the endpoints of the slider - slider.noUiSlider({ - start: new_vals, - range: {'min': new_lims[0], 'max': new_lims[1]} - }, true); - } -}; - -var transposeArray2D = function(a) { - return a.length === 0 ? a : HTMLWidgets.transposeArray2D(a); -}; - -var crosstalkPluginsInstalled = false; - -function maybeInstallCrosstalkPlugins() { - if (crosstalkPluginsInstalled) - return; - crosstalkPluginsInstalled = true; - - $.fn.dataTable.ext.afnFiltering.push( - function(oSettings, aData, iDataIndex) { - var ctfilter = oSettings.nTable.ctfilter; - if (ctfilter && !ctfilter[iDataIndex]) - return false; - - var ctselect = oSettings.nTable.ctselect; - if (ctselect && !ctselect[iDataIndex]) - return false; - - return true; - } - ); -} - -HTMLWidgets.widget({ - name: "datatables", - type: "output", - renderOnNullValue: true, - initialize: function(el, width, height) { - $(el).html(' '); - return { - data: null, - ctfilterHandle: new crosstalk.FilterHandle(), - ctfilterSubscription: null, - ctselectHandle: new crosstalk.SelectionHandle(), - ctselectSubscription: null - }; - }, - renderValue: function(el, data, instance) { - if (el.offsetWidth === 0 || el.offsetHeight === 0) { - instance.data = data; - return; - } - instance.data = null; - var $el = $(el); - $el.empty(); - - if (data === null) { - $el.append(' '); - // clear previous Shiny inputs (if any) - for (var i in instance.clearInputs) instance.clearInputs[i](); - instance.clearInputs = {}; - return; - } - - var crosstalkOptions = data.crosstalkOptions; - if (!crosstalkOptions) crosstalkOptions = { - 'key': null, 'group': null - }; - if (crosstalkOptions.group) { - maybeInstallCrosstalkPlugins(); - instance.ctfilterHandle.setGroup(crosstalkOptions.group); - instance.ctselectHandle.setGroup(crosstalkOptions.group); - } - - // if we are in the viewer then we always want to fillContainer and - // and autoHideNavigation (unless the user has explicitly set these) - if (window.HTMLWidgets.viewerMode) { - if (!data.hasOwnProperty("fillContainer")) - data.fillContainer = true; - if (!data.hasOwnProperty("autoHideNavigation")) - data.autoHideNavigation = true; - } - - // propagate fillContainer to instance (so we have it in resize) - instance.fillContainer = data.fillContainer; - - var cells = data.data; - - if (cells instanceof Array) cells = transposeArray2D(cells); - - $el.append(data.container); - var $table = $el.find('table'); - if (data.class) $table.addClass(data.class); - if (data.caption) $table.prepend(data.caption); - - if (!data.selection) data.selection = { - mode: 'none', selected: null, target: 'row', selectable: null - }; - if (HTMLWidgets.shinyMode && data.selection.mode !== 'none' && - data.selection.target === 'row+column') { - if ($table.children('tfoot').length === 0) { - $table.append($('')); - $table.find('thead tr').clone().appendTo($table.find('tfoot')); - } - } - - // column filters - var filterRow; - switch (data.filter) { - case 'top': - $table.children('thead').append(data.filterHTML); - filterRow = $table.find('thead tr:last td'); - break; - case 'bottom': - if ($table.children('tfoot').length === 0) { - $table.append($('')); - } - $table.children('tfoot').prepend(data.filterHTML); - filterRow = $table.find('tfoot tr:first td'); - break; - } - - var options = { searchDelay: 1000 }; - if (cells !== null) $.extend(options, { - data: cells - }); - - // options for fillContainer - var bootstrapActive = typeof($.fn.popover) != 'undefined'; - if (instance.fillContainer) { - - // force scrollX/scrollY and turn off autoWidth - options.scrollX = true; - options.scrollY = "100px"; // can be any value, we'll adjust below - - // if we aren't paginating then move around the info/filter controls - // to save space at the bottom and rephrase the info callback - if (data.options.paging === false) { - - // we know how to do this cleanly for bootstrap, not so much - // for other themes/layouts - if (bootstrapActive) { - options.dom = "<'row'<'col-sm-4'i><'col-sm-8'f>>" + - "<'row'<'col-sm-12'tr>>"; - } - - options.fnInfoCallback = function(oSettings, iStart, iEnd, - iMax, iTotal, sPre) { - return Number(iTotal).toLocaleString() + " records"; - }; - } - } - - // auto hide navigation if requested - // Note, this only works on client-side processing mode as on server-side, - // cells (data.data) is null; In addition, we require the pageLength option - // being provided explicitly to enable this. Despite we may be able to deduce - // the default value of pageLength, it may complicate things so we'd rather - // put this responsiblity to users and warn them on the R side. - if (data.autoHideNavigation === true && data.options.paging !== false) { - // strip all nav if length >= cells - if ((cells instanceof Array) && data.options.pageLength >= cells.length) - options.dom = bootstrapActive ? "<'row'<'col-sm-12'tr>>" : "t"; - // alternatively lean things out for flexdashboard mobile portrait - else if (bootstrapActive && window.FlexDashboard && window.FlexDashboard.isMobilePhone()) - options.dom = "<'row'<'col-sm-12'f>>" + - "<'row'<'col-sm-12'tr>>" + - "<'row'<'col-sm-12'p>>"; - } - - $.extend(true, options, data.options || {}); - - var searchCols = options.searchCols; - if (searchCols) { - searchCols = searchCols.map(function(x) { - return x === null ? '' : x.search; - }); - // FIXME: this means I don't respect the escapeRegex setting - delete options.searchCols; - } - - // server-side processing? - var server = options.serverSide === true; - - // use the dataSrc function to pre-process JSON data returned from R - var DT_rows_all = [], DT_rows_current = []; - if (server && HTMLWidgets.shinyMode && typeof options.ajax === 'object' && - /^session\/[\da-z]+\/dataobj/.test(options.ajax.url) && !options.ajax.dataSrc) { - options.ajax.dataSrc = function(json) { - DT_rows_all = $.makeArray(json.DT_rows_all); - DT_rows_current = $.makeArray(json.DT_rows_current); - var data = json.data; - if (!colReorderEnabled()) return data; - var table = $table.DataTable(), order = table.colReorder.order(), flag = true, i, j, row; - for (i = 0; i < order.length; ++i) if (order[i] !== i) flag = false; - if (flag) return data; - for (i = 0; i < data.length; ++i) { - row = data[i].slice(); - for (j = 0; j < order.length; ++j) data[i][j] = row[order[j]]; - } - return data; - }; - } - - var thiz = this; - if (instance.fillContainer) $table.on('init.dt', function(e) { - thiz.fillAvailableHeight(el, $(el).innerHeight()); - }); - // If the page contains serveral datatables and one of which enables colReorder, - // the table.colReorder.order() function will exist but throws error when called. - // So it seems like the only way to know if colReorder is enabled or not is to - // check the options. - var colReorderEnabled = function() { return "colReorder" in options; }; - var table = $table.DataTable(options); - $el.data('datatable', table); - - // Unregister previous Crosstalk event subscriptions, if they exist - if (instance.ctfilterSubscription) { - instance.ctfilterHandle.off("change", instance.ctfilterSubscription); - instance.ctfilterSubscription = null; - } - if (instance.ctselectSubscription) { - instance.ctselectHandle.off("change", instance.ctselectSubscription); - instance.ctselectSubscription = null; - } - - if (!crosstalkOptions.group) { - $table[0].ctfilter = null; - $table[0].ctselect = null; - } else { - var key = crosstalkOptions.key; - function keysToMatches(keys) { - if (!keys) { - return null; - } else { - var selectedKeys = {}; - for (var i = 0; i < keys.length; i++) { - selectedKeys[keys[i]] = true; - } - var matches = {}; - for (var j = 0; j < key.length; j++) { - if (selectedKeys[key[j]]) - matches[j] = true; - } - return matches; - } - } - - function applyCrosstalkFilter(e) { - $table[0].ctfilter = keysToMatches(e.value); - table.draw(); - } - instance.ctfilterSubscription = instance.ctfilterHandle.on("change", applyCrosstalkFilter); - applyCrosstalkFilter({value: instance.ctfilterHandle.filteredKeys}); - - function applyCrosstalkSelection(e) { - if (e.sender !== instance.ctselectHandle) { - table - .rows('.' + selClass, {search: 'applied'}) - .nodes() - .to$() - .removeClass(selClass); - if (selectedRows) - changeInput('rows_selected', selectedRows(), void 0, true); - } - - if (e.sender !== instance.ctselectHandle && e.value && e.value.length) { - var matches = keysToMatches(e.value); - - // persistent selection with plotly (& leaflet) - var ctOpts = crosstalk.var("plotlyCrosstalkOpts").get() || {}; - if (ctOpts.persistent === true) { - var matches = $.extend(matches, $table[0].ctselect); - } - - $table[0].ctselect = matches; - table.draw(); - } else { - if ($table[0].ctselect) { - $table[0].ctselect = null; - table.draw(); - } - } - } - instance.ctselectSubscription = instance.ctselectHandle.on("change", applyCrosstalkSelection); - // TODO: This next line doesn't seem to work when renderDataTable is used - applyCrosstalkSelection({value: instance.ctselectHandle.value}); - } - - var inArray = function(val, array) { - return $.inArray(val, $.makeArray(array)) > -1; - }; - - // search the i-th column - var searchColumn = function(i, value) { - var regex = false, ci = true; - if (options.search) { - regex = options.search.regex, - ci = options.search.caseInsensitive !== false; - } - return table.column(i).search(value, regex, !regex, ci); - }; - - if (data.filter !== 'none') { - - filterRow.each(function(i, td) { - - var $td = $(td), type = $td.data('type'), filter; - var $input = $td.children('div').first().children('input'); - var disabled = $input.prop('disabled'); - var searchable = table.settings()[0].aoColumns[i].bSearchable; - $input.prop('disabled', !searchable || disabled); - $input.data('searchable', searchable); // for updating later - $input.on('input blur', function() { - $input.next('span').toggle(Boolean($input.val())); - }); - // Bootstrap sets pointer-events to none and we won't be able to click - // the clear button - $input.next('span').css('pointer-events', 'auto').hide().click(function() { - $(this).hide().prev('input').val('').trigger('input').focus(); - }); - var searchCol; // search string for this column - if (searchCols && searchCols[i]) { - searchCol = searchCols[i]; - $input.val(searchCol).trigger('input'); - } - var $x = $td.children('div').last(); - - // remove the overflow: hidden attribute of the scrollHead - // (otherwise the scrolling table body obscures the filters) - // The workaround and the discussion from - // https://github.com/rstudio/DT/issues/554#issuecomment-518007347 - // Otherwise the filter selection will not be anchored to the values - // when the columns number is many and scrollX is enabled. - var scrollHead = $(el).find('.dataTables_scrollHead,.dataTables_scrollFoot'); - var cssOverflowHead = scrollHead.css('overflow'); - var scrollBody = $(el).find('.dataTables_scrollBody'); - var cssOverflowBody = scrollBody.css('overflow'); - var scrollTable = $(el).find('.dataTables_scroll'); - var cssOverflowTable = scrollTable.css('overflow'); - if (cssOverflowHead === 'hidden') { - $x.on('show hide', function(e) { - if (e.type === 'show') { - scrollHead.css('overflow', 'visible'); - scrollBody.css('overflow', 'visible'); - scrollTable.css('overflow-x', 'scroll'); - } else { - scrollHead.css('overflow', cssOverflowHead); - scrollBody.css('overflow', cssOverflowBody); - scrollTable.css('overflow-x', cssOverflowTable); - } - }); - $x.css('z-index', 25); - } - - if (inArray(type, ['factor', 'logical'])) { - $input.on({ - click: function() { - $input.parent().hide(); $x.show().trigger('show'); filter[0].selectize.focus(); - }, - input: function() { - if ($input.val() === '') filter[0].selectize.setValue([]); - } - }); - var $input2 = $x.children('select'); - filter = $input2.selectize({ - options: $input2.data('options').map(function(v, i) { - return ({text: v, value: v}); - }), - plugins: ['remove_button'], - hideSelected: true, - onChange: function(value) { - if (value === null) value = []; // compatibility with jQuery 3.0 - $input.val(value.length ? JSON.stringify(value) : ''); - if (value.length) $input.trigger('input'); - $input.attr('title', $input.val()); - if (server) { - table.column(i).search(value.length ? JSON.stringify(value) : '').draw(); - return; - } - // turn off filter if nothing selected - $td.data('filter', value.length > 0); - table.draw(); // redraw table, and filters will be applied - } - }); - if (searchCol) filter[0].selectize.setValue(JSON.parse(searchCol)); - filter[0].selectize.on('blur', function() { - $x.hide().trigger('hide'); $input.parent().show(); $input.trigger('blur'); - }); - filter.next('div').css('margin-bottom', 'auto'); - } else if (type === 'character') { - var fun = function() { - searchColumn(i, $input.val()).draw(); - }; - if (server) { - fun = $.fn.dataTable.util.throttle(fun, options.searchDelay); - } - $input.on('input', fun); - } else if (inArray(type, ['number', 'integer', 'date', 'time'])) { - var $x0 = $x; - $x = $x0.children('div').first(); - $x0.css({ - 'background-color': '#fff', - 'border': '1px #ddd solid', - 'border-radius': '4px', - 'padding': data.vertical ? '35px 20px': '20px 20px 10px 20px' - }); - var $spans = $x0.children('span').css({ - 'margin-top': data.vertical ? '0' : '10px', - 'white-space': 'nowrap' - }); - var $span1 = $spans.first(), $span2 = $spans.last(); - var r1 = +$x.data('min'), r2 = +$x.data('max'); - // when the numbers are too small or have many decimal places, the - // slider may have numeric precision problems (#150) - var scale = Math.pow(10, Math.max(0, +$x.data('scale') || 0)); - r1 = Math.round(r1 * scale); r2 = Math.round(r2 * scale); - var scaleBack = function(x, scale) { - if (scale === 1) return x; - var d = Math.round(Math.log(scale) / Math.log(10)); - // to avoid problems like 3.423/100 -> 0.034230000000000003 - return (x / scale).toFixed(d); - }; - var slider_min = function() { - return filter.noUiSlider('options').range.min; - }; - var slider_max = function() { - return filter.noUiSlider('options').range.max; - }; - $input.on({ - focus: function() { - $x0.show().trigger('show'); - // first, make sure the slider div leaves at least 20px between - // the two (slider value) span's - $x0.width(Math.max(160, $span1.outerWidth() + $span2.outerWidth() + 20)); - // then, if the input is really wide or slider is vertical, - // make the slider the same width as the input - if ($x0.outerWidth() < $input.outerWidth() || data.vertical) { - $x0.outerWidth($input.outerWidth()); - } - // make sure the slider div does not reach beyond the right margin - if ($(window).width() < $x0.offset().left + $x0.width()) { - $x0.offset({ - 'left': $input.offset().left + $input.outerWidth() - $x0.outerWidth() - }); - } - }, - blur: function() { - $x0.hide().trigger('hide'); - }, - input: function() { - if ($input.val() === '') filter.val([slider_min(), slider_max()]); - }, - change: function() { - var v = $input.val().replace(/\s/g, ''); - if (v === '') return; - v = v.split('...'); - if (v.length !== 2) { - $input.parent().addClass('has-error'); - return; - } - if (v[0] === '') v[0] = slider_min(); - if (v[1] === '') v[1] = slider_max(); - $input.parent().removeClass('has-error'); - // treat date as UTC time at midnight - var strTime = function(x) { - var s = type === 'date' ? 'T00:00:00Z' : ''; - var t = new Date(x + s).getTime(); - // add 10 minutes to date since it does not hurt the date, and - // it helps avoid the tricky floating point arithmetic problems, - // e.g. sometimes the date may be a few milliseconds earlier - // than the midnight due to precision problems in noUiSlider - return type === 'date' ? t + 3600000 : t; - }; - if (inArray(type, ['date', 'time'])) { - v[0] = strTime(v[0]); - v[1] = strTime(v[1]); - } - if (v[0] != slider_min()) v[0] *= scale; - if (v[1] != slider_max()) v[1] *= scale; - filter.val(v); - } - }); - var formatDate = function(d, isoFmt) { - d = scaleBack(d, scale); - if (type === 'number') return d; - if (type === 'integer') return parseInt(d); - var x = new Date(+d); - var fmt = ('filterDateFmt' in data) ? data.filterDateFmt[i] : undefined; - if (fmt !== undefined && isoFmt === false) return x[fmt.method].apply(x, fmt.params); - if (type === 'date') { - var pad0 = function(x) { - return ('0' + x).substr(-2, 2); - }; - return x.getUTCFullYear() + '-' + pad0(1 + x.getUTCMonth()) - + '-' + pad0(x.getUTCDate()); - } else { - return x.toISOString(); - } - }; - var opts = type === 'date' ? { step: 60 * 60 * 1000 } : - type === 'integer' ? { step: 1 } : {}; - - opts.orientation = data.vertical ? 'vertical': 'horizontal'; - opts.direction = data.vertical ? 'rtl': 'ltr'; - - filter = $x.noUiSlider($.extend({ - start: [r1, r2], - range: {min: r1, max: r2}, - connect: true - }, opts)); - if (scale > 1) (function() { - var t1 = r1, t2 = r2; - var val = filter.val(); - while (val[0] > r1 || val[1] < r2) { - if (val[0] > r1) { - t1 -= val[0] - r1; - } - if (val[1] < r2) { - t2 += r2 - val[1]; - } - filter = $x.noUiSlider($.extend({ - start: [t1, t2], - range: {min: t1, max: t2}, - connect: true - }, opts), true); - val = filter.val(); - } - r1 = t1; r2 = t2; - })(); - var updateSliderText = function(v1, v2) { - $span1.text(formatDate(v1, false)); $span2.text(formatDate(v2, false)); - }; - updateSliderText(r1, r2); - var updateSlider = function(e) { - var val = filter.val(); - // turn off filter if in full range - $td.data('filter', val[0] > slider_min() || val[1] < slider_max()); - var v1 = formatDate(val[0]), v2 = formatDate(val[1]), ival; - if ($td.data('filter')) { - ival = v1 + ' ... ' + v2; - $input.attr('title', ival).val(ival).trigger('input'); - } else { - $input.attr('title', '').val(''); - } - updateSliderText(val[0], val[1]); - if (e.type === 'slide') return; // no searching when sliding only - if (server) { - table.column(i).search($td.data('filter') ? ival : '').draw(); - return; - } - table.draw(); - }; - filter.on({ - set: updateSlider, - slide: updateSlider - }); - } - - // server-side processing will be handled by R (or whatever server - // language you use); the following code is only needed for client-side - // processing - if (server) { - // if a search string has been pre-set, search now - if (searchCol) searchColumn(i, searchCol).draw(); - return; - } - - var customFilter = function(settings, data, dataIndex) { - // there is no way to attach a search function to a specific table, - // and we need to make sure a global search function is not applied to - // all tables (i.e. a range filter in a previous table should not be - // applied to the current table); we use the settings object to - // determine if we want to perform searching on the current table, - // since settings.sTableId will be different to different tables - if (table.settings()[0] !== settings) return true; - // no filter on this column or no need to filter this column - if (typeof filter === 'undefined' || !$td.data('filter')) return true; - - var r = filter.val(), v, r0, r1; - var i_data = function(i) { - if (!colReorderEnabled()) return i; - var order = table.colReorder.order(), k; - for (k = 0; k < order.length; ++k) if (order[k] === i) return k; - return i; // in theory it will never be here... - } - v = data[i_data(i)]; - if (type === 'number' || type === 'integer') { - v = parseFloat(v); - // how to handle NaN? currently exclude these rows - if (isNaN(v)) return(false); - r0 = parseFloat(scaleBack(r[0], scale)) - r1 = parseFloat(scaleBack(r[1], scale)); - if (v >= r0 && v <= r1) return true; - } else if (type === 'date' || type === 'time') { - v = new Date(v); - r0 = new Date(r[0] / scale); r1 = new Date(r[1] / scale); - if (v >= r0 && v <= r1) return true; - } else if (type === 'factor') { - if (r.length === 0 || inArray(v, r)) return true; - } else if (type === 'logical') { - if (r.length === 0) return true; - if (inArray(v === '' ? 'na' : v, r)) return true; - } - return false; - }; - - $.fn.dataTable.ext.search.push(customFilter); - - // search for the preset search strings if it is non-empty - if (searchCol) { - if (inArray(type, ['factor', 'logical'])) { - filter[0].selectize.setValue(JSON.parse(searchCol)); - } else if (type === 'character') { - $input.trigger('input'); - } else if (inArray(type, ['number', 'integer', 'date', 'time'])) { - $input.trigger('change'); - } - } - - }); - - } - - // highlight search keywords - var highlight = function() { - var body = $(table.table().body()); - // removing the old highlighting first - body.unhighlight(); - - // don't highlight the "not found" row, so we get the rows using the api - if (table.rows({ filter: 'applied' }).data().length === 0) return; - // highlight global search keywords - body.highlight($.trim(table.search()).split(/\s+/)); - // then highlight keywords from individual column filters - if (filterRow) filterRow.each(function(i, td) { - var $td = $(td), type = $td.data('type'); - if (type !== 'character') return; - var $input = $td.children('div').first().children('input'); - var column = table.column(i).nodes().to$(), - val = $.trim($input.val()); - if (type !== 'character' || val === '') return; - column.highlight(val.split(/\s+/)); - }); - }; - - if (options.searchHighlight) { - table - .on('draw.dt.dth column-visibility.dt.dth column-reorder.dt.dth', highlight) - .on('destroy', function() { - // remove event handler - table.off('draw.dt.dth column-visibility.dt.dth column-reorder.dt.dth'); - }); - - // Set the option for escaping regex characters in our search string. This will be used - // for all future matching. - jQuery.fn.highlight.options.escapeRegex = (!options.search || !options.search.regex); - - // initial highlight for state saved conditions and initial states - highlight(); - } - - // run the callback function on the table instance - if (typeof data.callback === 'function') data.callback(table); - - // double click to edit the cell, row, column, or all cells - if (data.editable) table.on('dblclick.dt', 'tbody td', function(e) { - // only bring up the editor when the cell itself is dbclicked, and ignore - // other dbclick events bubbled up (e.g. from the ) - if (e.target !== this) return; - var target = [], immediate = false; - switch (data.editable.target) { - case 'cell': - target = [this]; - immediate = true; // edit will take effect immediately - break; - case 'row': - target = table.cells(table.cell(this).index().row, '*').nodes(); - break; - case 'column': - target = table.cells('*', table.cell(this).index().column).nodes(); - break; - case 'all': - target = table.cells().nodes(); - break; - default: - throw 'The editable parameter must be "cell", "row", "column", or "all"'; - } - var disableCols = data.editable.disable ? data.editable.disable.columns : null; - var numericCols = data.editable.numeric; - var areaCols = data.editable.area; - for (var i = 0; i < target.length; i++) { - (function(cell, current) { - var $cell = $(cell), html = $cell.html(); - var _cell = table.cell(cell), value = _cell.data(), index = _cell.index().column; - var $input; - if (inArray(index, numericCols)) { - $input = $(''); - } else if (inArray(index, areaCols)) { - $input = $(''); - } else { - $input = $(''); - } - if (!immediate) { - $cell.data('input', $input).data('html', html); - $input.attr('title', 'Hit Ctrl+Enter to finish editing, or Esc to cancel'); - } - $input.val(value); - if (inArray(index, disableCols)) { - $input.attr('readonly', '').css('filter', 'invert(25%)'); - } - $cell.empty().append($input); - if (cell === current) $input.focus(); - $input.css('width', '100%'); - - if (immediate) $input.on('blur', function(e) { - var valueNew = $input.val(); - if (valueNew != value) { - _cell.data(valueNew); - if (HTMLWidgets.shinyMode) { - changeInput('cell_edit', [cellInfo(cell)], 'DT.cellInfo', null, {priority: 'event'}); - } - // for server-side processing, users have to call replaceData() to update the table - if (!server) table.draw(false); - } else { - $cell.html(html); - } - }).on('keyup', function(e) { - // hit Escape to cancel editing - if (e.keyCode === 27) $input.trigger('blur'); - }); - - // bulk edit (row, column, or all) - if (!immediate) $input.on('keyup', function(e) { - var removeInput = function($cell, restore) { - $cell.data('input').remove(); - if (restore) $cell.html($cell.data('html')); - } - if (e.keyCode === 27) { - for (var i = 0; i < target.length; i++) { - removeInput($(target[i]), true); - } - } else if (e.keyCode === 13 && e.ctrlKey) { - // Ctrl + Enter - var cell, $cell, _cell, cellData = []; - for (var i = 0; i < target.length; i++) { - cell = target[i]; $cell = $(cell); _cell = table.cell(cell); - _cell.data($cell.data('input').val()); - HTMLWidgets.shinyMode && cellData.push(cellInfo(cell)); - removeInput($cell, false); - } - if (HTMLWidgets.shinyMode) { - changeInput('cell_edit', cellData, 'DT.cellInfo', null, {priority: "event"}); - } - if (!server) table.draw(false); - } - }); - })(target[i], this); - } - }); - - // interaction with shiny - if (!HTMLWidgets.shinyMode && !crosstalkOptions.group) return; - - var methods = {}; - var shinyData = {}; - - methods.updateCaption = function(caption) { - if (!caption) return; - $table.children('caption').replaceWith(caption); - } - - // register clear functions to remove input values when the table is removed - instance.clearInputs = {}; - - var changeInput = function(id, value, type, noCrosstalk, opts) { - var event = id; - id = el.id + '_' + id; - if (type) id = id + ':' + type; - // do not update if the new value is the same as old value - if (event !== 'cell_edit' && !/_clicked$/.test(event) && shinyData.hasOwnProperty(id) && shinyData[id] === JSON.stringify(value)) - return; - shinyData[id] = JSON.stringify(value); - if (HTMLWidgets.shinyMode && Shiny.setInputValue) { - Shiny.setInputValue(id, value, opts); - if (!instance.clearInputs[id]) instance.clearInputs[id] = function() { - Shiny.setInputValue(id, null); - } - } - - // HACK - if (event === "rows_selected" && !noCrosstalk) { - if (crosstalkOptions.group) { - var keys = crosstalkOptions.key; - var selectedKeys = null; - if (value) { - selectedKeys = []; - for (var i = 0; i < value.length; i++) { - // The value array's contents use 1-based row numbers, so we must - // convert to 0-based before indexing into the keys array. - selectedKeys.push(keys[value[i] - 1]); - } - } - instance.ctselectHandle.set(selectedKeys); - } - } - }; - - var addOne = function(x) { - return x.map(function(i) { return 1 + i; }); - }; - - var unique = function(x) { - var ux = []; - $.each(x, function(i, el){ - if ($.inArray(el, ux) === -1) ux.push(el); - }); - return ux; - } - - // change the row index of a cell - var tweakCellIndex = function(cell) { - var info = cell.index(); - // some cell may not be valid. e.g, #759 - // when using the RowGroup extension, datatables will - // generate the row label and the cells are not part of - // the data thus contain no row/col info - if (info === undefined) - return {row: null, col: null}; - if (server) { - info.row = DT_rows_current[info.row]; - } else { - info.row += 1; - } - return {row: info.row, col: info.column}; - } - - var cleanSelectedValues = function() { - changeInput('rows_selected', []); - changeInput('columns_selected', []); - changeInput('cells_selected', transposeArray2D([]), 'shiny.matrix'); - } - // #828 we should clean the selection on the server-side when the table reloads - cleanSelectedValues(); - - // a flag to indicates if select extension is initialized or not - var flagSelectExt = table.settings()[0]._select !== undefined; - // the Select extension should only be used in the client mode and - // when the selection.mode is set to none - if (data.selection.mode === 'none' && !server && flagSelectExt) { - var updateRowsSelected = function() { - var rows = table.rows({selected: true}); - var selected = []; - $.each(rows.indexes().toArray(), function(i, v) { - selected.push(v + 1); - }); - changeInput('rows_selected', selected); - } - var updateColsSelected = function() { - var columns = table.columns({selected: true}); - changeInput('columns_selected', columns.indexes().toArray()); - } - var updateCellsSelected = function() { - var cells = table.cells({selected: true}); - var selected = []; - cells.every(function() { - var row = this.index().row; - var col = this.index().column; - selected = selected.concat([[row + 1, col]]); - }); - changeInput('cells_selected', transposeArray2D(selected), 'shiny.matrix'); - } - table.on('select deselect', function(e, dt, type, indexes) { - updateRowsSelected(); - updateColsSelected(); - updateCellsSelected(); - }) - } - - var selMode = data.selection.mode, selTarget = data.selection.target; - var selDisable = data.selection.selectable === false; - if (inArray(selMode, ['single', 'multiple'])) { - var selClass = inArray(data.style, ['bootstrap', 'bootstrap4']) ? 'active' : 'selected'; - // selected1: row indices; selected2: column indices - var initSel = function(x) { - if (x === null || typeof x === 'boolean' || selTarget === 'cell') { - return {rows: [], cols: []}; - } else if (selTarget === 'row') { - return {rows: $.makeArray(x), cols: []}; - } else if (selTarget === 'column') { - return {rows: [], cols: $.makeArray(x)}; - } else if (selTarget === 'row+column') { - return {rows: $.makeArray(x.rows), cols: $.makeArray(x.cols)}; - } - } - var selected = data.selection.selected; - var selected1 = initSel(selected).rows, selected2 = initSel(selected).cols; - // selectable should contain either all positive or all non-positive values, not both - // positive values indicate "selectable" while non-positive values means "nonselectable" - // the assertion is performed on R side. (only column indicides could be zero which indicates - // the row name) - var selectable = data.selection.selectable; - var selectable1 = initSel(selectable).rows, selectable2 = initSel(selectable).cols; - - // After users reorder the rows or filter the table, we cannot use the table index - // directly. Instead, we need this function to find out the rows between the two clicks. - // If user filter the table again between the start click and the end click, the behavior - // would be undefined, but it should not be a problem. - var shiftSelRowsIndex = function(start, end) { - var indexes = server ? DT_rows_all : table.rows({ search: 'applied' }).indexes().toArray(); - start = indexes.indexOf(start); end = indexes.indexOf(end); - // if start is larger than end, we need to swap - if (start > end) { - var tmp = end; end = start; start = tmp; - } - return indexes.slice(start, end + 1); - } - - var serverRowIndex = function(clientRowIndex) { - return server ? DT_rows_current[clientRowIndex] : clientRowIndex + 1; - } - - // row, column, or cell selection - var lastClickedRow; - if (inArray(selTarget, ['row', 'row+column'])) { - // Get the current selected rows. It will also - // update the selected1's value based on the current row selection state - // Note we can't put this function inside selectRows() directly, - // the reason is method.selectRows() will override selected1's value but this - // function will add rows to selected1 (keep the existing selection), which is - // inconsistent with column and cell selection. - var selectedRows = function() { - var rows = table.rows('.' + selClass); - var idx = rows.indexes().toArray(); - if (!server) { - selected1 = addOne(idx); - return selected1; - } - idx = idx.map(function(i) { - return DT_rows_current[i]; - }); - selected1 = selMode === 'multiple' ? unique(selected1.concat(idx)) : idx; - return selected1; - } - // Change selected1's value based on selectable1, then refresh the row state - var onlyKeepSelectableRows = function() { - if (selDisable) { // users can't select; useful when only want backend select - selected1 = []; - return; - } - if (selectable1.length === 0) return; - var nonselectable = selectable1[0] <= 0; - if (nonselectable) { - // should make selectable1 positive - selected1 = $(selected1).not(selectable1.map(function(i) { return -i; })).get(); - } else { - selected1 = $(selected1).filter(selectable1).get(); - } - } - // Change selected1's value based on selectable1, then - // refresh the row selection state according to values in selected1 - var selectRows = function(ignoreSelectable) { - if (!ignoreSelectable) onlyKeepSelectableRows(); - table.$('tr.' + selClass).removeClass(selClass); - if (selected1.length === 0) return; - if (server) { - table.rows({page: 'current'}).every(function() { - if (inArray(DT_rows_current[this.index()], selected1)) { - $(this.node()).addClass(selClass); - } - }); - } else { - var selected0 = selected1.map(function(i) { return i - 1; }); - $(table.rows(selected0).nodes()).addClass(selClass); - } - } - table.on('mousedown.dt', 'tbody tr', function(e) { - var $this = $(this), thisRow = table.row(this); - if (selMode === 'multiple') { - if (e.shiftKey && lastClickedRow !== undefined) { - // select or de-select depends on the last clicked row's status - var flagSel = !$this.hasClass(selClass); - var crtClickedRow = serverRowIndex(thisRow.index()); - if (server) { - var rowsIndex = shiftSelRowsIndex(lastClickedRow, crtClickedRow); - // update current page's selClass - rowsIndex.map(function(i) { - var rowIndex = DT_rows_current.indexOf(i); - if (rowIndex >= 0) { - var row = table.row(rowIndex).nodes().to$(); - var flagRowSel = !row.hasClass(selClass); - if (flagSel === flagRowSel) row.toggleClass(selClass); - } - }); - // update selected1 - if (flagSel) { - selected1 = unique(selected1.concat(rowsIndex)); - } else { - selected1 = selected1.filter(function(index) { - return !inArray(index, rowsIndex); - }); - } - } else { - // js starts from 0 - shiftSelRowsIndex(lastClickedRow - 1, crtClickedRow - 1).map(function(value) { - var row = table.row(value).nodes().to$(); - var flagRowSel = !row.hasClass(selClass); - if (flagSel === flagRowSel) row.toggleClass(selClass); - }); - } - e.preventDefault(); - } else { - $this.toggleClass(selClass); - } - } else { - if ($this.hasClass(selClass)) { - $this.removeClass(selClass); - } else { - table.$('tr.' + selClass).removeClass(selClass); - $this.addClass(selClass); - } - } - if (server && !$this.hasClass(selClass)) { - var id = DT_rows_current[thisRow.index()]; - // remove id from selected1 since its class .selected has been removed - if (inArray(id, selected1)) selected1.splice($.inArray(id, selected1), 1); - } - selectedRows(); // update selected1's value based on selClass - selectRows(false); // only keep the selectable rows - changeInput('rows_selected', selected1); - changeInput('row_last_clicked', serverRowIndex(thisRow.index()), null, null, {priority: 'event'}); - lastClickedRow = serverRowIndex(thisRow.index()); - }); - selectRows(false); // in case users have specified pre-selected rows - // restore selected rows after the table is redrawn (e.g. sort/search/page); - // client-side tables will preserve the selections automatically; for - // server-side tables, we have to *real* row indices are in `selected1` - changeInput('rows_selected', selected1); - if (server) table.on('draw.dt', function(e) { selectRows(false); }); - methods.selectRows = function(selected, ignoreSelectable) { - selected1 = $.makeArray(selected); - selectRows(ignoreSelectable); - changeInput('rows_selected', selected1); - } - } - - if (inArray(selTarget, ['column', 'row+column'])) { - if (selTarget === 'row+column') { - $(table.columns().footer()).css('cursor', 'pointer'); - } - // update selected2's value based on selectable2 - var onlyKeepSelectableCols = function() { - if (selDisable) { // users can't select; useful when only want backend select - selected2 = []; - return; - } - if (selectable2.length === 0) return; - var nonselectable = selectable2[0] <= 0; - if (nonselectable) { - // need to make selectable2 positive - selected2 = $(selected2).not(selectable2.map(function(i) { return -i; })).get(); - } else { - selected2 = $(selected2).filter(selectable2).get(); - } - } - // update selected2 and then - // refresh the col selection state according to values in selected2 - var selectCols = function(ignoreSelectable) { - if (!ignoreSelectable) onlyKeepSelectableCols(); - // if selected2 is not a valide index (e.g., larger than the column number) - // table.columns(selected2) will fail and result in a blank table - // this is different from the table.rows(), where the out-of-range indexes - // doesn't affect at all - selected2 = $(selected2).filter(table.columns().indexes()).get(); - table.columns().nodes().flatten().to$().removeClass(selClass); - if (selected2.length > 0) - table.columns(selected2).nodes().flatten().to$().addClass(selClass); - } - var callback = function() { - var colIdx = selTarget === 'column' ? table.cell(this).index().column : - $.inArray(this, table.columns().footer()), - thisCol = $(table.column(colIdx).nodes()); - if (colIdx === -1) return; - if (thisCol.hasClass(selClass)) { - thisCol.removeClass(selClass); - selected2.splice($.inArray(colIdx, selected2), 1); - } else { - if (selMode === 'single') $(table.cells().nodes()).removeClass(selClass); - thisCol.addClass(selClass); - selected2 = selMode === 'single' ? [colIdx] : unique(selected2.concat([colIdx])); - } - selectCols(false); // update selected2 based on selectable - changeInput('columns_selected', selected2); - } - if (selTarget === 'column') { - $(table.table().body()).on('click.dt', 'td', callback); - } else { - $(table.table().footer()).on('click.dt', 'tr th', callback); - } - selectCols(false); // in case users have specified pre-selected columns - changeInput('columns_selected', selected2); - if (server) table.on('draw.dt', function(e) { selectCols(false); }); - methods.selectColumns = function(selected, ignoreSelectable) { - selected2 = $.makeArray(selected); - selectCols(ignoreSelectable); - changeInput('columns_selected', selected2); - } - } - - if (selTarget === 'cell') { - var selected3 = [], selectable3 = []; - if (selected !== null) selected3 = selected; - if (selectable !== null && typeof selectable !== 'boolean') selectable3 = selectable; - var findIndex = function(ij, sel) { - for (var i = 0; i < sel.length; i++) { - if (ij[0] === sel[i][0] && ij[1] === sel[i][1]) return i; - } - return -1; - } - // Change selected3's value based on selectable3, then refresh the cell state - var onlyKeepSelectableCells = function() { - if (selDisable) { // users can't select; useful when only want backend select - selected3 = []; - return; - } - if (selectable3.length === 0) return; - var nonselectable = selectable3[0][0] <= 0; - var out = []; - if (nonselectable) { - selected3.map(function(ij) { - // should make selectable3 positive - if (findIndex([-ij[0], -ij[1]], selectable3) === -1) { out.push(ij); } - }); - } else { - selected3.map(function(ij) { - if (findIndex(ij, selectable3) > -1) { out.push(ij); } - }); - } - selected3 = out; - } - // Change selected3's value based on selectable3, then - // refresh the cell selection state according to values in selected3 - var selectCells = function(ignoreSelectable) { - if (!ignoreSelectable) onlyKeepSelectableCells(); - table.$('td.' + selClass).removeClass(selClass); - if (selected3.length === 0) return; - if (server) { - table.cells({page: 'current'}).every(function() { - var info = tweakCellIndex(this); - if (findIndex([info.row, info.col], selected3) > -1) - $(this.node()).addClass(selClass); - }); - } else { - selected3.map(function(ij) { - $(table.cell(ij[0] - 1, ij[1]).node()).addClass(selClass); - }); - } - }; - table.on('click.dt', 'tbody td', function() { - var $this = $(this), info = tweakCellIndex(table.cell(this)); - if ($this.hasClass(selClass)) { - $this.removeClass(selClass); - selected3.splice(findIndex([info.row, info.col], selected3), 1); - } else { - if (selMode === 'single') $(table.cells().nodes()).removeClass(selClass); - $this.addClass(selClass); - selected3 = selMode === 'single' ? [[info.row, info.col]] : - unique(selected3.concat([[info.row, info.col]])); - } - selectCells(false); // must call this to update selected3 based on selectable3 - changeInput('cells_selected', transposeArray2D(selected3), 'shiny.matrix'); - }); - selectCells(false); // in case users have specified pre-selected columns - changeInput('cells_selected', transposeArray2D(selected3), 'shiny.matrix'); - - if (server) table.on('draw.dt', function(e) { selectCells(false); }); - methods.selectCells = function(selected, ignoreSelectable) { - selected3 = selected ? selected : []; - selectCells(ignoreSelectable); - changeInput('cells_selected', transposeArray2D(selected3), 'shiny.matrix'); - } - } - } - - // expose some table info to Shiny - var updateTableInfo = function(e, settings) { - // TODO: is anyone interested in the page info? - // changeInput('page_info', table.page.info()); - var updateRowInfo = function(id, modifier) { - var idx; - if (server) { - idx = modifier.page === 'current' ? DT_rows_current : DT_rows_all; - } else { - var rows = table.rows($.extend({ - search: 'applied', - page: 'all' - }, modifier)); - idx = addOne(rows.indexes().toArray()); - } - changeInput('rows' + '_' + id, idx); - }; - updateRowInfo('current', {page: 'current'}); - updateRowInfo('all', {}); - } - table.on('draw.dt', updateTableInfo); - updateTableInfo(); - - // state info - table.on('draw.dt column-visibility.dt', function() { - changeInput('state', table.state()); - }); - changeInput('state', table.state()); - - // search info - var updateSearchInfo = function() { - changeInput('search', table.search()); - if (filterRow) changeInput('search_columns', filterRow.toArray().map(function(td) { - return $(td).find('input').first().val(); - })); - } - table.on('draw.dt', updateSearchInfo); - updateSearchInfo(); - - var cellInfo = function(thiz) { - var info = tweakCellIndex(table.cell(thiz)); - info.value = table.cell(thiz).data(); - return info; - } - // the current cell clicked on - table.on('click.dt', 'tbody td', function() { - changeInput('cell_clicked', cellInfo(this), null, null, {priority: 'event'}); - }) - changeInput('cell_clicked', {}); - - // do not trigger table selection when clicking on links unless they have classes - table.on('click.dt', 'tbody td a', function(e) { - if (this.className === '') e.stopPropagation(); - }); - - methods.addRow = function(data, rowname, resetPaging) { - var n = table.columns().indexes().length, d = n - data.length; - if (d === 1) { - data = rowname.concat(data) - } else if (d !== 0) { - console.log(data); - console.log(table.columns().indexes()); - throw 'New data must be of the same length as current data (' + n + ')'; - }; - table.row.add(data).draw(resetPaging); - } - - methods.updateSearch = function(keywords) { - if (keywords.global !== null) - $(table.table().container()).find('input[type=search]').first() - .val(keywords.global).trigger('input'); - var columns = keywords.columns; - if (!filterRow || columns === null) return; - filterRow.toArray().map(function(td, i) { - var v = typeof columns === 'string' ? columns : columns[i]; - if (typeof v === 'undefined') { - console.log('The search keyword for column ' + i + ' is undefined') - return; - } - $(td).find('input').first().val(v); - searchColumn(i, v); - }); - table.draw(); - } - - methods.hideCols = function(hide, reset) { - if (reset) table.columns().visible(true, false); - table.columns(hide).visible(false); - } - - methods.showCols = function(show, reset) { - if (reset) table.columns().visible(false, false); - table.columns(show).visible(true); - } - - methods.colReorder = function(order, origOrder) { - table.colReorder.order(order, origOrder); - } - - methods.selectPage = function(page) { - if (table.page.info().pages < page || page < 1) { - throw 'Selected page is out of range'; - }; - table.page(page - 1).draw(false); - } - - methods.reloadData = function(resetPaging, clearSelection) { - // empty selections first if necessary - if (methods.selectRows && inArray('row', clearSelection)) methods.selectRows([]); - if (methods.selectColumns && inArray('column', clearSelection)) methods.selectColumns([]); - if (methods.selectCells && inArray('cell', clearSelection)) methods.selectCells([]); - table.ajax.reload(null, resetPaging); - } - - // update table filters (set new limits of sliders) - methods.updateFilters = function(newProps) { - // loop through each filter in the filter row - filterRow.each(function(i, td) { - var k = i; - if (filterRow.length > newProps.length) { - if (i === 0) return; // first column is row names - k = i - 1; - } - // Update the filters to reflect the updated data. - // Allow "falsy" (e.g. NULL) to signify a no-op. - if (newProps[k]) { - setFilterProps(td, newProps[k]); - } - }); - }; - - table.shinyMethods = methods; - }, - resize: function(el, width, height, instance) { - if (instance.data) this.renderValue(el, instance.data, instance); - - // dynamically adjust height if fillContainer = TRUE - if (instance.fillContainer) - this.fillAvailableHeight(el, height); - - this.adjustWidth(el); - }, - - // dynamically set the scroll body to fill available height - // (used with fillContainer = TRUE) - fillAvailableHeight: function(el, availableHeight) { - - // see how much of the table is occupied by header/footer elements - // and use that to compute a target scroll body height - var dtWrapper = $(el).find('div.dataTables_wrapper'); - var dtScrollBody = $(el).find($('div.dataTables_scrollBody')); - var framingHeight = dtWrapper.innerHeight() - dtScrollBody.innerHeight(); - var scrollBodyHeight = availableHeight - framingHeight; - - // we need to set `max-height` to none as datatables library now sets this - // to a fixed height, disabling the ability to resize to fill the window, - // as it will be set to a fixed 100px under such circumstances, e.g., RStudio IDE, - // or FlexDashboard - // see https://github.com/rstudio/DT/issues/951#issuecomment-1026464509 - dtScrollBody.css('max-height', 'none'); - // set the height - dtScrollBody.height(scrollBodyHeight + 'px'); - }, - - // adjust the width of columns; remove the hard-coded widths on table and the - // scroll header when scrollX/Y are enabled - adjustWidth: function(el) { - var $el = $(el), table = $el.data('datatable'); - if (table) table.columns.adjust(); - $el.find('.dataTables_scrollHeadInner').css('width', '') - .children('table').css('margin-left', ''); - } -}); - - if (!HTMLWidgets.shinyMode) return; - - Shiny.addCustomMessageHandler('datatable-calls', function(data) { - var id = data.id; - var el = document.getElementById(id); - var table = el ? $(el).data('datatable') : null; - if (!table) { - console.log("Couldn't find table with id " + id); - return; - } - - var methods = table.shinyMethods, call = data.call; - if (methods[call.method]) { - methods[call.method].apply(table, call.args); - } else { - console.log("Unknown method " + call.method); - } - }); - -})(); diff --git a/master/assets/datatables-css-0.0.0/datatables-crosstalk.css b/master/assets/datatables-css-0.0.0/datatables-crosstalk.css deleted file mode 100644 index fb5bae849..000000000 --- a/master/assets/datatables-css-0.0.0/datatables-crosstalk.css +++ /dev/null @@ -1,23 +0,0 @@ -.dt-crosstalk-fade { - opacity: 0.2; -} - -html body div.DTS div.dataTables_scrollBody { - background: none; -} - - -/* -Fix https://github.com/rstudio/DT/issues/563 -If the `table.display` is set to "block" (e.g., pkgdown), the browser will display -datatable objects strangely. The search panel and the page buttons will still be -in full-width but the table body will be "compact" and shorter. -In therory, having this attributes will affect `dom="t"` -with `display: block` users. But in reality, there should be no one. -We may remove the below lines in the future if the upstream agree to have this there. -See https://github.com/DataTables/DataTablesSrc/issues/160 -*/ - -table.dataTable { - display: table; -} diff --git a/master/assets/dt-core-1.11.3/css/jquery.dataTables.extra.css b/master/assets/dt-core-1.11.3/css/jquery.dataTables.extra.css deleted file mode 100644 index b2dd141f4..000000000 --- a/master/assets/dt-core-1.11.3/css/jquery.dataTables.extra.css +++ /dev/null @@ -1,28 +0,0 @@ -/* Selected rows/cells */ -table.dataTable tr.selected td, table.dataTable td.selected { - background-color: #b0bed9 !important; -} -/* In case of scrollX/Y or FixedHeader */ -.dataTables_scrollBody .dataTables_sizing { - visibility: hidden; -} - -/* The datatables' theme CSS file doesn't define -the color but with white background. It leads to an issue that -when the HTML's body color is set to 'white', the user can't -see the text since the background is white. One case happens in the -RStudio's IDE when inline viewing the DT table inside an Rmd file, -if the IDE theme is set to "Cobalt". - -See https://github.com/rstudio/DT/issues/447 for more info - -This fixes should have little side-effects because all the other elements -of the default theme use the #333 font color. - -TODO: The upstream may use relative colors for both the table background -and the color. It means the table can display well without this patch -then. At that time, we need to remove the below CSS attributes. -*/ -div.datatables { - color: #333; -} diff --git a/master/assets/dt-core-1.11.3/css/jquery.dataTables.min.css b/master/assets/dt-core-1.11.3/css/jquery.dataTables.min.css deleted file mode 100644 index f1db0e82d..000000000 --- a/master/assets/dt-core-1.11.3/css/jquery.dataTables.min.css +++ /dev/null @@ -1 +0,0 @@ -td.dt-control{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAACjElEQVR4Aa2V30uTURjHnVBUgglCaXVTJJVLMdhQm7+1JEvJiKAggmgSQiKJl0V0E13UVf0HQZmBLcvlpqa55tqV0YoMzIhY6js0yDH11X17vuO8Sq5Zgl/48DznPD/G63nOMSmBkoUNwhYhTUgn9NUeY8z5p0wqOVXYKRwQLMJhhYV7Kpaqck2rNdskbBPMdrv9osfjcQaDwW/RaHSR0OceY8xhrqox/a3ZZmGHkO9wOB7ouj6PBGKMOcxlzcqmdDYKGZmZmSWjo6PvIYosRuDWXGj50IwTb4+hxleN5sAVvJh4jvBCGBRzWSO121UPk3EAaUKuz+d7ycTp+Wnc/nwL1d4qHBVidmjZv/npBkJzGiiv19vFWmGrcVDsvKupqeky/056VMf1j9dQOViBKo9Aa/ixdbnYcrQGWsBc1jQ2NtrZQ/VKShHM8kvdEPVN9qJsoBRl/aUoHyiJ+UpcCxJTtmfCDYoHJT2yYyOlPtcaCoUmGGwdbkVRbxGK+2y0gg2GisUvNmJCy/BVUJqm/eBIxXqpgbUtiBise12HQlc+ClwFSKRCiZH6wXpQs7OzETWn6XENa/trYemywuK0IpGsTotgRU3fcVBzouWG6pOnpqY0BhuGGpDXeUjIW7JKcfuX3tjjP9k4FBkZN4PtY+042JGzzNMcGDJ35C7tmcU++tJmjE63OpSUuLEJ62GcfXUO+59kr8rJnlOY0WfAGtYaY/PHYPv9fhdEY7++4nz/BWS17UPWY0Es2avWp3vOYOTnCCheBtaqHskJr95kZBL3AvdR2XkEex5mYbdQ+qwCd97dRTAcXHn1Moyrt16PA2tN//V8jY+Pf4cS/VWerzU9sDay1gd2Xf4F/AZqlpeB9836LwAAAABJRU5ErkJggg==) no-repeat center center;cursor:pointer}tr.dt-hasChild td.dt-control{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAACdUlEQVR4Aa2V30tTYRjHVSgsoQKhXPUPlKZMlImiIIg/pggiiDeCBAdqyC4Kf9zVhVdeelX33QnCbtYvxZsxxkoqKxiz1SzdFudMb5xO5/bt+fa+sPCw3IVf+PA+532e5ytn53lfK0qoSrggXBauCbUKxtxjjjVnq1IXXxFuCXeEFqGdMOYec6zRtZX/M6sWrgv1hmHcDwQCLxOJxM9CoZAnjLnHHGt0bbXdVG1cEm4KLp/P9yKXyx2jhJhjDWvZc9qUwUWhzuFwdMVisc8QFQ4PcbCygvT0NJLDw0gNDSH96DEyfj8KmQwo1rJHem8oD2VapX/sxlAo9Aqi/N4e9hYWsDMwgARxD2DH7ZZYren5eZxYFqhgMOhnr3BVeSnn216v98Hf3yqXg/X0CX719YFs9/WquJfPGtkzZ2fBWvZ4PB6DHtqrokaol7/0GqLM2hq2enpsxMmpvf3VVVD8UOJxV42Uet1Wy7J+M5mam8P37u6ySM7MgDJNM8mRUl5qYDtOREz+GB3FZlcXNjs7UUrMk/jYGKhsNnuo57TWZhgTw0hHO0EpRdpV/tvICKgjUdFQv/Lu7q7JZHxqCl9dLqGtSJtL4VJ80Wvc8xD2V9YfRUbmLZPp5WVstLTYaSWt+lmt1tISKH5Q/VFqbGOTl6GNTk7iQ3Oz4FSrU8UfuTqdBJHxceQz+2APe/8Zm+Jgh8PhNxBlt7YQNQysNzVivbEJ7wXGiiZEJiZwEI2C4mFgr/aoKnn0jk0TiWfPsTE4iHcN9xBuaMCn/n5sLy7iKJk8ffTqikfvfC4H9laWdX2lUqltaDEu9/o664LtIOVfsOf4L+APb5yaiwyN8+8AAAAASUVORK5CYII=) no-repeat center center}table.dataTable th.dt-left,table.dataTable td.dt-left{text-align:left}table.dataTable th.dt-center,table.dataTable td.dt-center,table.dataTable td.dataTables_empty{text-align:center}table.dataTable th.dt-right,table.dataTable td.dt-right{text-align:right}table.dataTable th.dt-justify,table.dataTable td.dt-justify{text-align:justify}table.dataTable th.dt-nowrap,table.dataTable td.dt-nowrap{white-space:nowrap}table.dataTable thead th.dt-head-left,table.dataTable thead td.dt-head-left,table.dataTable tfoot th.dt-head-left,table.dataTable tfoot td.dt-head-left{text-align:left}table.dataTable thead th.dt-head-center,table.dataTable thead td.dt-head-center,table.dataTable tfoot th.dt-head-center,table.dataTable tfoot td.dt-head-center{text-align:center}table.dataTable thead th.dt-head-right,table.dataTable thead td.dt-head-right,table.dataTable tfoot th.dt-head-right,table.dataTable tfoot td.dt-head-right{text-align:right}table.dataTable thead th.dt-head-justify,table.dataTable thead td.dt-head-justify,table.dataTable tfoot th.dt-head-justify,table.dataTable tfoot td.dt-head-justify{text-align:justify}table.dataTable thead th.dt-head-nowrap,table.dataTable thead td.dt-head-nowrap,table.dataTable tfoot th.dt-head-nowrap,table.dataTable tfoot td.dt-head-nowrap{white-space:nowrap}table.dataTable tbody th.dt-body-left,table.dataTable tbody td.dt-body-left{text-align:left}table.dataTable tbody th.dt-body-center,table.dataTable tbody td.dt-body-center{text-align:center}table.dataTable tbody th.dt-body-right,table.dataTable tbody td.dt-body-right{text-align:right}table.dataTable tbody th.dt-body-justify,table.dataTable tbody td.dt-body-justify{text-align:justify}table.dataTable tbody th.dt-body-nowrap,table.dataTable tbody td.dt-body-nowrap{white-space:nowrap}table.dataTable{width:100%;margin:0 auto;clear:both;border-collapse:separate;border-spacing:0}table.dataTable thead th,table.dataTable tfoot th{font-weight:bold}table.dataTable thead th,table.dataTable thead td{padding:10px 18px;border-bottom:1px solid #111}table.dataTable thead th:active,table.dataTable thead td:active{outline:none}table.dataTable tfoot th,table.dataTable tfoot td{padding:10px 18px 6px 18px;border-top:1px solid #111}table.dataTable thead .sorting,table.dataTable thead .sorting_asc,table.dataTable thead .sorting_desc,table.dataTable thead .sorting_asc_disabled,table.dataTable thead .sorting_desc_disabled{cursor:pointer;*cursor:hand;background-repeat:no-repeat;background-position:center right}table.dataTable thead .sorting{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAQAAADYWf5HAAAAkElEQVQoz7XQMQ5AQBCF4dWQSJxC5wwax1Cq1e7BAdxD5SL+Tq/QCM1oNiJidwox0355mXnG/DrEtIQ6azioNZQxI0ykPhTQIwhCR+BmBYtlK7kLJYwWCcJA9M4qdrZrd8pPjZWPtOqdRQy320YSV17OatFC4euts6z39GYMKRPCTKY9UnPQ6P+GtMRfGtPnBCiqhAeJPmkqAAAAAElFTkSuQmCC)}table.dataTable thead .sorting_asc{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAYAAAByUDbMAAAAZ0lEQVQ4y2NgGLKgquEuFxBPAGI2ahhWCsS/gDibUoO0gPgxEP8H4ttArEyuQYxAPBdqEAxPBImTY5gjEL9DM+wTENuQahAvEO9DMwiGdwAxOymGJQLxTyD+jgWDxCMZRsEoGAVoAADeemwtPcZI2wAAAABJRU5ErkJggg==) !important}table.dataTable thead .sorting_desc{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAYAAAByUDbMAAAAZUlEQVQ4y2NgGAWjYBSggaqGu5FA/BOIv2PBIPFEUgxjB+IdQPwfC94HxLykus4GiD+hGfQOiB3J8SojEE9EM2wuSJzcsFMG4ttQgx4DsRalkZENxL+AuJQaMcsGxBOAmGvopk8AVz1sLZgg0bsAAAAASUVORK5CYII=) !important}table.dataTable thead .sorting_asc_disabled{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAQAAADYWf5HAAAAWUlEQVQoz2NgGAWDCtyJvPPzznc4/HknEbsy9js77vyHw313eHGZZ3PnE1TRuzuOuK1lvDMRqmzuHUZ87lO+cxuo6PEdLUIeyb7z604pYf+y3Zlwh4u2YQoAc7ZCBHH4jigAAAAASUVORK5CYII=)}table.dataTable thead .sorting_desc_disabled{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAQAAADYWf5HAAAAW0lEQVQoz2NgoCm4w3Vnwh02wspK7/y6k01Ikdadx3f+37l9RxmfIsY7c4GKQHDiHUbcyhzvvIMq+3THBpci3jv7oIpAcMcdduzKEu/8vPMdDn/eiWQYBYMKAAC3ykIEuYQJUgAAAABJRU5ErkJggg==)}table.dataTable tbody tr{background-color:#fff}table.dataTable tbody tr.selected{background-color:#b0bed9}table.dataTable tbody th,table.dataTable tbody td{padding:8px 10px}table.dataTable.row-border tbody th,table.dataTable.row-border tbody td,table.dataTable.display tbody th,table.dataTable.display tbody td{border-top:1px solid #ddd}table.dataTable.row-border tbody tr:first-child th,table.dataTable.row-border tbody tr:first-child td,table.dataTable.display tbody tr:first-child th,table.dataTable.display tbody tr:first-child td{border-top:none}table.dataTable.cell-border tbody th,table.dataTable.cell-border tbody td{border-top:1px solid #ddd;border-right:1px solid #ddd}table.dataTable.cell-border tbody tr th:first-child,table.dataTable.cell-border tbody tr td:first-child{border-left:1px solid #ddd}table.dataTable.cell-border tbody tr:first-child th,table.dataTable.cell-border tbody tr:first-child td{border-top:none}table.dataTable.stripe tbody tr.odd,table.dataTable.display tbody tr.odd{background-color:#f9f9f9}table.dataTable.stripe tbody tr.odd.selected,table.dataTable.display tbody tr.odd.selected{background-color:#acbad4}table.dataTable.hover tbody tr:hover,table.dataTable.display tbody tr:hover{background-color:#f6f6f6}table.dataTable.hover tbody tr:hover.selected,table.dataTable.display tbody tr:hover.selected{background-color:#aab7d1}table.dataTable.order-column tbody tr>.sorting_1,table.dataTable.order-column tbody tr>.sorting_2,table.dataTable.order-column tbody tr>.sorting_3,table.dataTable.display tbody tr>.sorting_1,table.dataTable.display tbody tr>.sorting_2,table.dataTable.display tbody tr>.sorting_3{background-color:#fafafa}table.dataTable.order-column tbody tr.selected>.sorting_1,table.dataTable.order-column tbody tr.selected>.sorting_2,table.dataTable.order-column tbody tr.selected>.sorting_3,table.dataTable.display tbody tr.selected>.sorting_1,table.dataTable.display tbody tr.selected>.sorting_2,table.dataTable.display tbody tr.selected>.sorting_3{background-color:#acbad5}table.dataTable.display tbody tr.odd>.sorting_1,table.dataTable.order-column.stripe tbody tr.odd>.sorting_1{background-color:#f1f1f1}table.dataTable.display tbody tr.odd>.sorting_2,table.dataTable.order-column.stripe tbody tr.odd>.sorting_2{background-color:#f3f3f3}table.dataTable.display tbody tr.odd>.sorting_3,table.dataTable.order-column.stripe tbody tr.odd>.sorting_3{background-color:whitesmoke}table.dataTable.display tbody tr.odd.selected>.sorting_1,table.dataTable.order-column.stripe tbody tr.odd.selected>.sorting_1{background-color:#a6b4cd}table.dataTable.display tbody tr.odd.selected>.sorting_2,table.dataTable.order-column.stripe tbody tr.odd.selected>.sorting_2{background-color:#a8b5cf}table.dataTable.display tbody tr.odd.selected>.sorting_3,table.dataTable.order-column.stripe tbody tr.odd.selected>.sorting_3{background-color:#a9b7d1}table.dataTable.display tbody tr.even>.sorting_1,table.dataTable.order-column.stripe tbody tr.even>.sorting_1{background-color:#fafafa}table.dataTable.display tbody tr.even>.sorting_2,table.dataTable.order-column.stripe tbody tr.even>.sorting_2{background-color:#fcfcfc}table.dataTable.display tbody tr.even>.sorting_3,table.dataTable.order-column.stripe tbody tr.even>.sorting_3{background-color:#fefefe}table.dataTable.display tbody tr.even.selected>.sorting_1,table.dataTable.order-column.stripe tbody tr.even.selected>.sorting_1{background-color:#acbad5}table.dataTable.display tbody tr.even.selected>.sorting_2,table.dataTable.order-column.stripe tbody tr.even.selected>.sorting_2{background-color:#aebcd6}table.dataTable.display tbody tr.even.selected>.sorting_3,table.dataTable.order-column.stripe tbody tr.even.selected>.sorting_3{background-color:#afbdd8}table.dataTable.display tbody tr:hover>.sorting_1,table.dataTable.order-column.hover tbody tr:hover>.sorting_1{background-color:#eaeaea}table.dataTable.display tbody tr:hover>.sorting_2,table.dataTable.order-column.hover tbody tr:hover>.sorting_2{background-color:#ececec}table.dataTable.display tbody tr:hover>.sorting_3,table.dataTable.order-column.hover tbody tr:hover>.sorting_3{background-color:#efefef}table.dataTable.display tbody tr:hover.selected>.sorting_1,table.dataTable.order-column.hover tbody tr:hover.selected>.sorting_1{background-color:#a2aec7}table.dataTable.display tbody tr:hover.selected>.sorting_2,table.dataTable.order-column.hover tbody tr:hover.selected>.sorting_2{background-color:#a3b0c9}table.dataTable.display tbody tr:hover.selected>.sorting_3,table.dataTable.order-column.hover tbody tr:hover.selected>.sorting_3{background-color:#a5b2cb}table.dataTable.no-footer{border-bottom:1px solid #111}table.dataTable.nowrap th,table.dataTable.nowrap td{white-space:nowrap}table.dataTable.compact thead th,table.dataTable.compact thead td{padding:4px 17px}table.dataTable.compact tfoot th,table.dataTable.compact tfoot td{padding:4px}table.dataTable.compact tbody th,table.dataTable.compact tbody td{padding:4px}table.dataTable th,table.dataTable td{box-sizing:content-box}.dataTables_wrapper{position:relative;clear:both}.dataTables_wrapper .dataTables_length{float:left}.dataTables_wrapper .dataTables_length select{border:1px solid #aaa;border-radius:3px;padding:5px;background-color:transparent;padding:4px}.dataTables_wrapper .dataTables_filter{float:right;text-align:right}.dataTables_wrapper .dataTables_filter input{border:1px solid #aaa;border-radius:3px;padding:5px;background-color:transparent;margin-left:3px}.dataTables_wrapper .dataTables_info{clear:both;float:left;padding-top:.755em}.dataTables_wrapper .dataTables_paginate{float:right;text-align:right;padding-top:.25em}.dataTables_wrapper .dataTables_paginate .paginate_button{box-sizing:border-box;display:inline-block;min-width:1.5em;padding:.5em 1em;margin-left:2px;text-align:center;text-decoration:none !important;cursor:pointer;*cursor:hand;color:#333 !important;border:1px solid transparent;border-radius:2px}.dataTables_wrapper .dataTables_paginate .paginate_button.current,.dataTables_wrapper .dataTables_paginate .paginate_button.current:hover{color:#333 !important;border:1px solid #979797;background-color:white;background:-webkit-gradient(linear, left top, left bottom, color-stop(0%, white), color-stop(100%, #dcdcdc));background:-webkit-linear-gradient(top, white 0%, #dcdcdc 100%);background:-moz-linear-gradient(top, white 0%, #dcdcdc 100%);background:-ms-linear-gradient(top, white 0%, #dcdcdc 100%);background:-o-linear-gradient(top, white 0%, #dcdcdc 100%);background:linear-gradient(to bottom, white 0%, #dcdcdc 100%)}.dataTables_wrapper .dataTables_paginate .paginate_button.disabled,.dataTables_wrapper .dataTables_paginate .paginate_button.disabled:hover,.dataTables_wrapper .dataTables_paginate .paginate_button.disabled:active{cursor:default;color:#666 !important;border:1px solid transparent;background:transparent;box-shadow:none}.dataTables_wrapper .dataTables_paginate .paginate_button:hover{color:white !important;border:1px solid #111;background-color:#585858;background:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #585858), color-stop(100%, #111));background:-webkit-linear-gradient(top, #585858 0%, #111 100%);background:-moz-linear-gradient(top, #585858 0%, #111 100%);background:-ms-linear-gradient(top, #585858 0%, #111 100%);background:-o-linear-gradient(top, #585858 0%, #111 100%);background:linear-gradient(to bottom, #585858 0%, #111 100%)}.dataTables_wrapper .dataTables_paginate .paginate_button:active{outline:none;background-color:#2b2b2b;background:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #2b2b2b), color-stop(100%, #0c0c0c));background:-webkit-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:-moz-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:-ms-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:-o-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:linear-gradient(to bottom, #2b2b2b 0%, #0c0c0c 100%);box-shadow:inset 0 0 3px #111}.dataTables_wrapper .dataTables_paginate .ellipsis{padding:0 1em}.dataTables_wrapper .dataTables_processing{position:absolute;top:50%;left:50%;width:100%;height:40px;margin-left:-50%;margin-top:-25px;padding-top:20px;text-align:center;font-size:1.2em;background-color:white;background:-webkit-gradient(linear, left top, right top, color-stop(0%, rgba(255, 255, 255, 0)), color-stop(25%, rgba(255, 255, 255, 0.9)), color-stop(75%, rgba(255, 255, 255, 0.9)), color-stop(100%, rgba(255, 255, 255, 0)));background:-webkit-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);background:-moz-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);background:-ms-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);background:-o-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);background:linear-gradient(to right, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%)}.dataTables_wrapper .dataTables_length,.dataTables_wrapper .dataTables_filter,.dataTables_wrapper .dataTables_info,.dataTables_wrapper .dataTables_processing,.dataTables_wrapper .dataTables_paginate{color:#333}.dataTables_wrapper .dataTables_scroll{clear:both}.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody{*margin-top:-1px;-webkit-overflow-scrolling:touch}.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>thead>tr>th,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>thead>tr>td,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>tbody>tr>th,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>tbody>tr>td{vertical-align:middle}.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>thead>tr>th>div.dataTables_sizing,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>thead>tr>td>div.dataTables_sizing,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>tbody>tr>th>div.dataTables_sizing,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>tbody>tr>td>div.dataTables_sizing{height:0;overflow:hidden;margin:0 !important;padding:0 !important}.dataTables_wrapper.no-footer .dataTables_scrollBody{border-bottom:1px solid #111}.dataTables_wrapper.no-footer div.dataTables_scrollHead table.dataTable,.dataTables_wrapper.no-footer div.dataTables_scrollBody>table{border-bottom:none}.dataTables_wrapper:after{visibility:hidden;display:block;content:"";clear:both;height:0}@media screen and (max-width: 767px){.dataTables_wrapper .dataTables_info,.dataTables_wrapper .dataTables_paginate{float:none;text-align:center}.dataTables_wrapper .dataTables_paginate{margin-top:.5em}}@media screen and (max-width: 640px){.dataTables_wrapper .dataTables_length,.dataTables_wrapper .dataTables_filter{float:none;text-align:center}.dataTables_wrapper .dataTables_filter{margin-top:.5em}} diff --git a/master/assets/dt-core-1.11.3/js/jquery.dataTables.min.js b/master/assets/dt-core-1.11.3/js/jquery.dataTables.min.js deleted file mode 100644 index ff23e9148..000000000 --- a/master/assets/dt-core-1.11.3/js/jquery.dataTables.min.js +++ /dev/null @@ -1,187 +0,0 @@ -/*! - Copyright 2008-2021 SpryMedia Ltd. - - This source file is free software, available under the following license: - MIT license - http://datatables.net/license - - This source file is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details. - - For details please refer to: http://www.datatables.net - DataTables 1.11.3 - ©2008-2021 SpryMedia Ltd - datatables.net/license -*/ -var $jscomp=$jscomp||{};$jscomp.scope={};$jscomp.findInternal=function(l,z,A){l instanceof String&&(l=String(l));for(var q=l.length,E=0;E").css({position:"fixed",top:0,left:-1*l(z).scrollLeft(),height:1, -width:1,overflow:"hidden"}).append(l("
").css({position:"absolute",top:1,left:1,width:100,overflow:"scroll"}).append(l("
").css({width:"100%",height:10}))).appendTo("body"),d=c.children(),e=d.children();b.barWidth=d[0].offsetWidth-d[0].clientWidth;b.bScrollOversize=100===e[0].offsetWidth&&100!==d[0].clientWidth;b.bScrollbarLeft=1!==Math.round(e.offset().left);b.bBounding=c[0].getBoundingClientRect().width?!0:!1;c.remove()}l.extend(a.oBrowser,u.__browser);a.oScroll.iBarWidth=u.__browser.barWidth} -function Cb(a,b,c,d,e,h){var f=!1;if(c!==q){var g=c;f=!0}for(;d!==e;)a.hasOwnProperty(d)&&(g=f?b(g,a[d],d,a):a[d],f=!0,d+=h);return g}function Xa(a,b){var c=u.defaults.column,d=a.aoColumns.length;c=l.extend({},u.models.oColumn,c,{nTh:b?b:A.createElement("th"),sTitle:c.sTitle?c.sTitle:b?b.innerHTML:"",aDataSort:c.aDataSort?c.aDataSort:[d],mData:c.mData?c.mData:d,idx:d});a.aoColumns.push(c);c=a.aoPreSearchCols;c[d]=l.extend({},u.models.oSearch,c[d]);Ga(a,d,l(b).data())}function Ga(a,b,c){b=a.aoColumns[b]; -var d=a.oClasses,e=l(b.nTh);if(!b.sWidthOrig){b.sWidthOrig=e.attr("width")||null;var h=(e.attr("style")||"").match(/width:\s*(\d+[pxem%]+)/);h&&(b.sWidthOrig=h[1])}c!==q&&null!==c&&(Ab(c),P(u.defaults.column,c,!0),c.mDataProp===q||c.mData||(c.mData=c.mDataProp),c.sType&&(b._sManualType=c.sType),c.className&&!c.sClass&&(c.sClass=c.className),c.sClass&&e.addClass(c.sClass),l.extend(b,c),X(b,c,"sWidth","sWidthOrig"),c.iDataSort!==q&&(b.aDataSort=[c.iDataSort]),X(b,c,"aDataSort"));var f=b.mData,g=na(f), -k=b.mRender?na(b.mRender):null;c=function(m){return"string"===typeof m&&-1!==m.indexOf("@")};b._bAttrSrc=l.isPlainObject(f)&&(c(f.sort)||c(f.type)||c(f.filter));b._setter=null;b.fnGetData=function(m,n,p){var t=g(m,n,q,p);return k&&n?k(t,n,m,p):t};b.fnSetData=function(m,n,p){return ha(f)(m,n,p)};"number"!==typeof f&&(a._rowReadObject=!0);a.oFeatures.bSort||(b.bSortable=!1,e.addClass(d.sSortableNone));a=-1!==l.inArray("asc",b.asSorting);c=-1!==l.inArray("desc",b.asSorting);b.bSortable&&(a||c)?a&&!c? -(b.sSortingClass=d.sSortableAsc,b.sSortingClassJUI=d.sSortJUIAscAllowed):!a&&c?(b.sSortingClass=d.sSortableDesc,b.sSortingClassJUI=d.sSortJUIDescAllowed):(b.sSortingClass=d.sSortable,b.sSortingClassJUI=d.sSortJUI):(b.sSortingClass=d.sSortableNone,b.sSortingClassJUI="")}function ta(a){if(!1!==a.oFeatures.bAutoWidth){var b=a.aoColumns;Ya(a);for(var c=0,d=b.length;cm[n])d(g.length+m[n],k);else if("string"===typeof m[n]){var p=0;for(f=g.length;pb&&a[e]--; -1!=d&&c===q&&a.splice(d,1)}function wa(a,b,c,d){var e=a.aoData[b],h,f=function(k,m){for(;k.childNodes.length;)k.removeChild(k.firstChild);k.innerHTML=T(a,b,m,"display")};if("dom"!==c&&(c&&"auto"!==c||"dom"!==e.src)){var g=e.anCells;if(g)if(d!==q)f(g[d],d);else for(c=0,h=g.length;c").appendTo(d));var k=0;for(b=g.length;k=a.fnRecordsDisplay()?0:g,a.iInitDisplayStart=-1);g=a._iDisplayStart;var n=a.fnDisplayEnd();if(a.bDeferLoading)a.bDeferLoading=!1,a.iDraw++,V(a,!1);else if(!k)a.iDraw++;else if(!a.bDestroying&&!b){Gb(a);return}if(0!==m.length)for(b=k?a.aoData.length:n,f=k?0:g;f",{"class":h?e[0]:""}).append(l("",{valign:"top",colSpan:oa(a),"class":a.oClasses.sRowEmpty}).html(d))[0];F(a,"aoHeaderCallback","header",[l(a.nTHead).children("tr")[0],cb(a),g,n,m]);F(a,"aoFooterCallback", -"footer",[l(a.nTFoot).children("tr")[0],cb(a),g,n,m]);e=l(a.nTBody);e.children().detach();e.append(l(c));F(a,"aoDrawCallback","draw",[a]);a.bSorted=!1;a.bFiltered=!1;a.bDrawing=!1}}function ka(a,b){var c=a.oFeatures,d=c.bFilter;c.bSort&&Hb(a);d?za(a,a.oPreviousSearch):a.aiDisplay=a.aiDisplayMaster.slice();!0!==b&&(a._iDisplayStart=0);a._drawHold=b;ja(a);a._drawHold=!1}function Ib(a){var b=a.oClasses,c=l(a.nTable);c=l("
").insertBefore(c);var d=a.oFeatures,e=l("
",{id:a.sTableId+"_wrapper", -"class":b.sWrapper+(a.nTFoot?"":" "+b.sNoFooter)});a.nHolding=c[0];a.nTableWrapper=e[0];a.nTableReinsertBefore=a.nTable.nextSibling;for(var h=a.sDom.split(""),f,g,k,m,n,p,t=0;t")[0];m=h[t+1];if("'"==m||'"'==m){n="";for(p=2;h[t+p]!=m;)n+=h[t+p],p++;"H"==n?n=b.sJUIHeader:"F"==n&&(n=b.sJUIFooter);-1!=n.indexOf(".")?(m=n.split("."),k.id=m[0].substr(1,m[0].length-1),k.className=m[1]):"#"==n.charAt(0)?k.id=n.substr(1,n.length-1):k.className=n;t+=p}e.append(k); -e=l(k)}else if(">"==g)e=e.parent();else if("l"==g&&d.bPaginate&&d.bLengthChange)f=Jb(a);else if("f"==g&&d.bFilter)f=Kb(a);else if("r"==g&&d.bProcessing)f=Lb(a);else if("t"==g)f=Mb(a);else if("i"==g&&d.bInfo)f=Nb(a);else if("p"==g&&d.bPaginate)f=Ob(a);else if(0!==u.ext.feature.length)for(k=u.ext.feature,p=0,m=k.length;p',g=d.sSearch;g=g.match(/_INPUT_/)?g.replace("_INPUT_",f):g+f;b=l("
",{id:h.f?null:c+"_filter","class":b.sFilter}).append(l("
").addClass(b.sLength);a.aanFeatures.l||(k[0].id=c+"_length");k.children().append(a.oLanguage.sLengthMenu.replace("_MENU_",e[0].outerHTML));l("select",k).val(a._iDisplayLength).on("change.DT",function(m){jb(a,l(this).val());ja(a)});l(a.nTable).on("length.dt.DT",function(m,n,p){a===n&&l("select",k).val(p)});return k[0]}function Ob(a){var b=a.sPaginationType,c=u.ext.pager[b],d="function"===typeof c,e=function(f){ja(f)};b=l("
").addClass(a.oClasses.sPaging+b)[0]; -var h=a.aanFeatures;d||c.fnInit(a,b,e);h.p||(b.id=a.sTableId+"_paginate",a.aoDrawCallback.push({fn:function(f){if(d){var g=f._iDisplayStart,k=f._iDisplayLength,m=f.fnRecordsDisplay(),n=-1===k;g=n?0:Math.ceil(g/k);k=n?1:Math.ceil(m/k);m=c(g,k);var p;n=0;for(p=h.p.length;nh&& -(d=0)):"first"==b?d=0:"previous"==b?(d=0<=e?d-e:0,0>d&&(d=0)):"next"==b?d+e",{id:a.aanFeatures.r?null:a.sTableId+"_processing","class":a.oClasses.sProcessing}).html(a.oLanguage.sProcessing).insertBefore(a.nTable)[0]}function V(a,b){a.oFeatures.bProcessing&&l(a.aanFeatures.r).css("display",b?"block":"none"); -F(a,null,"processing",[a,b])}function Mb(a){var b=l(a.nTable),c=a.oScroll;if(""===c.sX&&""===c.sY)return a.nTable;var d=c.sX,e=c.sY,h=a.oClasses,f=b.children("caption"),g=f.length?f[0]._captionSide:null,k=l(b[0].cloneNode(!1)),m=l(b[0].cloneNode(!1)),n=b.children("tfoot");n.length||(n=null);k=l("
",{"class":h.sScrollWrapper}).append(l("
",{"class":h.sScrollHead}).css({overflow:"hidden",position:"relative",border:0,width:d?d?K(d):null:"100%"}).append(l("
",{"class":h.sScrollHeadInner}).css({"box-sizing":"content-box", -width:c.sXInner||"100%"}).append(k.removeAttr("id").css("margin-left",0).append("top"===g?f:null).append(b.children("thead"))))).append(l("
",{"class":h.sScrollBody}).css({position:"relative",overflow:"auto",width:d?K(d):null}).append(b));n&&k.append(l("
",{"class":h.sScrollFoot}).css({overflow:"hidden",border:0,width:d?d?K(d):null:"100%"}).append(l("
",{"class":h.sScrollFootInner}).append(m.removeAttr("id").css("margin-left",0).append("bottom"===g?f:null).append(b.children("tfoot"))))); -b=k.children();var p=b[0];h=b[1];var t=n?b[2]:null;if(d)l(h).on("scroll.DT",function(v){v=this.scrollLeft;p.scrollLeft=v;n&&(t.scrollLeft=v)});l(h).css("max-height",e);c.bCollapse||l(h).css("height",e);a.nScrollHead=p;a.nScrollBody=h;a.nScrollFoot=t;a.aoDrawCallback.push({fn:Ha,sName:"scrolling"});return k[0]}function Ha(a){var b=a.oScroll,c=b.sX,d=b.sXInner,e=b.sY;b=b.iBarWidth;var h=l(a.nScrollHead),f=h[0].style,g=h.children("div"),k=g[0].style,m=g.children("table");g=a.nScrollBody;var n=l(g),p= -g.style,t=l(a.nScrollFoot).children("div"),v=t.children("table"),x=l(a.nTHead),w=l(a.nTable),r=w[0],C=r.style,G=a.nTFoot?l(a.nTFoot):null,aa=a.oBrowser,L=aa.bScrollOversize;U(a.aoColumns,"nTh");var O=[],I=[],H=[],ea=[],Y,Ca=function(D){D=D.style;D.paddingTop="0";D.paddingBottom="0";D.borderTopWidth="0";D.borderBottomWidth="0";D.height=0};var fa=g.scrollHeight>g.clientHeight;if(a.scrollBarVis!==fa&&a.scrollBarVis!==q)a.scrollBarVis=fa,ta(a);else{a.scrollBarVis=fa;w.children("thead, tfoot").remove(); -if(G){var ba=G.clone().prependTo(w);var la=G.find("tr");ba=ba.find("tr")}var mb=x.clone().prependTo(w);x=x.find("tr");fa=mb.find("tr");mb.find("th, td").removeAttr("tabindex");c||(p.width="100%",h[0].style.width="100%");l.each(Na(a,mb),function(D,W){Y=ua(a,D);W.style.width=a.aoColumns[Y].sWidth});G&&ca(function(D){D.style.width=""},ba);h=w.outerWidth();""===c?(C.width="100%",L&&(w.find("tbody").height()>g.offsetHeight||"scroll"==n.css("overflow-y"))&&(C.width=K(w.outerWidth()-b)),h=w.outerWidth()): -""!==d&&(C.width=K(d),h=w.outerWidth());ca(Ca,fa);ca(function(D){var W=z.getComputedStyle?z.getComputedStyle(D).width:K(l(D).width());H.push(D.innerHTML);O.push(W)},fa);ca(function(D,W){D.style.width=O[W]},x);l(fa).height(0);G&&(ca(Ca,ba),ca(function(D){ea.push(D.innerHTML);I.push(K(l(D).css("width")))},ba),ca(function(D,W){D.style.width=I[W]},la),l(ba).height(0));ca(function(D,W){D.innerHTML='
'+H[W]+"
";D.childNodes[0].style.height="0";D.childNodes[0].style.overflow= -"hidden";D.style.width=O[W]},fa);G&&ca(function(D,W){D.innerHTML='
'+ea[W]+"
";D.childNodes[0].style.height="0";D.childNodes[0].style.overflow="hidden";D.style.width=I[W]},ba);w.outerWidth()g.offsetHeight||"scroll"==n.css("overflow-y")?h+b:h,L&&(g.scrollHeight>g.offsetHeight||"scroll"==n.css("overflow-y"))&&(C.width=K(la-b)),""!==c&&""===d||da(a,1,"Possible column misalignment",6)):la="100%";p.width=K(la);f.width=K(la);G&&(a.nScrollFoot.style.width= -K(la));!e&&L&&(p.height=K(r.offsetHeight+b));c=w.outerWidth();m[0].style.width=K(c);k.width=K(c);d=w.height()>g.clientHeight||"scroll"==n.css("overflow-y");e="padding"+(aa.bScrollbarLeft?"Left":"Right");k[e]=d?b+"px":"0px";G&&(v[0].style.width=K(c),t[0].style.width=K(c),t[0].style[e]=d?b+"px":"0px");w.children("colgroup").insertBefore(w.children("thead"));n.trigger("scroll");!a.bSorted&&!a.bFiltered||a._drawHold||(g.scrollTop=0)}}function ca(a,b,c){for(var d=0,e=0,h=b.length,f,g;e").appendTo(g.find("tbody"));g.find("thead, tfoot").remove();g.append(l(a.nTHead).clone()).append(l(a.nTFoot).clone());g.find("tfoot th, tfoot td").css("width","");m=Na(a,g.find("thead")[0]);for(v=0;v").css({width:w.sWidthOrig, -margin:0,padding:0,border:0,height:1}));if(a.aoData.length)for(v=0;v").css(h||e?{position:"absolute",top:0,left:0,height:1,right:0,overflow:"hidden"}:{}).append(g).appendTo(p);h&&f?g.width(f):h?(g.css("width","auto"),g.removeAttr("width"),g.width()").css("width",K(a)).appendTo(b||A.body);b=a[0].offsetWidth;a.remove();return b}function $b(a,b){var c=ac(a,b);if(0>c)return null;var d=a.aoData[c];return d.nTr?d.anCells[b]: -l("").html(T(a,c,b,"display"))[0]}function ac(a,b){for(var c,d=-1,e=-1,h=0,f=a.aoData.length;hd&&(d=c.length,e=h);return e}function K(a){return null===a?"0px":"number"==typeof a?0>a?"0px":a+"px":a.match(/\d$/)?a+"px":a}function pa(a){var b=[],c=a.aoColumns;var d=a.aaSortingFixed;var e=l.isPlainObject(d);var h=[];var f=function(n){n.length&&!Array.isArray(n[0])?h.push(n):l.merge(h,n)};Array.isArray(d)&&f(d); -e&&d.pre&&f(d.pre);f(a.aaSorting);e&&d.post&&f(d.post);for(a=0;aG?1:0;if(0!==C)return"asc"===r.dir?C:-C}C=c[n];G=c[p];return CG?1:0}):f.sort(function(n,p){var t,v=g.length,x=e[n]._aSortData,w=e[p]._aSortData;for(t=0;tG?1:0})}a.bSorted=!0}function cc(a){var b=a.aoColumns,c=pa(a);a=a.oLanguage.oAria;for(var d=0,e=b.length;d/g,"");var k=h.nTh;k.removeAttribute("aria-sort");h.bSortable&&(0e?e+1:3))}e=0;for(h=d.length;ee?e+1:3))}a.aLastSort=d}function bc(a,b){var c=a.aoColumns[b],d=u.ext.order[c.sSortDataType],e;d&&(e=d.call(a.oInstance,a,b,va(a,b)));for(var h,f=u.ext.type.order[c.sType+"-pre"],g=0,k=a.aoData.length;g=e.length?[0, -m[1]]:m)}));b.search!==q&&l.extend(a.oPreviousSearch,Wb(b.search));if(b.columns){f=0;for(d=b.columns.length;f=c&&(b=c-d);b-=b%d;if(-1===d||0>b)b=0;a._iDisplayStart=b}function fb(a,b){a=a.renderer;var c=u.ext.renderer[b];return l.isPlainObject(a)&&a[b]?c[a[b]]||c._:"string"===typeof a?c[a]||c._:c._}function Q(a){return a.oFeatures.bServerSide?"ssp":a.ajax||a.sAjaxSource?"ajax":"dom"}function Da(a,b){var c=ec.numbers_length,d=Math.floor(c/2); -b<=c?a=ra(0,b):a<=d?(a=ra(0,c-2),a.push("ellipsis"),a.push(b-1)):(a>=b-1-d?a=ra(b-(c-2),b):(a=ra(a-d+2,a+d-1),a.push("ellipsis"),a.push(b-1)),a.splice(0,0,"ellipsis"),a.splice(0,0,0));a.DT_el="span";return a}function Wa(a){l.each({num:function(b){return Ta(b,a)},"num-fmt":function(b){return Ta(b,a,rb)},"html-num":function(b){return Ta(b,a,Ua)},"html-num-fmt":function(b){return Ta(b,a,Ua,rb)}},function(b,c){M.type.order[b+a+"-pre"]=c;b.match(/^html\-/)&&(M.type.search[b+a]=M.type.search.html)})}function fc(a){return function(){var b= -[Sa(this[u.ext.iApiIndex])].concat(Array.prototype.slice.call(arguments));return u.ext.internal[a].apply(this,b)}}var u=function(a,b){if(this instanceof u)return l(a).DataTable(b);b=a;this.$=function(f,g){return this.api(!0).$(f,g)};this._=function(f,g){return this.api(!0).rows(f,g).data()};this.api=function(f){return f?new B(Sa(this[M.iApiIndex])):new B(this)};this.fnAddData=function(f,g){var k=this.api(!0);f=Array.isArray(f)&&(Array.isArray(f[0])||l.isPlainObject(f[0]))?k.rows.add(f):k.row.add(f); -(g===q||g)&&k.draw();return f.flatten().toArray()};this.fnAdjustColumnSizing=function(f){var g=this.api(!0).columns.adjust(),k=g.settings()[0],m=k.oScroll;f===q||f?g.draw(!1):(""!==m.sX||""!==m.sY)&&Ha(k)};this.fnClearTable=function(f){var g=this.api(!0).clear();(f===q||f)&&g.draw()};this.fnClose=function(f){this.api(!0).row(f).child.hide()};this.fnDeleteRow=function(f,g,k){var m=this.api(!0);f=m.rows(f);var n=f.settings()[0],p=n.aoData[f[0][0]];f.remove();g&&g.call(this,n,p);(k===q||k)&&m.draw(); -return p};this.fnDestroy=function(f){this.api(!0).destroy(f)};this.fnDraw=function(f){this.api(!0).draw(f)};this.fnFilter=function(f,g,k,m,n,p){n=this.api(!0);null===g||g===q?n.search(f,k,m,p):n.column(g).search(f,k,m,p);n.draw()};this.fnGetData=function(f,g){var k=this.api(!0);if(f!==q){var m=f.nodeName?f.nodeName.toLowerCase():"";return g!==q||"td"==m||"th"==m?k.cell(f,g).data():k.row(f).data()||null}return k.data().toArray()};this.fnGetNodes=function(f){var g=this.api(!0);return f!==q?g.row(f).node(): -g.rows().nodes().flatten().toArray()};this.fnGetPosition=function(f){var g=this.api(!0),k=f.nodeName.toUpperCase();return"TR"==k?g.row(f).index():"TD"==k||"TH"==k?(f=g.cell(f).index(),[f.row,f.columnVisible,f.column]):null};this.fnIsOpen=function(f){return this.api(!0).row(f).child.isShown()};this.fnOpen=function(f,g,k){return this.api(!0).row(f).child(g,k).show().child()[0]};this.fnPageChange=function(f,g){f=this.api(!0).page(f);(g===q||g)&&f.draw(!1)};this.fnSetColumnVis=function(f,g,k){f=this.api(!0).column(f).visible(g); -(k===q||k)&&f.columns.adjust().draw()};this.fnSettings=function(){return Sa(this[M.iApiIndex])};this.fnSort=function(f){this.api(!0).order(f).draw()};this.fnSortListener=function(f,g,k){this.api(!0).order.listener(f,g,k)};this.fnUpdate=function(f,g,k,m,n){var p=this.api(!0);k===q||null===k?p.row(g).data(f):p.cell(g,k).data(f);(n===q||n)&&p.columns.adjust();(m===q||m)&&p.draw();return 0};this.fnVersionCheck=M.fnVersionCheck;var c=this,d=b===q,e=this.length;d&&(b={});this.oApi=this.internal=M.internal; -for(var h in u.ext.internal)h&&(this[h]=fc(h));this.each(function(){var f={},g=1").appendTo(t));r.nTHead=H[0];var ea=t.children("tbody");0===ea.length&&(ea=l("").insertAfter(H)); -r.nTBody=ea[0];H=t.children("tfoot");0===H.length&&0").appendTo(t));0===H.length||0===H.children().length?t.addClass(C.sNoFooter):0/g,uc=/^\d{2,4}[\.\/\-]\d{1,2}[\.\/\-]\d{1,2}([T ]{1}\d{1,2}[:\.]\d{2}([\.:]\d{2})?)?$/,vc=/(\/|\.|\*|\+|\?|\||\(|\)|\[|\]|\{|\}|\\|\$|\^|\-)/g,rb=/['\u00A0,$£€¥%\u2009\u202F\u20BD\u20a9\u20BArfkɃΞ]/gi,Z=function(a){return a&&!0!==a&&"-"!==a?!1:!0},hc=function(a){var b=parseInt(a,10);return!isNaN(b)&&isFinite(a)?b:null},ic=function(a,b){sb[b]||(sb[b]=new RegExp(ib(b),"g"));return"string"===typeof a&&"."!==b?a.replace(/\./g, -"").replace(sb[b],"."):a},tb=function(a,b,c){var d="string"===typeof a;if(Z(a))return!0;b&&d&&(a=ic(a,b));c&&d&&(a=a.replace(rb,""));return!isNaN(parseFloat(a))&&isFinite(a)},jc=function(a,b,c){return Z(a)?!0:Z(a)||"string"===typeof a?tb(a.replace(Ua,""),b,c)?!0:null:null},U=function(a,b,c){var d=[],e=0,h=a.length;if(c!==q)for(;ea.length)){var b=a.slice().sort();for(var c=b[0],d=1,e=b.length;d")[0],sc=Qa.textContent!==q,tc=/<.*?>/g,gb=u.util.throttle,nc=[],N=Array.prototype,wc=function(a){var b,c=u.settings,d=l.map(c,function(h,f){return h.nTable});if(a){if(a.nTable&&a.oApi)return[a];if(a.nodeName&&"table"===a.nodeName.toLowerCase()){var e=l.inArray(a,d);return-1!==e?[c[e]]:null}if(a&&"function"===typeof a.settings)return a.settings().toArray();"string"===typeof a?b=l(a):a instanceof l&&(b=a)}else return[];if(b)return b.map(function(h){e= -l.inArray(this,d);return-1!==e?c[e]:null}).toArray()};var B=function(a,b){if(!(this instanceof B))return new B(a,b);var c=[],d=function(f){(f=wc(f))&&c.push.apply(c,f)};if(Array.isArray(a))for(var e=0,h=a.length;ea?new B(b[a],this[a]):null},filter:function(a){var b=[];if(N.filter)b=N.filter.call(this,a,this);else for(var c=0,d=this.length;c").addClass(g),l("td",k).addClass(g).html(f)[0].colSpan= -oa(a),e.push(k[0]))};h(c,d);b._details&&b._details.detach();b._details=l(e);b._detailsShow&&b._details.insertAfter(b.nTr)},xb=function(a,b){var c=a.context;c.length&&(a=c[0].aoData[b!==q?b:a[0]])&&a._details&&(a._details.remove(),a._detailsShow=q,a._details=q,l(a.nTr).removeClass("dt-hasChild"),qa(c[0]))},qc=function(a,b){var c=a.context;if(c.length&&a.length){var d=c[0].aoData[a[0]];d._details&&((d._detailsShow=b)?(d._details.insertAfter(d.nTr),l(d.nTr).addClass("dt-hasChild")):(d._details.detach(), -l(d.nTr).removeClass("dt-hasChild")),F(c[0],null,"childRow",[b,a.row(a[0])]),zc(c[0]),qa(c[0]))}},zc=function(a){var b=new B(a),c=a.aoData;b.off("draw.dt.DT_details column-visibility.dt.DT_details destroy.dt.DT_details");0g){var n=l.map(d,function(p,t){return p.bVisible?t:null});return[n[n.length+g]]}return[ua(a,g)];case "name":return l.map(e,function(p,t){return p===m[1]?t:null});default:return[]}if(f.nodeName&&f._DT_CellIndex)return[f._DT_CellIndex.column]; -g=l(h).filter(f).map(function(){return l.inArray(this,h)}).toArray();if(g.length||!f.nodeName)return g;g=l(f).closest("*[data-dt-column]");return g.length?[g.data("dt-column")]:[]},a,c)};y("columns()",function(a,b){a===q?a="":l.isPlainObject(a)&&(b=a,a="");b=vb(b);var c=this.iterator("table",function(d){return Bc(d,a,b)},1);c.selector.cols=a;c.selector.opts=b;return c});J("columns().header()","column().header()",function(a,b){return this.iterator("column",function(c,d){return c.aoColumns[d].nTh}, -1)});J("columns().footer()","column().footer()",function(a,b){return this.iterator("column",function(c,d){return c.aoColumns[d].nTf},1)});J("columns().data()","column().data()",function(){return this.iterator("column-rows",rc,1)});J("columns().dataSrc()","column().dataSrc()",function(){return this.iterator("column",function(a,b){return a.aoColumns[b].mData},1)});J("columns().cache()","column().cache()",function(a){return this.iterator("column-rows",function(b,c,d,e,h){return Ea(b.aoData,h,"search"=== -a?"_aFilterData":"_aSortData",c)},1)});J("columns().nodes()","column().nodes()",function(){return this.iterator("column-rows",function(a,b,c,d,e){return Ea(a.aoData,e,"anCells",b)},1)});J("columns().visible()","column().visible()",function(a,b){var c=this,d=this.iterator("column",function(e,h){if(a===q)return e.aoColumns[h].bVisible;var f=e.aoColumns,g=f[h],k=e.aoData,m;if(a!==q&&g.bVisible!==a){if(a){var n=l.inArray(!0,U(f,"bVisible"),h+1);f=0;for(m=k.length;fd;return!0};u.isDataTable=u.fnIsDataTable=function(a){var b= -l(a).get(0),c=!1;if(a instanceof u.Api)return!0;l.each(u.settings,function(d,e){d=e.nScrollHead?l("table",e.nScrollHead)[0]:null;var h=e.nScrollFoot?l("table",e.nScrollFoot)[0]:null;if(e.nTable===b||d===b||h===b)c=!0});return c};u.tables=u.fnTables=function(a){var b=!1;l.isPlainObject(a)&&(b=a.api,a=a.visible);var c=l.map(u.settings,function(d){if(!a||a&&l(d.nTable).is(":visible"))return d.nTable});return b?new B(c):c};u.camelToHungarian=P;y("$()",function(a,b){b=this.rows(b).nodes();b=l(b);return l([].concat(b.filter(a).toArray(), -b.find(a).toArray()))});l.each(["on","one","off"],function(a,b){y(b+"()",function(){var c=Array.prototype.slice.call(arguments);c[0]=l.map(c[0].split(/\s/),function(e){return e.match(/\.dt\b/)?e:e+".dt"}).join(" ");var d=l(this.tables().nodes());d[b].apply(d,c);return this})});y("clear()",function(){return this.iterator("table",function(a){Ka(a)})});y("settings()",function(){return new B(this.context,this.context)});y("init()",function(){var a=this.context;return a.length?a[0].oInit:null});y("data()", -function(){return this.iterator("table",function(a){return U(a.aoData,"_aData")}).flatten()});y("destroy()",function(a){a=a||!1;return this.iterator("table",function(b){var c=b.nTableWrapper.parentNode,d=b.oClasses,e=b.nTable,h=b.nTBody,f=b.nTHead,g=b.nTFoot,k=l(e);h=l(h);var m=l(b.nTableWrapper),n=l.map(b.aoData,function(t){return t.nTr}),p;b.bDestroying=!0;F(b,"aoDestroyCallback","destroy",[b]);a||(new B(b)).columns().visible(!0);m.off(".DT").find(":not(tbody *)").off(".DT");l(z).off(".DT-"+b.sInstance); -e!=f.parentNode&&(k.children("thead").detach(),k.append(f));g&&e!=g.parentNode&&(k.children("tfoot").detach(),k.append(g));b.aaSorting=[];b.aaSortingFixed=[];Ra(b);l(n).removeClass(b.asStripeClasses.join(" "));l("th, td",f).removeClass(d.sSortable+" "+d.sSortableAsc+" "+d.sSortableDesc+" "+d.sSortableNone);h.children().detach();h.append(n);f=a?"remove":"detach";k[f]();m[f]();!a&&c&&(c.insertBefore(e,b.nTableReinsertBefore),k.css("width",b.sDestroyWidth).removeClass(d.sTable),(p=b.asDestroyStripes.length)&& -h.children().each(function(t){l(this).addClass(b.asDestroyStripes[t%p])}));c=l.inArray(b,u.settings);-1!==c&&u.settings.splice(c,1)})});l.each(["column","row","cell"],function(a,b){y(b+"s().every()",function(c){var d=this.selector.opts,e=this;return this.iterator(b,function(h,f,g,k,m){c.call(e[b](f,"cell"===b?g:d,"cell"===b?d:q),f,g,k,m)})})});y("i18n()",function(a,b,c){var d=this.context[0];a=na(a)(d.oLanguage);a===q&&(a=b);c!==q&&l.isPlainObject(a)&&(a=a[c]!==q?a[c]:a._);return a.replace("%d",c)}); -u.version="1.11.3";u.settings=[];u.models={};u.models.oSearch={bCaseInsensitive:!0,sSearch:"",bRegex:!1,bSmart:!0,"return":!1};u.models.oRow={nTr:null,anCells:null,_aData:[],_aSortData:null,_aFilterData:null,_sFilterRow:null,_sRowStripe:"",src:null,idx:-1};u.models.oColumn={idx:null,aDataSort:null,asSorting:null,bSearchable:null,bSortable:null,bVisible:null,_sManualType:null,_bAttrSrc:!1,fnCreatedCell:null,fnGetData:null,fnSetData:null,mData:null,mRender:null,nTh:null,nTf:null,sClass:null,sContentPadding:null, -sDefaultContent:null,sName:null,sSortDataType:"std",sSortingClass:null,sSortingClassJUI:null,sTitle:null,sType:null,sWidth:null,sWidthOrig:null};u.defaults={aaData:null,aaSorting:[[0,"asc"]],aaSortingFixed:[],ajax:null,aLengthMenu:[10,25,50,100],aoColumns:null,aoColumnDefs:null,aoSearchCols:[],asStripeClasses:null,bAutoWidth:!0,bDeferRender:!1,bDestroy:!1,bFilter:!0,bInfo:!0,bLengthChange:!0,bPaginate:!0,bProcessing:!1,bRetrieve:!1,bScrollCollapse:!1,bServerSide:!1,bSort:!0,bSortMulti:!0,bSortCellsTop:!1, -bSortClasses:!0,bStateSave:!1,fnCreatedRow:null,fnDrawCallback:null,fnFooterCallback:null,fnFormatNumber:function(a){return a.toString().replace(/\B(?=(\d{3})+(?!\d))/g,this.oLanguage.sThousands)},fnHeaderCallback:null,fnInfoCallback:null,fnInitComplete:null,fnPreDrawCallback:null,fnRowCallback:null,fnServerData:null,fnServerParams:null,fnStateLoadCallback:function(a){try{return JSON.parse((-1===a.iStateDuration?sessionStorage:localStorage).getItem("DataTables_"+a.sInstance+"_"+location.pathname))}catch(b){return{}}}, -fnStateLoadParams:null,fnStateLoaded:null,fnStateSaveCallback:function(a,b){try{(-1===a.iStateDuration?sessionStorage:localStorage).setItem("DataTables_"+a.sInstance+"_"+location.pathname,JSON.stringify(b))}catch(c){}},fnStateSaveParams:null,iStateDuration:7200,iDeferLoading:null,iDisplayLength:10,iDisplayStart:0,iTabIndex:0,oClasses:{},oLanguage:{oAria:{sSortAscending:": activate to sort column ascending",sSortDescending:": activate to sort column descending"},oPaginate:{sFirst:"First",sLast:"Last", -sNext:"Next",sPrevious:"Previous"},sEmptyTable:"No data available in table",sInfo:"Showing _START_ to _END_ of _TOTAL_ entries",sInfoEmpty:"Showing 0 to 0 of 0 entries",sInfoFiltered:"(filtered from _MAX_ total entries)",sInfoPostFix:"",sDecimal:"",sThousands:",",sLengthMenu:"Show _MENU_ entries",sLoadingRecords:"Loading...",sProcessing:"Processing...",sSearch:"Search:",sSearchPlaceholder:"",sUrl:"",sZeroRecords:"No matching records found"},oSearch:l.extend({},u.models.oSearch),sAjaxDataProp:"data", -sAjaxSource:null,sDom:"lfrtip",searchDelay:null,sPaginationType:"simple_numbers",sScrollX:"",sScrollXInner:"",sScrollY:"",sServerMethod:"GET",renderer:null,rowId:"DT_RowId"};E(u.defaults);u.defaults.column={aDataSort:null,iDataSort:-1,asSorting:["asc","desc"],bSearchable:!0,bSortable:!0,bVisible:!0,fnCreatedCell:null,mData:null,mRender:null,sCellType:"td",sClass:"",sContentPadding:"",sDefaultContent:null,sName:"",sSortDataType:"std",sTitle:null,sType:null,sWidth:null};E(u.defaults.column);u.models.oSettings= -{oFeatures:{bAutoWidth:null,bDeferRender:null,bFilter:null,bInfo:null,bLengthChange:null,bPaginate:null,bProcessing:null,bServerSide:null,bSort:null,bSortMulti:null,bSortClasses:null,bStateSave:null},oScroll:{bCollapse:null,iBarWidth:0,sX:null,sXInner:null,sY:null},oLanguage:{fnInfoCallback:null},oBrowser:{bScrollOversize:!1,bScrollbarLeft:!1,bBounding:!1,barWidth:0},ajax:null,aanFeatures:[],aoData:[],aiDisplay:[],aiDisplayMaster:[],aIds:{},aoColumns:[],aoHeader:[],aoFooter:[],oPreviousSearch:{}, -aoPreSearchCols:[],aaSorting:null,aaSortingFixed:[],asStripeClasses:null,asDestroyStripes:[],sDestroyWidth:0,aoRowCallback:[],aoHeaderCallback:[],aoFooterCallback:[],aoDrawCallback:[],aoRowCreatedCallback:[],aoPreDrawCallback:[],aoInitComplete:[],aoStateSaveParams:[],aoStateLoadParams:[],aoStateLoaded:[],sTableId:"",nTable:null,nTHead:null,nTFoot:null,nTBody:null,nTableWrapper:null,bDeferLoading:!1,bInitialised:!1,aoOpenRows:[],sDom:null,searchDelay:null,sPaginationType:"two_button",iStateDuration:0, -aoStateSave:[],aoStateLoad:[],oSavedState:null,oLoadedState:null,sAjaxSource:null,sAjaxDataProp:null,jqXHR:null,json:q,oAjaxData:q,fnServerData:null,aoServerParams:[],sServerMethod:null,fnFormatNumber:null,aLengthMenu:null,iDraw:0,bDrawing:!1,iDrawError:-1,_iDisplayLength:10,_iDisplayStart:0,_iRecordsTotal:0,_iRecordsDisplay:0,oClasses:{},bFiltered:!1,bSorted:!1,bSortCellsTop:null,oInit:null,aoDestroyCallback:[],fnRecordsTotal:function(){return"ssp"==Q(this)?1*this._iRecordsTotal:this.aiDisplayMaster.length}, -fnRecordsDisplay:function(){return"ssp"==Q(this)?1*this._iRecordsDisplay:this.aiDisplay.length},fnDisplayEnd:function(){var a=this._iDisplayLength,b=this._iDisplayStart,c=b+a,d=this.aiDisplay.length,e=this.oFeatures,h=e.bPaginate;return e.bServerSide?!1===h||-1===a?b+d:Math.min(b+a,this._iRecordsDisplay):!h||c>d||-1===a?d:c},oInstance:null,sInstance:null,iTabIndex:0,nScrollHead:null,nScrollFoot:null,aLastSort:[],oPlugins:{},rowIdFn:null,rowId:null};u.ext=M={buttons:{},classes:{},builder:"-source-", -errMode:"alert",feature:[],search:[],selector:{cell:[],column:[],row:[]},internal:{},legacy:{ajax:null},pager:{},renderer:{pageButton:{},header:{}},order:{},type:{detect:[],search:{},order:{}},_unique:0,fnVersionCheck:u.fnVersionCheck,iApiIndex:0,oJUIClasses:{},sVersion:u.version};l.extend(M,{afnFiltering:M.search,aTypes:M.type.detect,ofnSearch:M.type.search,oSort:M.type.order,afnSortData:M.order,aoFeatures:M.feature,oApi:M.internal,oStdClasses:M.classes,oPagination:M.pager});l.extend(u.ext.classes, -{sTable:"dataTable",sNoFooter:"no-footer",sPageButton:"paginate_button",sPageButtonActive:"current",sPageButtonDisabled:"disabled",sStripeOdd:"odd",sStripeEven:"even",sRowEmpty:"dataTables_empty",sWrapper:"dataTables_wrapper",sFilter:"dataTables_filter",sInfo:"dataTables_info",sPaging:"dataTables_paginate paging_",sLength:"dataTables_length",sProcessing:"dataTables_processing",sSortAsc:"sorting_asc",sSortDesc:"sorting_desc",sSortable:"sorting",sSortableAsc:"sorting_desc_disabled",sSortableDesc:"sorting_asc_disabled", -sSortableNone:"sorting_disabled",sSortColumn:"sorting_",sFilterInput:"",sLengthSelect:"",sScrollWrapper:"dataTables_scroll",sScrollHead:"dataTables_scrollHead",sScrollHeadInner:"dataTables_scrollHeadInner",sScrollBody:"dataTables_scrollBody",sScrollFoot:"dataTables_scrollFoot",sScrollFootInner:"dataTables_scrollFootInner",sHeaderTH:"",sFooterTH:"",sSortJUIAsc:"",sSortJUIDesc:"",sSortJUI:"",sSortJUIAscAllowed:"",sSortJUIDescAllowed:"",sSortJUIWrapper:"",sSortIcon:"",sJUIHeader:"",sJUIFooter:""});var ec= -u.ext.pager;l.extend(ec,{simple:function(a,b){return["previous","next"]},full:function(a,b){return["first","previous","next","last"]},numbers:function(a,b){return[Da(a,b)]},simple_numbers:function(a,b){return["previous",Da(a,b),"next"]},full_numbers:function(a,b){return["first","previous",Da(a,b),"next","last"]},first_last_numbers:function(a,b){return["first",Da(a,b),"last"]},_numbers:Da,numbers_length:7});l.extend(!0,u.ext.renderer,{pageButton:{_:function(a,b,c,d,e,h){var f=a.oClasses,g=a.oLanguage.oPaginate, -k=a.oLanguage.oAria.paginate||{},m,n,p=0,t=function(x,w){var r,C=f.sPageButtonDisabled,G=function(I){lb(a,I.data.action,!0)};var aa=0;for(r=w.length;aa").appendTo(x);t(O,L)}else{m=null;n=L;O=a.iTabIndex;switch(L){case "ellipsis":x.append('');break;case "first":m=g.sFirst;0===e&&(O=-1,n+=" "+C);break;case "previous":m=g.sPrevious;0===e&&(O=-1,n+=" "+C);break;case "next":m=g.sNext;if(0=== -h||e===h-1)O=-1,n+=" "+C;break;case "last":m=g.sLast;if(0===h||e===h-1)O=-1,n+=" "+C;break;default:m=a.fnFormatNumber(L+1),n=e===L?f.sPageButtonActive:""}null!==m&&(O=l("",{"class":f.sPageButton+" "+n,"aria-controls":a.sTableId,"aria-label":k[L],"data-dt-idx":p,tabindex:O,id:0===c&&"string"===typeof L?a.sTableId+"_"+L:null}).html(m).appendTo(x),ob(O,{action:L},G),p++)}}};try{var v=l(b).find(A.activeElement).data("dt-idx")}catch(x){}t(l(b).empty(),d);v!==q&&l(b).find("[data-dt-idx="+v+"]").trigger("focus")}}}); -l.extend(u.ext.type.detect,[function(a,b){b=b.oLanguage.sDecimal;return tb(a,b)?"num"+b:null},function(a,b){if(a&&!(a instanceof Date)&&!uc.test(a))return null;b=Date.parse(a);return null!==b&&!isNaN(b)||Z(a)?"date":null},function(a,b){b=b.oLanguage.sDecimal;return tb(a,b,!0)?"num-fmt"+b:null},function(a,b){b=b.oLanguage.sDecimal;return jc(a,b)?"html-num"+b:null},function(a,b){b=b.oLanguage.sDecimal;return jc(a,b,!0)?"html-num-fmt"+b:null},function(a,b){return Z(a)||"string"===typeof a&&-1!==a.indexOf("<")? -"html":null}]);l.extend(u.ext.type.search,{html:function(a){return Z(a)?a:"string"===typeof a?a.replace(gc," ").replace(Ua,""):""},string:function(a){return Z(a)?a:"string"===typeof a?a.replace(gc," "):a}});var Ta=function(a,b,c,d){if(0!==a&&(!a||"-"===a))return-Infinity;b&&(a=ic(a,b));a.replace&&(c&&(a=a.replace(c,"")),d&&(a=a.replace(d,"")));return 1*a};l.extend(M.type.order,{"date-pre":function(a){a=Date.parse(a);return isNaN(a)?-Infinity:a},"html-pre":function(a){return Z(a)?"":a.replace?a.replace(/<.*?>/g, -"").toLowerCase():a+""},"string-pre":function(a){return Z(a)?"":"string"===typeof a?a.toLowerCase():a.toString?a.toString():""},"string-asc":function(a,b){return ab?1:0},"string-desc":function(a,b){return ab?-1:0}});Wa("");l.extend(!0,u.ext.renderer,{header:{_:function(a,b,c,d){l(a.nTable).on("order.dt.DT",function(e,h,f,g){a===h&&(e=c.idx,b.removeClass(d.sSortAsc+" "+d.sSortDesc).addClass("asc"==g[e]?d.sSortAsc:"desc"==g[e]?d.sSortDesc:c.sSortingClass))})},jqueryui:function(a,b,c, -d){l("
").addClass(d.sSortJUIWrapper).append(b.contents()).append(l("").addClass(d.sSortIcon+" "+c.sSortingClassJUI)).appendTo(b);l(a.nTable).on("order.dt.DT",function(e,h,f,g){a===h&&(e=c.idx,b.removeClass(d.sSortAsc+" "+d.sSortDesc).addClass("asc"==g[e]?d.sSortAsc:"desc"==g[e]?d.sSortDesc:c.sSortingClass),b.find("span."+d.sSortIcon).removeClass(d.sSortJUIAsc+" "+d.sSortJUIDesc+" "+d.sSortJUI+" "+d.sSortJUIAscAllowed+" "+d.sSortJUIDescAllowed).addClass("asc"==g[e]?d.sSortJUIAsc:"desc"== -g[e]?d.sSortJUIDesc:c.sSortingClassJUI))})}}});var yb=function(a){Array.isArray(a)&&(a=a.join(","));return"string"===typeof a?a.replace(/&/g,"&").replace(//g,">").replace(/"/g,"""):a};u.render={number:function(a,b,c,d,e){return{display:function(h){if("number"!==typeof h&&"string"!==typeof h)return h;var f=0>h?"-":"",g=parseFloat(h);if(isNaN(g))return yb(h);g=g.toFixed(c);h=Math.abs(g);g=parseInt(h,10);h=c?b+(h-g).toFixed(c).substring(2):"";0===g&&0===parseFloat(h)&& -(f="");return f+(d||"")+g.toString().replace(/\B(?=(\d{3})+(?!\d))/g,a)+h+(e||"")}}},text:function(){return{display:yb,filter:yb}}};l.extend(u.ext.internal,{_fnExternApiFunc:fc,_fnBuildAjax:Oa,_fnAjaxUpdate:Gb,_fnAjaxParameters:Pb,_fnAjaxUpdateDraw:Qb,_fnAjaxDataSrc:Aa,_fnAddColumn:Xa,_fnColumnOptions:Ga,_fnAdjustColumnSizing:ta,_fnVisibleToColumnIndex:ua,_fnColumnIndexToVisible:va,_fnVisbleColumns:oa,_fnGetColumns:Ia,_fnColumnTypes:Za,_fnApplyColumnDefs:Db,_fnHungarianMap:E,_fnCamelToHungarian:P, -_fnLanguageCompat:ma,_fnBrowserDetect:Bb,_fnAddData:ia,_fnAddTr:Ja,_fnNodeToDataIndex:function(a,b){return b._DT_RowIndex!==q?b._DT_RowIndex:null},_fnNodeToColumnIndex:function(a,b,c){return l.inArray(c,a.aoData[b].anCells)},_fnGetCellData:T,_fnSetCellData:Eb,_fnSplitObjNotation:bb,_fnGetObjectDataFn:na,_fnSetObjectDataFn:ha,_fnGetDataMaster:cb,_fnClearTable:Ka,_fnDeleteIndex:La,_fnInvalidate:wa,_fnGetRowElements:ab,_fnCreateTr:$a,_fnBuildHead:Fb,_fnDrawHead:ya,_fnDraw:ja,_fnReDraw:ka,_fnAddOptionsHtml:Ib, -_fnDetectHeader:xa,_fnGetUniqueThs:Na,_fnFeatureHtmlFilter:Kb,_fnFilterComplete:za,_fnFilterCustom:Tb,_fnFilterColumn:Sb,_fnFilter:Rb,_fnFilterCreateSearch:hb,_fnEscapeRegex:ib,_fnFilterData:Ub,_fnFeatureHtmlInfo:Nb,_fnUpdateInfo:Xb,_fnInfoMacros:Yb,_fnInitialise:Ba,_fnInitComplete:Pa,_fnLengthChange:jb,_fnFeatureHtmlLength:Jb,_fnFeatureHtmlPaginate:Ob,_fnPageChange:lb,_fnFeatureHtmlProcessing:Lb,_fnProcessingDisplay:V,_fnFeatureHtmlTable:Mb,_fnScrollDraw:Ha,_fnApplyToChildren:ca,_fnCalculateColumnWidths:Ya, -_fnThrottle:gb,_fnConvertToWidth:Zb,_fnGetWidestNode:$b,_fnGetMaxLenString:ac,_fnStringToCss:K,_fnSortFlatten:pa,_fnSort:Hb,_fnSortAria:cc,_fnSortListener:nb,_fnSortAttachListener:eb,_fnSortingClasses:Ra,_fnSortData:bc,_fnSaveState:qa,_fnLoadState:dc,_fnImplementState:pb,_fnSettingsFromNode:Sa,_fnLog:da,_fnMap:X,_fnBindAction:ob,_fnCallbackReg:R,_fnCallbackFire:F,_fnLengthOverflow:kb,_fnRenderer:fb,_fnDataSource:Q,_fnRowAttributes:db,_fnExtend:qb,_fnCalculateEnd:function(){}});l.fn.dataTable=u;u.$= -l;l.fn.dataTableSettings=u.settings;l.fn.dataTableExt=u.ext;l.fn.DataTable=function(a){return l(this).dataTable(a).api()};l.each(u,function(a,b){l.fn.DataTable[a]=b});return u}); diff --git a/master/assets/dt-ext-buttons-1.11.3/css/buttons.dataTables.min.css b/master/assets/dt-ext-buttons-1.11.3/css/buttons.dataTables.min.css deleted file mode 100644 index a3d28f85a..000000000 --- a/master/assets/dt-ext-buttons-1.11.3/css/buttons.dataTables.min.css +++ /dev/null @@ -1 +0,0 @@ -@keyframes dtb-spinner{100%{transform:rotate(360deg)}}@-o-keyframes dtb-spinner{100%{-o-transform:rotate(360deg);transform:rotate(360deg)}}@-ms-keyframes dtb-spinner{100%{-ms-transform:rotate(360deg);transform:rotate(360deg)}}@-webkit-keyframes dtb-spinner{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@-moz-keyframes dtb-spinner{100%{-moz-transform:rotate(360deg);transform:rotate(360deg)}}div.dt-button-info{position:fixed;top:50%;left:50%;width:400px;margin-top:-100px;margin-left:-200px;background-color:white;border:2px solid #111;box-shadow:3px 3px 8px rgba(0, 0, 0, 0.3);border-radius:3px;text-align:center;z-index:21}div.dt-button-info h2{padding:.5em;margin:0;font-weight:normal;border-bottom:1px solid #ddd;background-color:#f3f3f3}div.dt-button-info>div{padding:1em}button.dtb-hide-drop{display:none !important}div.dt-button-collection-title{text-align:center;padding:.3em 0 .5em;font-size:.9em}div.dt-button-collection-title:empty{display:none}button.dt-button,div.dt-button,a.dt-button,input.dt-button{position:relative;display:inline-block;box-sizing:border-box;margin-right:.333em;margin-bottom:.333em;padding:.5em 1em;border:1px solid rgba(0, 0, 0, 0.3);border-radius:2px;cursor:pointer;font-size:.88em;line-height:1.6em;color:black;white-space:nowrap;overflow:hidden;background-color:rgba(0, 0, 0, 0.1);background:-webkit-linear-gradient(top, rgba(230, 230, 230, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%);background:-moz-linear-gradient(top, rgba(230, 230, 230, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%);background:-ms-linear-gradient(top, rgba(230, 230, 230, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%);background:-o-linear-gradient(top, rgba(230, 230, 230, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%);background:linear-gradient(to bottom, rgba(230, 230, 230, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr="rgba(230, 230, 230, 0.1)", EndColorStr="rgba(0, 0, 0, 0.1)");-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;text-decoration:none;outline:none;text-overflow:ellipsis}button.dt-button.disabled,div.dt-button.disabled,a.dt-button.disabled,input.dt-button.disabled{cursor:default;opacity:.4}button.dt-button:active:not(.disabled),button.dt-button.active:not(.disabled),div.dt-button:active:not(.disabled),div.dt-button.active:not(.disabled),a.dt-button:active:not(.disabled),a.dt-button.active:not(.disabled),input.dt-button:active:not(.disabled),input.dt-button.active:not(.disabled){background-color:rgba(0, 0, 0, 0.1);background:-webkit-linear-gradient(top, rgba(179, 179, 179, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%);background:-moz-linear-gradient(top, rgba(179, 179, 179, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%);background:-ms-linear-gradient(top, rgba(179, 179, 179, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%);background:-o-linear-gradient(top, rgba(179, 179, 179, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%);background:linear-gradient(to bottom, rgba(179, 179, 179, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr="rgba(179, 179, 179, 0.1)", EndColorStr="rgba(0, 0, 0, 0.1)");box-shadow:inset 1px 1px 3px #999}button.dt-button:active:not(.disabled):hover:not(.disabled),button.dt-button.active:not(.disabled):hover:not(.disabled),div.dt-button:active:not(.disabled):hover:not(.disabled),div.dt-button.active:not(.disabled):hover:not(.disabled),a.dt-button:active:not(.disabled):hover:not(.disabled),a.dt-button.active:not(.disabled):hover:not(.disabled),input.dt-button:active:not(.disabled):hover:not(.disabled),input.dt-button.active:not(.disabled):hover:not(.disabled){box-shadow:inset 1px 1px 3px #999;background-color:rgba(0, 0, 0, 0.1);background:-webkit-linear-gradient(top, rgba(128, 128, 128, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%);background:-moz-linear-gradient(top, rgba(128, 128, 128, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%);background:-ms-linear-gradient(top, rgba(128, 128, 128, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%);background:-o-linear-gradient(top, rgba(128, 128, 128, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%);background:linear-gradient(to bottom, rgba(128, 128, 128, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr="rgba(128, 128, 128, 0.1)", EndColorStr="rgba(0, 0, 0, 0.1)")}button.dt-button:hover,div.dt-button:hover,a.dt-button:hover,input.dt-button:hover{text-decoration:none}button.dt-button:hover:not(.disabled),div.dt-button:hover:not(.disabled),a.dt-button:hover:not(.disabled),input.dt-button:hover:not(.disabled){border:1px solid #666;background-color:rgba(0, 0, 0, 0.1);background:-webkit-linear-gradient(top, rgba(153, 153, 153, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%);background:-moz-linear-gradient(top, rgba(153, 153, 153, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%);background:-ms-linear-gradient(top, rgba(153, 153, 153, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%);background:-o-linear-gradient(top, rgba(153, 153, 153, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%);background:linear-gradient(to bottom, rgba(153, 153, 153, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr="rgba(153, 153, 153, 0.1)", EndColorStr="rgba(0, 0, 0, 0.1)")}button.dt-button:focus:not(.disabled),div.dt-button:focus:not(.disabled),a.dt-button:focus:not(.disabled),input.dt-button:focus:not(.disabled){border:1px solid #426c9e;text-shadow:0 1px 0 #c4def1;outline:none;background-color:#79ace9;background:-webkit-linear-gradient(top, #d1e2f7 0%, #79ace9 100%);background:-moz-linear-gradient(top, #d1e2f7 0%, #79ace9 100%);background:-ms-linear-gradient(top, #d1e2f7 0%, #79ace9 100%);background:-o-linear-gradient(top, #d1e2f7 0%, #79ace9 100%);background:linear-gradient(to bottom, #d1e2f7 0%, #79ace9 100%);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr="#d1e2f7", EndColorStr="#79ace9")}button.dt-button span.dt-down-arrow,div.dt-button span.dt-down-arrow,a.dt-button span.dt-down-arrow,input.dt-button span.dt-down-arrow{position:relative;top:-2px;color:rgba(70, 70, 70, 0.75);font-size:8px;padding-left:10px}.dt-button embed{outline:none}div.dt-buttons{position:relative;float:left}div.dt-buttons.buttons-right{float:right}div.dataTables_layout_cell div.dt-buttons{float:none}div.dataTables_layout_cell div.dt-buttons.buttons-right{float:none}div.dt-button-collection{position:absolute;top:0;left:0;width:200px;margin-top:3px;padding:4px 4px 0 4px;border:1px solid #ccc;border:1px solid rgba(0, 0, 0, 0.4);background-color:white;overflow:hidden;z-index:2002;border-radius:5px;box-shadow:3px 3px 5px rgba(0, 0, 0, 0.3);box-sizing:border-box}div.dt-button-collection button.dt-button,div.dt-button-collection div.dt-button,div.dt-button-collection a.dt-button{position:relative;left:0;right:0;width:100%;display:block;float:none;margin-bottom:4px;margin-right:0}div.dt-button-collection button.dt-button:active:not(.disabled),div.dt-button-collection button.dt-button.active:not(.disabled),div.dt-button-collection div.dt-button:active:not(.disabled),div.dt-button-collection div.dt-button.active:not(.disabled),div.dt-button-collection a.dt-button:active:not(.disabled),div.dt-button-collection a.dt-button.active:not(.disabled){background-color:#dadada;background:-webkit-linear-gradient(top, #f0f0f0 0%, #dadada 100%);background:-moz-linear-gradient(top, #f0f0f0 0%, #dadada 100%);background:-ms-linear-gradient(top, #f0f0f0 0%, #dadada 100%);background:-o-linear-gradient(top, #f0f0f0 0%, #dadada 100%);background:linear-gradient(to bottom, #f0f0f0 0%, #dadada 100%);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr="#f0f0f0", EndColorStr="#dadada");box-shadow:inset 1px 1px 3px #666}div.dt-button-collection button.dt-button:first-child,div.dt-button-collection div.dt-button:first-child,div.dt-button-collection a.dt-button:first-child{border-top-left-radius:3px;border-top-right-radius:3px}div.dt-button-collection button.dt-button:last-child,div.dt-button-collection div.dt-button:last-child,div.dt-button-collection a.dt-button:last-child{border-bottom-left-radius:3px;border-bottom-right-radius:3px}div.dt-button-collection div.dt-btn-split-wrapper{display:flex;flex-direction:row;flex-wrap:wrap;justify-content:flex-start;align-content:flex-start;align-items:flex-start}div.dt-button-collection div.dt-btn-split-wrapper button.dt-button{margin-right:0px;display:inline-block;width:0;flex-grow:1;flex-shrink:0;flex-basis:50px}div.dt-button-collection div.dt-btn-split-wrapper button.dt-btn-split-drop{min-width:20px;margin-left:-1px;flex-grow:0;flex-shrink:0;flex-basis:0}div.dt-button-collection.fixed{position:fixed;top:50%;left:50%;margin-left:-75px;border-radius:0}div.dt-button-collection.fixed.two-column{margin-left:-200px}div.dt-button-collection.fixed.three-column{margin-left:-225px}div.dt-button-collection.fixed.four-column{margin-left:-300px}div.dt-button-collection>:last-child{display:block !important;-webkit-column-gap:8px;-moz-column-gap:8px;-ms-column-gap:8px;-o-column-gap:8px;column-gap:8px}div.dt-button-collection>:last-child>*{-webkit-column-break-inside:avoid;break-inside:avoid}div.dt-button-collection.two-column{width:400px}div.dt-button-collection.two-column>:last-child{padding-bottom:1px;-webkit-column-count:2;-moz-column-count:2;-ms-column-count:2;-o-column-count:2;column-count:2}div.dt-button-collection.three-column{width:450px}div.dt-button-collection.three-column>:last-child{padding-bottom:1px;-webkit-column-count:3;-moz-column-count:3;-ms-column-count:3;-o-column-count:3;column-count:3}div.dt-button-collection.four-column{width:600px}div.dt-button-collection.four-column>:last-child{padding-bottom:1px;-webkit-column-count:4;-moz-column-count:4;-ms-column-count:4;-o-column-count:4;column-count:4}div.dt-button-collection .dt-button{border-radius:0}div.dt-button-background{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0, 0, 0, 0.7);background:-ms-radial-gradient(center, ellipse farthest-corner, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%);background:-moz-radial-gradient(center, ellipse farthest-corner, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%);background:-o-radial-gradient(center, ellipse farthest-corner, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%);background:-webkit-gradient(radial, center center, 0, center center, 497, color-stop(0, rgba(0, 0, 0, 0.3)), color-stop(1, rgba(0, 0, 0, 0.7)));background:-webkit-radial-gradient(center, ellipse farthest-corner, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%);background:radial-gradient(ellipse farthest-corner at center, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%);z-index:2001}@media screen and (max-width: 640px){div.dt-buttons{float:none !important;text-align:center}}button.dt-button.processing,div.dt-button.processing,a.dt-button.processing{color:rgba(0, 0, 0, 0.2)}button.dt-button.processing:after,div.dt-button.processing:after,a.dt-button.processing:after{position:absolute;top:50%;left:50%;width:16px;height:16px;margin:-8px 0 0 -8px;box-sizing:border-box;display:block;content:" ";border:2px solid #282828;border-radius:50%;border-left-color:transparent;border-right-color:transparent;animation:dtb-spinner 1500ms infinite linear;-o-animation:dtb-spinner 1500ms infinite linear;-ms-animation:dtb-spinner 1500ms infinite linear;-webkit-animation:dtb-spinner 1500ms infinite linear;-moz-animation:dtb-spinner 1500ms infinite linear}button.dt-btn-split-drop{margin-left:calc(-1px - 0.333em);padding-left:.333em;padding-right:.333em;padding-bottom:calc(0.5em - 1px);border-radius:0px 1px 1px 0px;color:rgba(70, 70, 70, 0.9)}button.dt-btn-split-drop span.dt-btn-split-drop-arrow{font-size:10px}button.dt-btn-split-drop:hover{z-index:2}div.dt-btn-split-wrapper{display:inline-block}button.buttons-split{border-right:1px solid rgba(70, 70, 70, 0);border-radius:1px 0px 0px 1px}button.dt-btn-split-drop-button{background-color:white}button.dt-btn-split-drop-button:hover{background-color:white} diff --git a/master/assets/dt-ext-buttons-1.11.3/js/buttons.colVis.min.js b/master/assets/dt-ext-buttons-1.11.3/js/buttons.colVis.min.js deleted file mode 100644 index 16dc2088c..000000000 --- a/master/assets/dt-ext-buttons-1.11.3/js/buttons.colVis.min.js +++ /dev/null @@ -1,10 +0,0 @@ -/*! - Column visibility buttons for Buttons and DataTables. - 2016 SpryMedia Ltd - datatables.net/license -*/ -(function(h){"function"===typeof define&&define.amd?define(["jquery","datatables.net","datatables.net-buttons"],function(e){return h(e,window,document)}):"object"===typeof exports?module.exports=function(e,g){e||(e=window);g&&g.fn.dataTable||(g=require("datatables.net")(e,g).$);g.fn.dataTable.Buttons||require("datatables.net-buttons")(e,g);return h(g,e,e.document)}:h(jQuery,window,document)})(function(h,e,g,l){e=h.fn.dataTable;h.extend(e.ext.buttons,{colvis:function(b,a){var c=null,d={extend:"collection", -init:function(f,k){c=k},text:function(f){return f.i18n("buttons.colvis","Column visibility")},className:"buttons-colvis",buttons:[{extend:"columnsToggle",columns:a.columns,columnText:a.columnText}]};b.on("column-reorder.dt"+a.namespace,function(f,k,m){b.button(null,b.button(null,c).node()).collectionRebuild([{extend:"columnsToggle",columns:a.columns,columnText:a.columnText}])});return d},columnsToggle:function(b,a){return b.columns(a.columns).indexes().map(function(c){return{extend:"columnToggle", -columns:c,columnText:a.columnText}}).toArray()},columnToggle:function(b,a){return{extend:"columnVisibility",columns:a.columns,columnText:a.columnText}},columnsVisibility:function(b,a){return b.columns(a.columns).indexes().map(function(c){return{extend:"columnVisibility",columns:c,visibility:a.visibility,columnText:a.columnText}}).toArray()},columnVisibility:{columns:l,text:function(b,a,c){return c._columnText(b,c)},className:"buttons-columnVisibility",action:function(b,a,c,d){b=a.columns(d.columns); -a=b.visible();b.visible(d.visibility!==l?d.visibility:!(a.length&&a[0]))},init:function(b,a,c){var d=this;a.attr("data-cv-idx",c.columns);b.on("column-visibility.dt"+c.namespace,function(f,k){k.bDestroying||k.nTable!=b.settings()[0].nTable||d.active(b.column(c.columns).visible())}).on("column-reorder.dt"+c.namespace,function(f,k,m){c.destroying||1!==b.columns(c.columns).count()||(d.text(c._columnText(b,c)),d.active(b.column(c.columns).visible()))});this.active(b.column(c.columns).visible())},destroy:function(b, -a,c){b.off("column-visibility.dt"+c.namespace).off("column-reorder.dt"+c.namespace)},_columnText:function(b,a){var c=b.column(a.columns).index(),d=b.settings()[0].aoColumns[c].sTitle;d||(d=b.column(c).header().innerHTML);d=d.replace(/\n/g," ").replace(//gi," ").replace(//g,"").replace(//g,"").replace(/<.*?>/g,"").replace(/^\s+|\s+$/g,"");return a.columnText?a.columnText(b,c,d):d}},colvisRestore:{className:"buttons-colvisRestore",text:function(b){return b.i18n("buttons.colvisRestore", -"Restore visibility")},init:function(b,a,c){c._visOriginal=b.columns().indexes().map(function(d){return b.column(d).visible()}).toArray()},action:function(b,a,c,d){a.columns().every(function(f){f=a.colReorder&&a.colReorder.transpose?a.colReorder.transpose(f,"toOriginal"):f;this.visible(d._visOriginal[f])})}},colvisGroup:{className:"buttons-colvisGroup",action:function(b,a,c,d){a.columns(d.show).visible(!0,!1);a.columns(d.hide).visible(!1,!1);a.columns.adjust()},show:[],hide:[]}});return e.Buttons}); diff --git a/master/assets/dt-ext-buttons-1.11.3/js/buttons.html5.min.js b/master/assets/dt-ext-buttons-1.11.3/js/buttons.html5.min.js deleted file mode 100644 index f617f960e..000000000 --- a/master/assets/dt-ext-buttons-1.11.3/js/buttons.html5.min.js +++ /dev/null @@ -1,36 +0,0 @@ -/*! - HTML5 export buttons for Buttons and DataTables. - 2016 SpryMedia Ltd - datatables.net/license - - FileSaver.js (1.3.3) - MIT license - Copyright © 2016 Eli Grey - http://eligrey.com -*/ -(function(n){"function"===typeof define&&define.amd?define(["jquery","datatables.net","datatables.net-buttons"],function(u){return n(u,window,document)}):"object"===typeof exports?module.exports=function(u,x,E,F){u||(u=window);x&&x.fn.dataTable||(x=require("datatables.net")(u,x).$);x.fn.dataTable.Buttons||require("datatables.net-buttons")(u,x);return n(x,u,u.document,E,F)}:n(jQuery,window,document)})(function(n,u,x,E,F,B){function I(a){for(var c="";0<=a;)c=String.fromCharCode(a%26+65)+c,a=Math.floor(a/ -26)-1;return c}function O(a,c){J===B&&(J=-1===M.serializeToString((new u.DOMParser).parseFromString(P["xl/worksheets/sheet1.xml"],"text/xml")).indexOf("xmlns:r"));n.each(c,function(d,b){if(n.isPlainObject(b))d=a.folder(d),O(d,b);else{if(J){var m=b.childNodes[0],e,f=[];for(e=m.attributes.length-1;0<=e;e--){var g=m.attributes[e].nodeName;var p=m.attributes[e].nodeValue;-1!==g.indexOf(":")&&(f.push({name:g,value:p}),m.removeAttribute(g))}e=0;for(g=f.length;e'+b),b=b.replace(/_dt_b_namespace_token_/g,":"),b=b.replace(/xmlns:NS[\d]+="" NS[\d]+:/g,""));b=b.replace(/<([^<>]*?) xmlns=""([^<>]*?)>/g,"<$1 $2>");a.file(d,b)}})}function y(a,c,d){var b=a.createElement(c);d&&(d.attr&&n(b).attr(d.attr),d.children&&n.each(d.children,function(m,e){b.appendChild(e)}),null!==d.text&&d.text!== -B&&b.appendChild(a.createTextNode(d.text)));return b}function V(a,c){var d=a.header[c].length;a.footer&&a.footer[c].length>d&&(d=a.footer[c].length);for(var b=0,m=a.body.length;bd&&(d=e);if(401*a[1]?!0:!1};try{var M=new XMLSerializer,J}catch(a){}var P={"_rels/.rels":'', -"xl/_rels/workbook.xml.rels":'',"[Content_Types].xml":'', -"xl/workbook.xml":'', -"xl/worksheets/sheet1.xml":'',"xl/styles.xml":''}, -U=[{match:/^\-?\d+\.\d%$/,style:60,fmt:function(a){return a/100}},{match:/^\-?\d+\.?\d*%$/,style:56,fmt:function(a){return a/100}},{match:/^\-?\$[\d,]+.?\d*$/,style:57},{match:/^\-?£[\d,]+.?\d*$/,style:58},{match:/^\-?€[\d,]+.?\d*$/,style:59},{match:/^\-?\d+$/,style:65},{match:/^\-?\d+\.\d{2}$/,style:66},{match:/^\([\d,]+\)$/,style:61,fmt:function(a){return-1*a.replace(/[\(\)]/g,"")}},{match:/^\([\d,]+\.\d{2}\)$/,style:62,fmt:function(a){return-1*a.replace(/[\(\)]/g,"")}},{match:/^\-?[\d,]+$/,style:63}, -{match:/^\-?[\d,]+\.\d{2}$/,style:64},{match:/^[\d]{4}\-[\d]{2}\-[\d]{2}$/,style:67,fmt:function(a){return Math.round(25569+Date.parse(a)/864E5)}}];D.ext.buttons.copyHtml5={className:"buttons-copy buttons-html5",text:function(a){return a.i18n("buttons.copy","Copy")},action:function(a,c,d,b){this.processing(!0);var m=this;a=S(c,b);var e=c.buttons.exportInfo(b),f=R(b),g=a.str;d=n("
").css({height:1,width:1,overflow:"hidden",position:"fixed",top:0,left:0});e.title&&(g=e.title+f+f+g);e.messageTop&& -(g=e.messageTop+f+f+g);e.messageBottom&&(g=g+f+f+e.messageBottom);b.customize&&(g=b.customize(g,b,c));b=n("",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",y.option=!!ce.lastChild;var ge={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n",""]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function je(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Le(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var _t,zt=[],Ut=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=zt.pop()||S.expando+"_"+wt.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Ut.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Ut.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Ut,"$1"+r):!1!==e.jsonp&&(e.url+=(Tt.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,zt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((_t=E.implementation.createHTMLDocument("").body).innerHTML="
",2===_t.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=Fe(y.pixelPosition,function(e,t){if(t)return t=We(e,n),Pe.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0 - -(c) 2009-2014 Stuart Knightley -Dual licenced under the MIT license or GPLv3. See https://raw.github.com/Stuk/jszip/master/LICENSE.markdown. - -JSZip uses the library pako released under the MIT license : -https://github.com/nodeca/pako/blob/master/LICENSE -*/ -!function(a){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=a();else if("function"==typeof define&&define.amd)define([],a);else{var b;"undefined"!=typeof window?b=window:"undefined"!=typeof global?b=global:"undefined"!=typeof self&&(b=self),b.JSZip=a()}}(function(){return function a(b,c,d){function e(g,h){if(!c[g]){if(!b[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);throw new Error("Cannot find module '"+g+"'")}var j=c[g]={exports:{}};b[g][0].call(j.exports,function(a){var c=b[g][1][a];return e(c?c:a)},j,j.exports,a,b,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;g>2,g=(3&b)<<4|c>>4,h=(15&c)<<2|e>>6,i=63&e,isNaN(c)?h=i=64:isNaN(e)&&(i=64),j=j+d.charAt(f)+d.charAt(g)+d.charAt(h)+d.charAt(i);return j},c.decode=function(a){var b,c,e,f,g,h,i,j="",k=0;for(a=a.replace(/[^A-Za-z0-9\+\/\=]/g,"");k>4,c=(15&g)<<4|h>>2,e=(3&h)<<6|i,j+=String.fromCharCode(b),64!=h&&(j+=String.fromCharCode(c)),64!=i&&(j+=String.fromCharCode(e));return j}},{}],2:[function(a,b){"use strict";function c(){this.compressedSize=0,this.uncompressedSize=0,this.crc32=0,this.compressionMethod=null,this.compressedContent=null}c.prototype={getContent:function(){return null},getCompressedContent:function(){return null}},b.exports=c},{}],3:[function(a,b,c){"use strict";c.STORE={magic:"\x00\x00",compress:function(a){return a},uncompress:function(a){return a},compressInputType:null,uncompressInputType:null},c.DEFLATE=a("./flate")},{"./flate":8}],4:[function(a,b){"use strict";var c=a("./utils"),d=[0,1996959894,3993919788,2567524794,124634137,1886057615,3915621685,2657392035,249268274,2044508324,3772115230,2547177864,162941995,2125561021,3887607047,2428444049,498536548,1789927666,4089016648,2227061214,450548861,1843258603,4107580753,2211677639,325883990,1684777152,4251122042,2321926636,335633487,1661365465,4195302755,2366115317,997073096,1281953886,3579855332,2724688242,1006888145,1258607687,3524101629,2768942443,901097722,1119000684,3686517206,2898065728,853044451,1172266101,3705015759,2882616665,651767980,1373503546,3369554304,3218104598,565507253,1454621731,3485111705,3099436303,671266974,1594198024,3322730930,2970347812,795835527,1483230225,3244367275,3060149565,1994146192,31158534,2563907772,4023717930,1907459465,112637215,2680153253,3904427059,2013776290,251722036,2517215374,3775830040,2137656763,141376813,2439277719,3865271297,1802195444,476864866,2238001368,4066508878,1812370925,453092731,2181625025,4111451223,1706088902,314042704,2344532202,4240017532,1658658271,366619977,2362670323,4224994405,1303535960,984961486,2747007092,3569037538,1256170817,1037604311,2765210733,3554079995,1131014506,879679996,2909243462,3663771856,1141124467,855842277,2852801631,3708648649,1342533948,654459306,3188396048,3373015174,1466479909,544179635,3110523913,3462522015,1591671054,702138776,2966460450,3352799412,1504918807,783551873,3082640443,3233442989,3988292384,2596254646,62317068,1957810842,3939845945,2647816111,81470997,1943803523,3814918930,2489596804,225274430,2053790376,3826175755,2466906013,167816743,2097651377,4027552580,2265490386,503444072,1762050814,4150417245,2154129355,426522225,1852507879,4275313526,2312317920,282753626,1742555852,4189708143,2394877945,397917763,1622183637,3604390888,2714866558,953729732,1340076626,3518719985,2797360999,1068828381,1219638859,3624741850,2936675148,906185462,1090812512,3747672003,2825379669,829329135,1181335161,3412177804,3160834842,628085408,1382605366,3423369109,3138078467,570562233,1426400815,3317316542,2998733608,733239954,1555261956,3268935591,3050360625,752459403,1541320221,2607071920,3965973030,1969922972,40735498,2617837225,3943577151,1913087877,83908371,2512341634,3803740692,2075208622,213261112,2463272603,3855990285,2094854071,198958881,2262029012,4057260610,1759359992,534414190,2176718541,4139329115,1873836001,414664567,2282248934,4279200368,1711684554,285281116,2405801727,4167216745,1634467795,376229701,2685067896,3608007406,1308918612,956543938,2808555105,3495958263,1231636301,1047427035,2932959818,3654703836,1088359270,936918e3,2847714899,3736837829,1202900863,817233897,3183342108,3401237130,1404277552,615818150,3134207493,3453421203,1423857449,601450431,3009837614,3294710456,1567103746,711928724,3020668471,3272380065,1510334235,755167117];b.exports=function(a,b){if("undefined"==typeof a||!a.length)return 0;var e="string"!==c.getTypeOf(a);"undefined"==typeof b&&(b=0);var f=0,g=0,h=0;b=-1^b;for(var i=0,j=a.length;j>i;i++)h=e?a[i]:a.charCodeAt(i),g=255&(b^h),f=d[g],b=b>>>8^f;return-1^b}},{"./utils":21}],5:[function(a,b){"use strict";function c(){this.data=null,this.length=0,this.index=0}var d=a("./utils");c.prototype={checkOffset:function(a){this.checkIndex(this.index+a)},checkIndex:function(a){if(this.lengtha)throw new Error("End of data reached (data length = "+this.length+", asked index = "+a+"). Corrupted zip ?")},setIndex:function(a){this.checkIndex(a),this.index=a},skip:function(a){this.setIndex(this.index+a)},byteAt:function(){},readInt:function(a){var b,c=0;for(this.checkOffset(a),b=this.index+a-1;b>=this.index;b--)c=(c<<8)+this.byteAt(b);return this.index+=a,c},readString:function(a){return d.transformTo("string",this.readData(a))},readData:function(){},lastIndexOfSignature:function(){},readDate:function(){var a=this.readInt(4);return new Date((a>>25&127)+1980,(a>>21&15)-1,a>>16&31,a>>11&31,a>>5&63,(31&a)<<1)}},b.exports=c},{"./utils":21}],6:[function(a,b,c){"use strict";c.base64=!1,c.binary=!1,c.dir=!1,c.createFolders=!1,c.date=null,c.compression=null,c.compressionOptions=null,c.comment=null,c.unixPermissions=null,c.dosPermissions=null},{}],7:[function(a,b,c){"use strict";var d=a("./utils");c.string2binary=function(a){return d.string2binary(a)},c.string2Uint8Array=function(a){return d.transformTo("uint8array",a)},c.uint8Array2String=function(a){return d.transformTo("string",a)},c.string2Blob=function(a){var b=d.transformTo("arraybuffer",a);return d.arrayBuffer2Blob(b)},c.arrayBuffer2Blob=function(a){return d.arrayBuffer2Blob(a)},c.transformTo=function(a,b){return d.transformTo(a,b)},c.getTypeOf=function(a){return d.getTypeOf(a)},c.checkSupport=function(a){return d.checkSupport(a)},c.MAX_VALUE_16BITS=d.MAX_VALUE_16BITS,c.MAX_VALUE_32BITS=d.MAX_VALUE_32BITS,c.pretty=function(a){return d.pretty(a)},c.findCompression=function(a){return d.findCompression(a)},c.isRegExp=function(a){return d.isRegExp(a)}},{"./utils":21}],8:[function(a,b,c){"use strict";var d="undefined"!=typeof Uint8Array&&"undefined"!=typeof Uint16Array&&"undefined"!=typeof Uint32Array,e=a("pako");c.uncompressInputType=d?"uint8array":"array",c.compressInputType=d?"uint8array":"array",c.magic="\b\x00",c.compress=function(a,b){return e.deflateRaw(a,{level:b.level||-1})},c.uncompress=function(a){return e.inflateRaw(a)}},{pako:24}],9:[function(a,b){"use strict";function c(a,b){return this instanceof c?(this.files={},this.comment=null,this.root="",a&&this.load(a,b),void(this.clone=function(){var a=new c;for(var b in this)"function"!=typeof this[b]&&(a[b]=this[b]);return a})):new c(a,b)}var d=a("./base64");c.prototype=a("./object"),c.prototype.load=a("./load"),c.support=a("./support"),c.defaults=a("./defaults"),c.utils=a("./deprecatedPublicUtils"),c.base64={encode:function(a){return d.encode(a)},decode:function(a){return d.decode(a)}},c.compressions=a("./compressions"),b.exports=c},{"./base64":1,"./compressions":3,"./defaults":6,"./deprecatedPublicUtils":7,"./load":10,"./object":13,"./support":17}],10:[function(a,b){"use strict";var c=a("./base64"),d=a("./zipEntries");b.exports=function(a,b){var e,f,g,h;for(b=b||{},b.base64&&(a=c.decode(a)),f=new d(a,b),e=f.files,g=0;gc;c++)d+=String.fromCharCode(255&a),a>>>=8;return d},t=function(){var a,b,c={};for(a=0;a0?a.substring(0,b):""},x=function(a){return"/"!=a.slice(-1)&&(a+="/"),a},y=function(a,b){return b="undefined"!=typeof b?b:!1,a=x(a),this.files[a]||v.call(this,a,null,{dir:!0,createFolders:b}),this.files[a]},z=function(a,b,c){var f,g=new j;return a._data instanceof j?(g.uncompressedSize=a._data.uncompressedSize,g.crc32=a._data.crc32,0===g.uncompressedSize||a.dir?(b=i.STORE,g.compressedContent="",g.crc32=0):a._data.compressionMethod===b.magic?g.compressedContent=a._data.getCompressedContent():(f=a._data.getContent(),g.compressedContent=b.compress(d.transformTo(b.compressInputType,f),c))):(f=p(a),(!f||0===f.length||a.dir)&&(b=i.STORE,f=""),g.uncompressedSize=f.length,g.crc32=e(f),g.compressedContent=b.compress(d.transformTo(b.compressInputType,f),c)),g.compressedSize=g.compressedContent.length,g.compressionMethod=b.magic,g},A=function(a,b){var c=a;return a||(c=b?16893:33204),(65535&c)<<16},B=function(a){return 63&(a||0)},C=function(a,b,c,g,h){var i,j,k,m,n=(c.compressedContent,d.transformTo("string",l.utf8encode(b.name))),o=b.comment||"",p=d.transformTo("string",l.utf8encode(o)),q=n.length!==b.name.length,r=p.length!==o.length,t=b.options,u="",v="",w="";k=b._initialMetadata.dir!==b.dir?b.dir:t.dir,m=b._initialMetadata.date!==b.date?b.date:t.date;var x=0,y=0;k&&(x|=16),"UNIX"===h?(y=798,x|=A(b.unixPermissions,k)):(y=20,x|=B(b.dosPermissions,k)),i=m.getHours(),i<<=6,i|=m.getMinutes(),i<<=5,i|=m.getSeconds()/2,j=m.getFullYear()-1980,j<<=4,j|=m.getMonth()+1,j<<=5,j|=m.getDate(),q&&(v=s(1,1)+s(e(n),4)+n,u+="up"+s(v.length,2)+v),r&&(w=s(1,1)+s(this.crc32(p),4)+p,u+="uc"+s(w.length,2)+w);var z="";z+="\n\x00",z+=q||r?"\x00\b":"\x00\x00",z+=c.compressionMethod,z+=s(i,2),z+=s(j,2),z+=s(c.crc32,4),z+=s(c.compressedSize,4),z+=s(c.uncompressedSize,4),z+=s(n.length,2),z+=s(u.length,2);var C=f.LOCAL_FILE_HEADER+z+n+u,D=f.CENTRAL_FILE_HEADER+s(y,2)+z+s(p.length,2)+"\x00\x00\x00\x00"+s(x,4)+s(g,4)+n+u+p;return{fileRecord:C,dirRecord:D,compressedObject:c}},D={load:function(){throw new Error("Load method is not defined. Is the file jszip-load.js included ?")},filter:function(a){var b,c,d,e,f=[];for(b in this.files)this.files.hasOwnProperty(b)&&(d=this.files[b],e=new r(d.name,d._data,t(d.options)),c=b.slice(this.root.length,b.length),b.slice(0,this.root.length)===this.root&&a(c,e)&&f.push(e));return f},file:function(a,b,c){if(1===arguments.length){if(d.isRegExp(a)){var e=a;return this.filter(function(a,b){return!b.dir&&e.test(a)})}return this.filter(function(b,c){return!c.dir&&b===a})[0]||null}return a=this.root+a,v.call(this,a,b,c),this},folder:function(a){if(!a)return this;if(d.isRegExp(a))return this.filter(function(b,c){return c.dir&&a.test(b)});var b=this.root+a,c=y.call(this,b),e=this.clone();return e.root=c.name,e},remove:function(a){a=this.root+a;var b=this.files[a];if(b||("/"!=a.slice(-1)&&(a+="/"),b=this.files[a]),b&&!b.dir)delete this.files[a];else for(var c=this.filter(function(b,c){return c.name.slice(0,a.length)===a}),d=0;d=0;--f)if(this.data[f]===b&&this.data[f+1]===c&&this.data[f+2]===d&&this.data[f+3]===e)return f;return-1},c.prototype.readData=function(a){if(this.checkOffset(a),0===a)return new Uint8Array(0);var b=this.data.subarray(this.index,this.index+a);return this.index+=a,b},b.exports=c},{"./dataReader":5}],19:[function(a,b){"use strict";var c=a("./utils"),d=function(a){this.data=new Uint8Array(a),this.index=0};d.prototype={append:function(a){0!==a.length&&(a=c.transformTo("uint8array",a),this.data.set(a,this.index),this.index+=a.length)},finalize:function(){return this.data}},b.exports=d},{"./utils":21}],20:[function(a,b,c){"use strict";for(var d=a("./utils"),e=a("./support"),f=a("./nodeBuffer"),g=new Array(256),h=0;256>h;h++)g[h]=h>=252?6:h>=248?5:h>=240?4:h>=224?3:h>=192?2:1;g[254]=g[254]=1;var i=function(a){var b,c,d,f,g,h=a.length,i=0;for(f=0;h>f;f++)c=a.charCodeAt(f),55296===(64512&c)&&h>f+1&&(d=a.charCodeAt(f+1),56320===(64512&d)&&(c=65536+(c-55296<<10)+(d-56320),f++)),i+=128>c?1:2048>c?2:65536>c?3:4;for(b=e.uint8array?new Uint8Array(i):new Array(i),g=0,f=0;i>g;f++)c=a.charCodeAt(f),55296===(64512&c)&&h>f+1&&(d=a.charCodeAt(f+1),56320===(64512&d)&&(c=65536+(c-55296<<10)+(d-56320),f++)),128>c?b[g++]=c:2048>c?(b[g++]=192|c>>>6,b[g++]=128|63&c):65536>c?(b[g++]=224|c>>>12,b[g++]=128|c>>>6&63,b[g++]=128|63&c):(b[g++]=240|c>>>18,b[g++]=128|c>>>12&63,b[g++]=128|c>>>6&63,b[g++]=128|63&c);return b},j=function(a,b){var c;for(b=b||a.length,b>a.length&&(b=a.length),c=b-1;c>=0&&128===(192&a[c]);)c--;return 0>c?b:0===c?b:c+g[a[c]]>b?c:b},k=function(a){var b,c,e,f,h=a.length,i=new Array(2*h);for(c=0,b=0;h>b;)if(e=a[b++],128>e)i[c++]=e;else if(f=g[e],f>4)i[c++]=65533,b+=f-1;else{for(e&=2===f?31:3===f?15:7;f>1&&h>b;)e=e<<6|63&a[b++],f--;f>1?i[c++]=65533:65536>e?i[c++]=e:(e-=65536,i[c++]=55296|e>>10&1023,i[c++]=56320|1023&e)}return i.length!==c&&(i.subarray?i=i.subarray(0,c):i.length=c),d.applyFromCharCode(i)};c.utf8encode=function(a){return e.nodebuffer?f(a,"utf-8"):i(a)},c.utf8decode=function(a){if(e.nodebuffer)return d.transformTo("nodebuffer",a).toString("utf-8");a=d.transformTo(e.uint8array?"uint8array":"array",a);for(var b=[],c=0,f=a.length,g=65536;f>c;){var h=j(a,Math.min(c+g,f));b.push(e.uint8array?k(a.subarray(c,h)):k(a.slice(c,h))),c=h}return b.join("")}},{"./nodeBuffer":11,"./support":17,"./utils":21}],21:[function(a,b,c){"use strict";function d(a){return a}function e(a,b){for(var c=0;cg&&b>1;)try{d.push("array"===f||"nodebuffer"===f?String.fromCharCode.apply(null,a.slice(g,Math.min(g+b,e))):String.fromCharCode.apply(null,a.subarray(g,Math.min(g+b,e)))),g+=b}catch(i){b=Math.floor(b/2)}return d.join("")}function g(a,b){for(var c=0;cb?"0":"")+b.toString(16).toUpperCase();return d},c.findCompression=function(a){for(var b in i)if(i.hasOwnProperty(b)&&i[b].magic===a)return i[b];return null},c.isRegExp=function(a){return"[object RegExp]"===Object.prototype.toString.call(a)}},{"./compressions":3,"./nodeBuffer":11,"./support":17}],22:[function(a,b){"use strict";function c(a,b){this.files=[],this.loadOptions=b,a&&this.load(a)}var d=a("./stringReader"),e=a("./nodeBufferReader"),f=a("./uint8ArrayReader"),g=a("./utils"),h=a("./signature"),i=a("./zipEntry"),j=a("./support"),k=a("./object");c.prototype={checkSignature:function(a){var b=this.reader.readString(4);if(b!==a)throw new Error("Corrupted zip or bug : unexpected signature ("+g.pretty(b)+", expected "+g.pretty(a)+")")},readBlockEndOfCentral:function(){this.diskNumber=this.reader.readInt(2),this.diskWithCentralDirStart=this.reader.readInt(2),this.centralDirRecordsOnThisDisk=this.reader.readInt(2),this.centralDirRecords=this.reader.readInt(2),this.centralDirSize=this.reader.readInt(4),this.centralDirOffset=this.reader.readInt(4),this.zipCommentLength=this.reader.readInt(2),this.zipComment=this.reader.readString(this.zipCommentLength),this.zipComment=k.utf8decode(this.zipComment)},readBlockZip64EndOfCentral:function(){this.zip64EndOfCentralSize=this.reader.readInt(8),this.versionMadeBy=this.reader.readString(2),this.versionNeeded=this.reader.readInt(2),this.diskNumber=this.reader.readInt(4),this.diskWithCentralDirStart=this.reader.readInt(4),this.centralDirRecordsOnThisDisk=this.reader.readInt(8),this.centralDirRecords=this.reader.readInt(8),this.centralDirSize=this.reader.readInt(8),this.centralDirOffset=this.reader.readInt(8),this.zip64ExtensibleData={};for(var a,b,c,d=this.zip64EndOfCentralSize-44,e=0;d>e;)a=this.reader.readInt(2),b=this.reader.readInt(4),c=this.reader.readString(b),this.zip64ExtensibleData[a]={id:a,length:b,value:c}},readBlockZip64EndOfCentralLocator:function(){if(this.diskWithZip64CentralDirStart=this.reader.readInt(4),this.relativeOffsetEndOfZip64CentralDir=this.reader.readInt(8),this.disksCount=this.reader.readInt(4),this.disksCount>1)throw new Error("Multi-volumes zip are not supported")},readLocalFiles:function(){var a,b;for(a=0;a>8;this.dir=16&this.externalFileAttributes?!0:!1,a===h&&(this.dosPermissions=63&this.externalFileAttributes),a===i&&(this.unixPermissions=this.externalFileAttributes>>16&65535),this.dir||"/"!==this.fileName.slice(-1)||(this.dir=!0)},parseZIP64ExtraField:function(){if(this.extraFields[1]){var a=new d(this.extraFields[1].value);this.uncompressedSize===e.MAX_VALUE_32BITS&&(this.uncompressedSize=a.readInt(8)),this.compressedSize===e.MAX_VALUE_32BITS&&(this.compressedSize=a.readInt(8)),this.localHeaderOffset===e.MAX_VALUE_32BITS&&(this.localHeaderOffset=a.readInt(8)),this.diskNumberStart===e.MAX_VALUE_32BITS&&(this.diskNumberStart=a.readInt(4))}},readExtraFields:function(a){var b,c,d,e=a.index;for(this.extraFields=this.extraFields||{};a.index0?b.windowBits=-b.windowBits:b.gzip&&b.windowBits>0&&b.windowBits<16&&(b.windowBits+=16),this.err=0,this.msg="",this.ended=!1,this.chunks=[],this.strm=new k,this.strm.avail_out=0;var c=g.deflateInit2(this.strm,b.level,b.method,b.windowBits,b.memLevel,b.strategy);if(c!==n)throw new Error(j[c]);b.header&&g.deflateSetHeader(this.strm,b.header)};s.prototype.push=function(a,b){var c,d,e=this.strm,f=this.options.chunkSize;if(this.ended)return!1;d=b===~~b?b:b===!0?m:l,e.input="string"==typeof a?i.string2buf(a):a,e.next_in=0,e.avail_in=e.input.length;do{if(0===e.avail_out&&(e.output=new h.Buf8(f),e.next_out=0,e.avail_out=f),c=g.deflate(e,d),c!==o&&c!==n)return this.onEnd(c),this.ended=!0,!1;(0===e.avail_out||0===e.avail_in&&d===m)&&this.onData("string"===this.options.to?i.buf2binstring(h.shrinkBuf(e.output,e.next_out)):h.shrinkBuf(e.output,e.next_out))}while((e.avail_in>0||0===e.avail_out)&&c!==o);return d===m?(c=g.deflateEnd(this.strm),this.onEnd(c),this.ended=!0,c===n):!0},s.prototype.onData=function(a){this.chunks.push(a)},s.prototype.onEnd=function(a){a===n&&(this.result="string"===this.options.to?this.chunks.join(""):h.flattenChunks(this.chunks)),this.chunks=[],this.err=a,this.msg=this.strm.msg},c.Deflate=s,c.deflate=d,c.deflateRaw=e,c.gzip=f},{"./utils/common":27,"./utils/strings":28,"./zlib/deflate.js":32,"./zlib/messages":37,"./zlib/zstream":39}],26:[function(a,b,c){"use strict";function d(a,b){var c=new m(b);if(c.push(a,!0),c.err)throw c.msg;return c.result}function e(a,b){return b=b||{},b.raw=!0,d(a,b)}var f=a("./zlib/inflate.js"),g=a("./utils/common"),h=a("./utils/strings"),i=a("./zlib/constants"),j=a("./zlib/messages"),k=a("./zlib/zstream"),l=a("./zlib/gzheader"),m=function(a){this.options=g.assign({chunkSize:16384,windowBits:0,to:""},a||{});var b=this.options;b.raw&&b.windowBits>=0&&b.windowBits<16&&(b.windowBits=-b.windowBits,0===b.windowBits&&(b.windowBits=-15)),!(b.windowBits>=0&&b.windowBits<16)||a&&a.windowBits||(b.windowBits+=32),b.windowBits>15&&b.windowBits<48&&0===(15&b.windowBits)&&(b.windowBits|=15),this.err=0,this.msg="",this.ended=!1,this.chunks=[],this.strm=new k,this.strm.avail_out=0;var c=f.inflateInit2(this.strm,b.windowBits);if(c!==i.Z_OK)throw new Error(j[c]);this.header=new l,f.inflateGetHeader(this.strm,this.header)};m.prototype.push=function(a,b){var c,d,e,j,k,l=this.strm,m=this.options.chunkSize;if(this.ended)return!1;d=b===~~b?b:b===!0?i.Z_FINISH:i.Z_NO_FLUSH,l.input="string"==typeof a?h.binstring2buf(a):a,l.next_in=0,l.avail_in=l.input.length;do{if(0===l.avail_out&&(l.output=new g.Buf8(m),l.next_out=0,l.avail_out=m),c=f.inflate(l,i.Z_NO_FLUSH),c!==i.Z_STREAM_END&&c!==i.Z_OK)return this.onEnd(c),this.ended=!0,!1;l.next_out&&(0===l.avail_out||c===i.Z_STREAM_END||0===l.avail_in&&d===i.Z_FINISH)&&("string"===this.options.to?(e=h.utf8border(l.output,l.next_out),j=l.next_out-e,k=h.buf2string(l.output,e),l.next_out=j,l.avail_out=m-j,j&&g.arraySet(l.output,l.output,e,j,0),this.onData(k)):this.onData(g.shrinkBuf(l.output,l.next_out)))}while(l.avail_in>0&&c!==i.Z_STREAM_END);return c===i.Z_STREAM_END&&(d=i.Z_FINISH),d===i.Z_FINISH?(c=f.inflateEnd(this.strm),this.onEnd(c),this.ended=!0,c===i.Z_OK):!0},m.prototype.onData=function(a){this.chunks.push(a)},m.prototype.onEnd=function(a){a===i.Z_OK&&(this.result="string"===this.options.to?this.chunks.join(""):g.flattenChunks(this.chunks)),this.chunks=[],this.err=a,this.msg=this.strm.msg},c.Inflate=m,c.inflate=d,c.inflateRaw=e,c.ungzip=d},{"./utils/common":27,"./utils/strings":28,"./zlib/constants":30,"./zlib/gzheader":33,"./zlib/inflate.js":35,"./zlib/messages":37,"./zlib/zstream":39}],27:[function(a,b,c){"use strict";var d="undefined"!=typeof Uint8Array&&"undefined"!=typeof Uint16Array&&"undefined"!=typeof Int32Array;c.assign=function(a){for(var b=Array.prototype.slice.call(arguments,1);b.length;){var c=b.shift();if(c){if("object"!=typeof c)throw new TypeError(c+"must be non-object");for(var d in c)c.hasOwnProperty(d)&&(a[d]=c[d])}}return a},c.shrinkBuf=function(a,b){return a.length===b?a:a.subarray?a.subarray(0,b):(a.length=b,a)};var e={arraySet:function(a,b,c,d,e){if(b.subarray&&a.subarray)return void a.set(b.subarray(c,c+d),e);for(var f=0;d>f;f++)a[e+f]=b[c+f]},flattenChunks:function(a){var b,c,d,e,f,g;for(d=0,b=0,c=a.length;c>b;b++)d+=a[b].length;for(g=new Uint8Array(d),e=0,b=0,c=a.length;c>b;b++)f=a[b],g.set(f,e),e+=f.length;return g}},f={arraySet:function(a,b,c,d,e){for(var f=0;d>f;f++)a[e+f]=b[c+f]},flattenChunks:function(a){return[].concat.apply([],a)}};c.setTyped=function(a){a?(c.Buf8=Uint8Array,c.Buf16=Uint16Array,c.Buf32=Int32Array,c.assign(c,e)):(c.Buf8=Array,c.Buf16=Array,c.Buf32=Array,c.assign(c,f))},c.setTyped(d)},{}],28:[function(a,b,c){"use strict";function d(a,b){if(65537>b&&(a.subarray&&g||!a.subarray&&f))return String.fromCharCode.apply(null,e.shrinkBuf(a,b));for(var c="",d=0;b>d;d++)c+=String.fromCharCode(a[d]);return c}var e=a("./common"),f=!0,g=!0;try{String.fromCharCode.apply(null,[0])}catch(h){f=!1}try{String.fromCharCode.apply(null,new Uint8Array(1))}catch(h){g=!1}for(var i=new e.Buf8(256),j=0;256>j;j++)i[j]=j>=252?6:j>=248?5:j>=240?4:j>=224?3:j>=192?2:1;i[254]=i[254]=1,c.string2buf=function(a){var b,c,d,f,g,h=a.length,i=0;for(f=0;h>f;f++)c=a.charCodeAt(f),55296===(64512&c)&&h>f+1&&(d=a.charCodeAt(f+1),56320===(64512&d)&&(c=65536+(c-55296<<10)+(d-56320),f++)),i+=128>c?1:2048>c?2:65536>c?3:4;for(b=new e.Buf8(i),g=0,f=0;i>g;f++)c=a.charCodeAt(f),55296===(64512&c)&&h>f+1&&(d=a.charCodeAt(f+1),56320===(64512&d)&&(c=65536+(c-55296<<10)+(d-56320),f++)),128>c?b[g++]=c:2048>c?(b[g++]=192|c>>>6,b[g++]=128|63&c):65536>c?(b[g++]=224|c>>>12,b[g++]=128|c>>>6&63,b[g++]=128|63&c):(b[g++]=240|c>>>18,b[g++]=128|c>>>12&63,b[g++]=128|c>>>6&63,b[g++]=128|63&c);return b},c.buf2binstring=function(a){return d(a,a.length)},c.binstring2buf=function(a){for(var b=new e.Buf8(a.length),c=0,d=b.length;d>c;c++)b[c]=a.charCodeAt(c);return b},c.buf2string=function(a,b){var c,e,f,g,h=b||a.length,j=new Array(2*h);for(e=0,c=0;h>c;)if(f=a[c++],128>f)j[e++]=f;else if(g=i[f],g>4)j[e++]=65533,c+=g-1;else{for(f&=2===g?31:3===g?15:7;g>1&&h>c;)f=f<<6|63&a[c++],g--;g>1?j[e++]=65533:65536>f?j[e++]=f:(f-=65536,j[e++]=55296|f>>10&1023,j[e++]=56320|1023&f)}return d(j,e)},c.utf8border=function(a,b){var c;for(b=b||a.length,b>a.length&&(b=a.length),c=b-1;c>=0&&128===(192&a[c]);)c--;return 0>c?b:0===c?b:c+i[a[c]]>b?c:b}},{"./common":27}],29:[function(a,b){"use strict";function c(a,b,c,d){for(var e=65535&a|0,f=a>>>16&65535|0,g=0;0!==c;){g=c>2e3?2e3:c,c-=g;do e=e+b[d++]|0,f=f+e|0;while(--g);e%=65521,f%=65521}return e|f<<16|0}b.exports=c},{}],30:[function(a,b){b.exports={Z_NO_FLUSH:0,Z_PARTIAL_FLUSH:1,Z_SYNC_FLUSH:2,Z_FULL_FLUSH:3,Z_FINISH:4,Z_BLOCK:5,Z_TREES:6,Z_OK:0,Z_STREAM_END:1,Z_NEED_DICT:2,Z_ERRNO:-1,Z_STREAM_ERROR:-2,Z_DATA_ERROR:-3,Z_BUF_ERROR:-5,Z_NO_COMPRESSION:0,Z_BEST_SPEED:1,Z_BEST_COMPRESSION:9,Z_DEFAULT_COMPRESSION:-1,Z_FILTERED:1,Z_HUFFMAN_ONLY:2,Z_RLE:3,Z_FIXED:4,Z_DEFAULT_STRATEGY:0,Z_BINARY:0,Z_TEXT:1,Z_UNKNOWN:2,Z_DEFLATED:8}},{}],31:[function(a,b){"use strict";function c(){for(var a,b=[],c=0;256>c;c++){a=c;for(var d=0;8>d;d++)a=1&a?3988292384^a>>>1:a>>>1;b[c]=a}return b}function d(a,b,c,d){var f=e,g=d+c;a=-1^a;for(var h=d;g>h;h++)a=a>>>8^f[255&(a^b[h])];return-1^a}var e=c();b.exports=d},{}],32:[function(a,b,c){"use strict";function d(a,b){return a.msg=G[b],b}function e(a){return(a<<1)-(a>4?9:0)}function f(a){for(var b=a.length;--b>=0;)a[b]=0}function g(a){var b=a.state,c=b.pending;c>a.avail_out&&(c=a.avail_out),0!==c&&(C.arraySet(a.output,b.pending_buf,b.pending_out,c,a.next_out),a.next_out+=c,b.pending_out+=c,a.total_out+=c,a.avail_out-=c,b.pending-=c,0===b.pending&&(b.pending_out=0))}function h(a,b){D._tr_flush_block(a,a.block_start>=0?a.block_start:-1,a.strstart-a.block_start,b),a.block_start=a.strstart,g(a.strm)}function i(a,b){a.pending_buf[a.pending++]=b}function j(a,b){a.pending_buf[a.pending++]=b>>>8&255,a.pending_buf[a.pending++]=255&b}function k(a,b,c,d){var e=a.avail_in;return e>d&&(e=d),0===e?0:(a.avail_in-=e,C.arraySet(b,a.input,a.next_in,e,c),1===a.state.wrap?a.adler=E(a.adler,b,e,c):2===a.state.wrap&&(a.adler=F(a.adler,b,e,c)),a.next_in+=e,a.total_in+=e,e)}function l(a,b){var c,d,e=a.max_chain_length,f=a.strstart,g=a.prev_length,h=a.nice_match,i=a.strstart>a.w_size-jb?a.strstart-(a.w_size-jb):0,j=a.window,k=a.w_mask,l=a.prev,m=a.strstart+ib,n=j[f+g-1],o=j[f+g];a.prev_length>=a.good_match&&(e>>=2),h>a.lookahead&&(h=a.lookahead);do if(c=b,j[c+g]===o&&j[c+g-1]===n&&j[c]===j[f]&&j[++c]===j[f+1]){f+=2,c++;do;while(j[++f]===j[++c]&&j[++f]===j[++c]&&j[++f]===j[++c]&&j[++f]===j[++c]&&j[++f]===j[++c]&&j[++f]===j[++c]&&j[++f]===j[++c]&&j[++f]===j[++c]&&m>f);if(d=ib-(m-f),f=m-ib,d>g){if(a.match_start=b,g=d,d>=h)break;n=j[f+g-1],o=j[f+g]}}while((b=l[b&k])>i&&0!==--e);return g<=a.lookahead?g:a.lookahead}function m(a){var b,c,d,e,f,g=a.w_size;do{if(e=a.window_size-a.lookahead-a.strstart,a.strstart>=g+(g-jb)){C.arraySet(a.window,a.window,g,g,0),a.match_start-=g,a.strstart-=g,a.block_start-=g,c=a.hash_size,b=c;do d=a.head[--b],a.head[b]=d>=g?d-g:0;while(--c);c=g,b=c;do d=a.prev[--b],a.prev[b]=d>=g?d-g:0;while(--c);e+=g}if(0===a.strm.avail_in)break;if(c=k(a.strm,a.window,a.strstart+a.lookahead,e),a.lookahead+=c,a.lookahead+a.insert>=hb)for(f=a.strstart-a.insert,a.ins_h=a.window[f],a.ins_h=(a.ins_h<a.pending_buf_size-5&&(c=a.pending_buf_size-5);;){if(a.lookahead<=1){if(m(a),0===a.lookahead&&b===H)return sb;if(0===a.lookahead)break}a.strstart+=a.lookahead,a.lookahead=0;var d=a.block_start+c;if((0===a.strstart||a.strstart>=d)&&(a.lookahead=a.strstart-d,a.strstart=d,h(a,!1),0===a.strm.avail_out))return sb;if(a.strstart-a.block_start>=a.w_size-jb&&(h(a,!1),0===a.strm.avail_out))return sb}return a.insert=0,b===K?(h(a,!0),0===a.strm.avail_out?ub:vb):a.strstart>a.block_start&&(h(a,!1),0===a.strm.avail_out)?sb:sb}function o(a,b){for(var c,d;;){if(a.lookahead=hb&&(a.ins_h=(a.ins_h<=hb)if(d=D._tr_tally(a,a.strstart-a.match_start,a.match_length-hb),a.lookahead-=a.match_length,a.match_length<=a.max_lazy_match&&a.lookahead>=hb){a.match_length--;do a.strstart++,a.ins_h=(a.ins_h<=hb&&(a.ins_h=(a.ins_h<4096)&&(a.match_length=hb-1)),a.prev_length>=hb&&a.match_length<=a.prev_length){e=a.strstart+a.lookahead-hb,d=D._tr_tally(a,a.strstart-1-a.prev_match,a.prev_length-hb),a.lookahead-=a.prev_length-1,a.prev_length-=2;do++a.strstart<=e&&(a.ins_h=(a.ins_h<=hb&&a.strstart>0&&(e=a.strstart-1,d=g[e],d===g[++e]&&d===g[++e]&&d===g[++e])){f=a.strstart+ib;do;while(d===g[++e]&&d===g[++e]&&d===g[++e]&&d===g[++e]&&d===g[++e]&&d===g[++e]&&d===g[++e]&&d===g[++e]&&f>e);a.match_length=ib-(f-e),a.match_length>a.lookahead&&(a.match_length=a.lookahead)}if(a.match_length>=hb?(c=D._tr_tally(a,1,a.match_length-hb),a.lookahead-=a.match_length,a.strstart+=a.match_length,a.match_length=0):(c=D._tr_tally(a,0,a.window[a.strstart]),a.lookahead--,a.strstart++),c&&(h(a,!1),0===a.strm.avail_out))return sb}return a.insert=0,b===K?(h(a,!0),0===a.strm.avail_out?ub:vb):a.last_lit&&(h(a,!1),0===a.strm.avail_out)?sb:tb}function r(a,b){for(var c;;){if(0===a.lookahead&&(m(a),0===a.lookahead)){if(b===H)return sb;break}if(a.match_length=0,c=D._tr_tally(a,0,a.window[a.strstart]),a.lookahead--,a.strstart++,c&&(h(a,!1),0===a.strm.avail_out))return sb}return a.insert=0,b===K?(h(a,!0),0===a.strm.avail_out?ub:vb):a.last_lit&&(h(a,!1),0===a.strm.avail_out)?sb:tb}function s(a){a.window_size=2*a.w_size,f(a.head),a.max_lazy_match=B[a.level].max_lazy,a.good_match=B[a.level].good_length,a.nice_match=B[a.level].nice_length,a.max_chain_length=B[a.level].max_chain,a.strstart=0,a.block_start=0,a.lookahead=0,a.insert=0,a.match_length=a.prev_length=hb-1,a.match_available=0,a.ins_h=0}function t(){this.strm=null,this.status=0,this.pending_buf=null,this.pending_buf_size=0,this.pending_out=0,this.pending=0,this.wrap=0,this.gzhead=null,this.gzindex=0,this.method=Y,this.last_flush=-1,this.w_size=0,this.w_bits=0,this.w_mask=0,this.window=null,this.window_size=0,this.prev=null,this.head=null,this.ins_h=0,this.hash_size=0,this.hash_bits=0,this.hash_mask=0,this.hash_shift=0,this.block_start=0,this.match_length=0,this.prev_match=0,this.match_available=0,this.strstart=0,this.match_start=0,this.lookahead=0,this.prev_length=0,this.max_chain_length=0,this.max_lazy_match=0,this.level=0,this.strategy=0,this.good_match=0,this.nice_match=0,this.dyn_ltree=new C.Buf16(2*fb),this.dyn_dtree=new C.Buf16(2*(2*db+1)),this.bl_tree=new C.Buf16(2*(2*eb+1)),f(this.dyn_ltree),f(this.dyn_dtree),f(this.bl_tree),this.l_desc=null,this.d_desc=null,this.bl_desc=null,this.bl_count=new C.Buf16(gb+1),this.heap=new C.Buf16(2*cb+1),f(this.heap),this.heap_len=0,this.heap_max=0,this.depth=new C.Buf16(2*cb+1),f(this.depth),this.l_buf=0,this.lit_bufsize=0,this.last_lit=0,this.d_buf=0,this.opt_len=0,this.static_len=0,this.matches=0,this.insert=0,this.bi_buf=0,this.bi_valid=0}function u(a){var b;return a&&a.state?(a.total_in=a.total_out=0,a.data_type=X,b=a.state,b.pending=0,b.pending_out=0,b.wrap<0&&(b.wrap=-b.wrap),b.status=b.wrap?lb:qb,a.adler=2===b.wrap?0:1,b.last_flush=H,D._tr_init(b),M):d(a,O)}function v(a){var b=u(a);return b===M&&s(a.state),b}function w(a,b){return a&&a.state?2!==a.state.wrap?O:(a.state.gzhead=b,M):O}function x(a,b,c,e,f,g){if(!a)return O;var h=1;if(b===R&&(b=6),0>e?(h=0,e=-e):e>15&&(h=2,e-=16),1>f||f>Z||c!==Y||8>e||e>15||0>b||b>9||0>g||g>V)return d(a,O);8===e&&(e=9);var i=new t;return a.state=i,i.strm=a,i.wrap=h,i.gzhead=null,i.w_bits=e,i.w_size=1<>1,i.l_buf=3*i.lit_bufsize,i.level=b,i.strategy=g,i.method=c,v(a)}function y(a,b){return x(a,b,Y,$,_,W)}function z(a,b){var c,h,k,l;if(!a||!a.state||b>L||0>b)return a?d(a,O):O;if(h=a.state,!a.output||!a.input&&0!==a.avail_in||h.status===rb&&b!==K)return d(a,0===a.avail_out?Q:O);if(h.strm=a,c=h.last_flush,h.last_flush=b,h.status===lb)if(2===h.wrap)a.adler=0,i(h,31),i(h,139),i(h,8),h.gzhead?(i(h,(h.gzhead.text?1:0)+(h.gzhead.hcrc?2:0)+(h.gzhead.extra?4:0)+(h.gzhead.name?8:0)+(h.gzhead.comment?16:0)),i(h,255&h.gzhead.time),i(h,h.gzhead.time>>8&255),i(h,h.gzhead.time>>16&255),i(h,h.gzhead.time>>24&255),i(h,9===h.level?2:h.strategy>=T||h.level<2?4:0),i(h,255&h.gzhead.os),h.gzhead.extra&&h.gzhead.extra.length&&(i(h,255&h.gzhead.extra.length),i(h,h.gzhead.extra.length>>8&255)),h.gzhead.hcrc&&(a.adler=F(a.adler,h.pending_buf,h.pending,0)),h.gzindex=0,h.status=mb):(i(h,0),i(h,0),i(h,0),i(h,0),i(h,0),i(h,9===h.level?2:h.strategy>=T||h.level<2?4:0),i(h,wb),h.status=qb);else{var m=Y+(h.w_bits-8<<4)<<8,n=-1;n=h.strategy>=T||h.level<2?0:h.level<6?1:6===h.level?2:3,m|=n<<6,0!==h.strstart&&(m|=kb),m+=31-m%31,h.status=qb,j(h,m),0!==h.strstart&&(j(h,a.adler>>>16),j(h,65535&a.adler)),a.adler=1}if(h.status===mb)if(h.gzhead.extra){for(k=h.pending;h.gzindex<(65535&h.gzhead.extra.length)&&(h.pending!==h.pending_buf_size||(h.gzhead.hcrc&&h.pending>k&&(a.adler=F(a.adler,h.pending_buf,h.pending-k,k)),g(a),k=h.pending,h.pending!==h.pending_buf_size));)i(h,255&h.gzhead.extra[h.gzindex]),h.gzindex++;h.gzhead.hcrc&&h.pending>k&&(a.adler=F(a.adler,h.pending_buf,h.pending-k,k)),h.gzindex===h.gzhead.extra.length&&(h.gzindex=0,h.status=nb)}else h.status=nb;if(h.status===nb)if(h.gzhead.name){k=h.pending;do{if(h.pending===h.pending_buf_size&&(h.gzhead.hcrc&&h.pending>k&&(a.adler=F(a.adler,h.pending_buf,h.pending-k,k)),g(a),k=h.pending,h.pending===h.pending_buf_size)){l=1;break}l=h.gzindexk&&(a.adler=F(a.adler,h.pending_buf,h.pending-k,k)),0===l&&(h.gzindex=0,h.status=ob)}else h.status=ob;if(h.status===ob)if(h.gzhead.comment){k=h.pending;do{if(h.pending===h.pending_buf_size&&(h.gzhead.hcrc&&h.pending>k&&(a.adler=F(a.adler,h.pending_buf,h.pending-k,k)),g(a),k=h.pending,h.pending===h.pending_buf_size)){l=1;break}l=h.gzindexk&&(a.adler=F(a.adler,h.pending_buf,h.pending-k,k)),0===l&&(h.status=pb)}else h.status=pb;if(h.status===pb&&(h.gzhead.hcrc?(h.pending+2>h.pending_buf_size&&g(a),h.pending+2<=h.pending_buf_size&&(i(h,255&a.adler),i(h,a.adler>>8&255),a.adler=0,h.status=qb)):h.status=qb),0!==h.pending){if(g(a),0===a.avail_out)return h.last_flush=-1,M}else if(0===a.avail_in&&e(b)<=e(c)&&b!==K)return d(a,Q);if(h.status===rb&&0!==a.avail_in)return d(a,Q);if(0!==a.avail_in||0!==h.lookahead||b!==H&&h.status!==rb){var o=h.strategy===T?r(h,b):h.strategy===U?q(h,b):B[h.level].func(h,b);if((o===ub||o===vb)&&(h.status=rb),o===sb||o===ub)return 0===a.avail_out&&(h.last_flush=-1),M;if(o===tb&&(b===I?D._tr_align(h):b!==L&&(D._tr_stored_block(h,0,0,!1),b===J&&(f(h.head),0===h.lookahead&&(h.strstart=0,h.block_start=0,h.insert=0))),g(a),0===a.avail_out))return h.last_flush=-1,M}return b!==K?M:h.wrap<=0?N:(2===h.wrap?(i(h,255&a.adler),i(h,a.adler>>8&255),i(h,a.adler>>16&255),i(h,a.adler>>24&255),i(h,255&a.total_in),i(h,a.total_in>>8&255),i(h,a.total_in>>16&255),i(h,a.total_in>>24&255)):(j(h,a.adler>>>16),j(h,65535&a.adler)),g(a),h.wrap>0&&(h.wrap=-h.wrap),0!==h.pending?M:N)}function A(a){var b;return a&&a.state?(b=a.state.status,b!==lb&&b!==mb&&b!==nb&&b!==ob&&b!==pb&&b!==qb&&b!==rb?d(a,O):(a.state=null,b===qb?d(a,P):M)):O}var B,C=a("../utils/common"),D=a("./trees"),E=a("./adler32"),F=a("./crc32"),G=a("./messages"),H=0,I=1,J=3,K=4,L=5,M=0,N=1,O=-2,P=-3,Q=-5,R=-1,S=1,T=2,U=3,V=4,W=0,X=2,Y=8,Z=9,$=15,_=8,ab=29,bb=256,cb=bb+1+ab,db=30,eb=19,fb=2*cb+1,gb=15,hb=3,ib=258,jb=ib+hb+1,kb=32,lb=42,mb=69,nb=73,ob=91,pb=103,qb=113,rb=666,sb=1,tb=2,ub=3,vb=4,wb=3,xb=function(a,b,c,d,e){this.good_length=a,this.max_lazy=b,this.nice_length=c,this.max_chain=d,this.func=e};B=[new xb(0,0,0,0,n),new xb(4,4,8,4,o),new xb(4,5,16,8,o),new xb(4,6,32,32,o),new xb(4,4,16,16,p),new xb(8,16,32,32,p),new xb(8,16,128,128,p),new xb(8,32,128,256,p),new xb(32,128,258,1024,p),new xb(32,258,258,4096,p)],c.deflateInit=y,c.deflateInit2=x,c.deflateReset=v,c.deflateResetKeep=u,c.deflateSetHeader=w,c.deflate=z,c.deflateEnd=A,c.deflateInfo="pako deflate (from Nodeca project)"},{"../utils/common":27,"./adler32":29,"./crc32":31,"./messages":37,"./trees":38}],33:[function(a,b){"use strict";function c(){this.text=0,this.time=0,this.xflags=0,this.os=0,this.extra=null,this.extra_len=0,this.name="",this.comment="",this.hcrc=0,this.done=!1}b.exports=c},{}],34:[function(a,b){"use strict";var c=30,d=12;b.exports=function(a,b){var e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C;e=a.state,f=a.next_in,B=a.input,g=f+(a.avail_in-5),h=a.next_out,C=a.output,i=h-(b-a.avail_out),j=h+(a.avail_out-257),k=e.dmax,l=e.wsize,m=e.whave,n=e.wnext,o=e.window,p=e.hold,q=e.bits,r=e.lencode,s=e.distcode,t=(1<q&&(p+=B[f++]<>>24,p>>>=w,q-=w,w=v>>>16&255,0===w)C[h++]=65535&v;else{if(!(16&w)){if(0===(64&w)){v=r[(65535&v)+(p&(1<q&&(p+=B[f++]<>>=w,q-=w),15>q&&(p+=B[f++]<>>24,p>>>=w,q-=w,w=v>>>16&255,!(16&w)){if(0===(64&w)){v=s[(65535&v)+(p&(1<q&&(p+=B[f++]<q&&(p+=B[f++]<k){a.msg="invalid distance too far back",e.mode=c;break a}if(p>>>=w,q-=w,w=h-i,y>w){if(w=y-w,w>m&&e.sane){a.msg="invalid distance too far back",e.mode=c;break a}if(z=0,A=o,0===n){if(z+=l-w,x>w){x-=w;do C[h++]=o[z++];while(--w);z=h-y,A=C}}else if(w>n){if(z+=l+n-w,w-=n,x>w){x-=w;do C[h++]=o[z++];while(--w);if(z=0,x>n){w=n,x-=w;do C[h++]=o[z++];while(--w);z=h-y,A=C}}}else if(z+=n-w,x>w){x-=w;do C[h++]=o[z++];while(--w);z=h-y,A=C}for(;x>2;)C[h++]=A[z++],C[h++]=A[z++],C[h++]=A[z++],x-=3;x&&(C[h++]=A[z++],x>1&&(C[h++]=A[z++]))}else{z=h-y;do C[h++]=C[z++],C[h++]=C[z++],C[h++]=C[z++],x-=3;while(x>2);x&&(C[h++]=C[z++],x>1&&(C[h++]=C[z++]))}break}}break}}while(g>f&&j>h);x=q>>3,f-=x,q-=x<<3,p&=(1<f?5+(g-f):5-(f-g),a.avail_out=j>h?257+(j-h):257-(h-j),e.hold=p,e.bits=q}},{}],35:[function(a,b,c){"use strict";function d(a){return(a>>>24&255)+(a>>>8&65280)+((65280&a)<<8)+((255&a)<<24)}function e(){this.mode=0,this.last=!1,this.wrap=0,this.havedict=!1,this.flags=0,this.dmax=0,this.check=0,this.total=0,this.head=null,this.wbits=0,this.wsize=0,this.whave=0,this.wnext=0,this.window=null,this.hold=0,this.bits=0,this.length=0,this.offset=0,this.extra=0,this.lencode=null,this.distcode=null,this.lenbits=0,this.distbits=0,this.ncode=0,this.nlen=0,this.ndist=0,this.have=0,this.next=null,this.lens=new r.Buf16(320),this.work=new r.Buf16(288),this.lendyn=null,this.distdyn=null,this.sane=0,this.back=0,this.was=0}function f(a){var b;return a&&a.state?(b=a.state,a.total_in=a.total_out=b.total=0,a.msg="",b.wrap&&(a.adler=1&b.wrap),b.mode=K,b.last=0,b.havedict=0,b.dmax=32768,b.head=null,b.hold=0,b.bits=0,b.lencode=b.lendyn=new r.Buf32(ob),b.distcode=b.distdyn=new r.Buf32(pb),b.sane=1,b.back=-1,C):F}function g(a){var b;return a&&a.state?(b=a.state,b.wsize=0,b.whave=0,b.wnext=0,f(a)):F}function h(a,b){var c,d;return a&&a.state?(d=a.state,0>b?(c=0,b=-b):(c=(b>>4)+1,48>b&&(b&=15)),b&&(8>b||b>15)?F:(null!==d.window&&d.wbits!==b&&(d.window=null),d.wrap=c,d.wbits=b,g(a))):F}function i(a,b){var c,d;return a?(d=new e,a.state=d,d.window=null,c=h(a,b),c!==C&&(a.state=null),c):F}function j(a){return i(a,rb)}function k(a){if(sb){var b;for(p=new r.Buf32(512),q=new r.Buf32(32),b=0;144>b;)a.lens[b++]=8;for(;256>b;)a.lens[b++]=9;for(;280>b;)a.lens[b++]=7;for(;288>b;)a.lens[b++]=8;for(v(x,a.lens,0,288,p,0,a.work,{bits:9}),b=0;32>b;)a.lens[b++]=5;v(y,a.lens,0,32,q,0,a.work,{bits:5}),sb=!1}a.lencode=p,a.lenbits=9,a.distcode=q,a.distbits=5}function l(a,b,c,d){var e,f=a.state;return null===f.window&&(f.wsize=1<=f.wsize?(r.arraySet(f.window,b,c-f.wsize,f.wsize,0),f.wnext=0,f.whave=f.wsize):(e=f.wsize-f.wnext,e>d&&(e=d),r.arraySet(f.window,b,c-d,e,f.wnext),d-=e,d?(r.arraySet(f.window,b,c-d,d,0),f.wnext=d,f.whave=f.wsize):(f.wnext+=e,f.wnext===f.wsize&&(f.wnext=0),f.whaven;){if(0===i)break a;i--,m+=e[g++]<>>8&255,c.check=t(c.check,Bb,2,0),m=0,n=0,c.mode=L;break}if(c.flags=0,c.head&&(c.head.done=!1),!(1&c.wrap)||(((255&m)<<8)+(m>>8))%31){a.msg="incorrect header check",c.mode=lb;break}if((15&m)!==J){a.msg="unknown compression method",c.mode=lb;break}if(m>>>=4,n-=4,wb=(15&m)+8,0===c.wbits)c.wbits=wb;else if(wb>c.wbits){a.msg="invalid window size",c.mode=lb;break}c.dmax=1<n;){if(0===i)break a;i--,m+=e[g++]<>8&1),512&c.flags&&(Bb[0]=255&m,Bb[1]=m>>>8&255,c.check=t(c.check,Bb,2,0)),m=0,n=0,c.mode=M;case M:for(;32>n;){if(0===i)break a;i--,m+=e[g++]<>>8&255,Bb[2]=m>>>16&255,Bb[3]=m>>>24&255,c.check=t(c.check,Bb,4,0)),m=0,n=0,c.mode=N;case N:for(;16>n;){if(0===i)break a;i--,m+=e[g++]<>8),512&c.flags&&(Bb[0]=255&m,Bb[1]=m>>>8&255,c.check=t(c.check,Bb,2,0)),m=0,n=0,c.mode=O;case O:if(1024&c.flags){for(;16>n;){if(0===i)break a;i--,m+=e[g++]<>>8&255,c.check=t(c.check,Bb,2,0)),m=0,n=0}else c.head&&(c.head.extra=null);c.mode=P;case P:if(1024&c.flags&&(q=c.length,q>i&&(q=i),q&&(c.head&&(wb=c.head.extra_len-c.length,c.head.extra||(c.head.extra=new Array(c.head.extra_len)),r.arraySet(c.head.extra,e,g,q,wb)),512&c.flags&&(c.check=t(c.check,e,q,g)),i-=q,g+=q,c.length-=q),c.length))break a;c.length=0,c.mode=Q;case Q:if(2048&c.flags){if(0===i)break a;q=0;do wb=e[g+q++],c.head&&wb&&c.length<65536&&(c.head.name+=String.fromCharCode(wb));while(wb&&i>q);if(512&c.flags&&(c.check=t(c.check,e,q,g)),i-=q,g+=q,wb)break a}else c.head&&(c.head.name=null);c.length=0,c.mode=R;case R:if(4096&c.flags){if(0===i)break a;q=0;do wb=e[g+q++],c.head&&wb&&c.length<65536&&(c.head.comment+=String.fromCharCode(wb));while(wb&&i>q);if(512&c.flags&&(c.check=t(c.check,e,q,g)),i-=q,g+=q,wb)break a}else c.head&&(c.head.comment=null);c.mode=S;case S:if(512&c.flags){for(;16>n;){if(0===i)break a;i--,m+=e[g++]<>9&1,c.head.done=!0),a.adler=c.check=0,c.mode=V;break;case T:for(;32>n;){if(0===i)break a;i--,m+=e[g++]<>>=7&n,n-=7&n,c.mode=ib;break}for(;3>n;){if(0===i)break a;i--,m+=e[g++]<>>=1,n-=1,3&m){case 0:c.mode=X;break;case 1:if(k(c),c.mode=bb,b===B){m>>>=2,n-=2;break a}break;case 2:c.mode=$;break;case 3:a.msg="invalid block type",c.mode=lb}m>>>=2,n-=2;break;case X:for(m>>>=7&n,n-=7&n;32>n;){if(0===i)break a;i--,m+=e[g++]<>>16^65535)){a.msg="invalid stored block lengths",c.mode=lb;break}if(c.length=65535&m,m=0,n=0,c.mode=Y,b===B)break a;case Y:c.mode=Z;case Z:if(q=c.length){if(q>i&&(q=i),q>j&&(q=j),0===q)break a;r.arraySet(f,e,g,q,h),i-=q,g+=q,j-=q,h+=q,c.length-=q;break}c.mode=V;break;case $:for(;14>n;){if(0===i)break a;i--,m+=e[g++]<>>=5,n-=5,c.ndist=(31&m)+1,m>>>=5,n-=5,c.ncode=(15&m)+4,m>>>=4,n-=4,c.nlen>286||c.ndist>30){a.msg="too many length or distance symbols",c.mode=lb;break}c.have=0,c.mode=_;case _:for(;c.haven;){if(0===i)break a;i--,m+=e[g++]<>>=3,n-=3}for(;c.have<19;)c.lens[Cb[c.have++]]=0;if(c.lencode=c.lendyn,c.lenbits=7,yb={bits:c.lenbits},xb=v(w,c.lens,0,19,c.lencode,0,c.work,yb),c.lenbits=yb.bits,xb){a.msg="invalid code lengths set",c.mode=lb;break}c.have=0,c.mode=ab;case ab:for(;c.have>>24,rb=Ab>>>16&255,sb=65535&Ab,!(n>=qb);){if(0===i)break a;i--,m+=e[g++]<sb)m>>>=qb,n-=qb,c.lens[c.have++]=sb;else{if(16===sb){for(zb=qb+2;zb>n;){if(0===i)break a;i--,m+=e[g++]<>>=qb,n-=qb,0===c.have){a.msg="invalid bit length repeat",c.mode=lb;break}wb=c.lens[c.have-1],q=3+(3&m),m>>>=2,n-=2}else if(17===sb){for(zb=qb+3;zb>n;){if(0===i)break a;i--,m+=e[g++]<>>=qb,n-=qb,wb=0,q=3+(7&m),m>>>=3,n-=3}else{for(zb=qb+7;zb>n;){if(0===i)break a;i--,m+=e[g++]<>>=qb,n-=qb,wb=0,q=11+(127&m),m>>>=7,n-=7}if(c.have+q>c.nlen+c.ndist){a.msg="invalid bit length repeat",c.mode=lb;break}for(;q--;)c.lens[c.have++]=wb}}if(c.mode===lb)break;if(0===c.lens[256]){a.msg="invalid code -- missing end-of-block",c.mode=lb;break}if(c.lenbits=9,yb={bits:c.lenbits},xb=v(x,c.lens,0,c.nlen,c.lencode,0,c.work,yb),c.lenbits=yb.bits,xb){a.msg="invalid literal/lengths set",c.mode=lb;break}if(c.distbits=6,c.distcode=c.distdyn,yb={bits:c.distbits},xb=v(y,c.lens,c.nlen,c.ndist,c.distcode,0,c.work,yb),c.distbits=yb.bits,xb){a.msg="invalid distances set",c.mode=lb;break}if(c.mode=bb,b===B)break a;case bb:c.mode=cb;case cb:if(i>=6&&j>=258){a.next_out=h,a.avail_out=j,a.next_in=g,a.avail_in=i,c.hold=m,c.bits=n,u(a,p),h=a.next_out,f=a.output,j=a.avail_out,g=a.next_in,e=a.input,i=a.avail_in,m=c.hold,n=c.bits,c.mode===V&&(c.back=-1); -break}for(c.back=0;Ab=c.lencode[m&(1<>>24,rb=Ab>>>16&255,sb=65535&Ab,!(n>=qb);){if(0===i)break a;i--,m+=e[g++]<>tb)],qb=Ab>>>24,rb=Ab>>>16&255,sb=65535&Ab,!(n>=tb+qb);){if(0===i)break a;i--,m+=e[g++]<>>=tb,n-=tb,c.back+=tb}if(m>>>=qb,n-=qb,c.back+=qb,c.length=sb,0===rb){c.mode=hb;break}if(32&rb){c.back=-1,c.mode=V;break}if(64&rb){a.msg="invalid literal/length code",c.mode=lb;break}c.extra=15&rb,c.mode=db;case db:if(c.extra){for(zb=c.extra;zb>n;){if(0===i)break a;i--,m+=e[g++]<>>=c.extra,n-=c.extra,c.back+=c.extra}c.was=c.length,c.mode=eb;case eb:for(;Ab=c.distcode[m&(1<>>24,rb=Ab>>>16&255,sb=65535&Ab,!(n>=qb);){if(0===i)break a;i--,m+=e[g++]<>tb)],qb=Ab>>>24,rb=Ab>>>16&255,sb=65535&Ab,!(n>=tb+qb);){if(0===i)break a;i--,m+=e[g++]<>>=tb,n-=tb,c.back+=tb}if(m>>>=qb,n-=qb,c.back+=qb,64&rb){a.msg="invalid distance code",c.mode=lb;break}c.offset=sb,c.extra=15&rb,c.mode=fb;case fb:if(c.extra){for(zb=c.extra;zb>n;){if(0===i)break a;i--,m+=e[g++]<>>=c.extra,n-=c.extra,c.back+=c.extra}if(c.offset>c.dmax){a.msg="invalid distance too far back",c.mode=lb;break}c.mode=gb;case gb:if(0===j)break a;if(q=p-j,c.offset>q){if(q=c.offset-q,q>c.whave&&c.sane){a.msg="invalid distance too far back",c.mode=lb;break}q>c.wnext?(q-=c.wnext,ob=c.wsize-q):ob=c.wnext-q,q>c.length&&(q=c.length),pb=c.window}else pb=f,ob=h-c.offset,q=c.length;q>j&&(q=j),j-=q,c.length-=q;do f[h++]=pb[ob++];while(--q);0===c.length&&(c.mode=cb);break;case hb:if(0===j)break a;f[h++]=c.length,j--,c.mode=cb;break;case ib:if(c.wrap){for(;32>n;){if(0===i)break a;i--,m|=e[g++]<n;){if(0===i)break a;i--,m+=e[g++]<=D;D++)P[D]=0;for(E=0;o>E;E++)P[b[n+E]]++;for(H=C,G=d;G>=1&&0===P[G];G--);if(H>G&&(H=G),0===G)return p[q++]=20971520,p[q++]=20971520,s.bits=1,0;for(F=1;G>F&&0===P[F];F++);for(F>H&&(H=F),K=1,D=1;d>=D;D++)if(K<<=1,K-=P[D],0>K)return-1;if(K>0&&(a===g||1!==G))return-1;for(Q[1]=0,D=1;d>D;D++)Q[D+1]=Q[D]+P[D];for(E=0;o>E;E++)0!==b[n+E]&&(r[Q[b[n+E]]++]=E);if(a===g?(N=R=r,y=19):a===h?(N=j,O-=257,R=k,S-=257,y=256):(N=l,R=m,y=-1),M=0,E=0,D=F,x=q,I=H,J=0,v=-1,L=1<e||a===i&&L>f)return 1;for(var T=0;;){T++,z=D-J,r[E]y?(A=R[S+r[E]],B=N[O+r[E]]):(A=96,B=0),t=1<>J)+u]=z<<24|A<<16|B|0;while(0!==u);for(t=1<>=1;if(0!==t?(M&=t-1,M+=t):M=0,E++,0===--P[D]){if(D===G)break;D=b[n+r[E]]}if(D>H&&(M&w)!==v){for(0===J&&(J=H),x+=F,I=D-J,K=1<I+J&&(K-=P[I+J],!(0>=K));)I++,K<<=1;if(L+=1<e||a===i&&L>f)return 1;v=M&w,p[v]=H<<24|I<<16|x-q|0}}return 0!==M&&(p[x+M]=D-J<<24|64<<16|0),s.bits=H,0}},{"../utils/common":27}],37:[function(a,b){"use strict";b.exports={2:"need dictionary",1:"stream end",0:"","-1":"file error","-2":"stream error","-3":"data error","-4":"insufficient memory","-5":"buffer error","-6":"incompatible version"}},{}],38:[function(a,b,c){"use strict";function d(a){for(var b=a.length;--b>=0;)a[b]=0}function e(a){return 256>a?gb[a]:gb[256+(a>>>7)]}function f(a,b){a.pending_buf[a.pending++]=255&b,a.pending_buf[a.pending++]=b>>>8&255}function g(a,b,c){a.bi_valid>V-c?(a.bi_buf|=b<>V-a.bi_valid,a.bi_valid+=c-V):(a.bi_buf|=b<>>=1,c<<=1;while(--b>0);return c>>>1}function j(a){16===a.bi_valid?(f(a,a.bi_buf),a.bi_buf=0,a.bi_valid=0):a.bi_valid>=8&&(a.pending_buf[a.pending++]=255&a.bi_buf,a.bi_buf>>=8,a.bi_valid-=8)}function k(a,b){var c,d,e,f,g,h,i=b.dyn_tree,j=b.max_code,k=b.stat_desc.static_tree,l=b.stat_desc.has_stree,m=b.stat_desc.extra_bits,n=b.stat_desc.extra_base,o=b.stat_desc.max_length,p=0;for(f=0;U>=f;f++)a.bl_count[f]=0;for(i[2*a.heap[a.heap_max]+1]=0,c=a.heap_max+1;T>c;c++)d=a.heap[c],f=i[2*i[2*d+1]+1]+1,f>o&&(f=o,p++),i[2*d+1]=f,d>j||(a.bl_count[f]++,g=0,d>=n&&(g=m[d-n]),h=i[2*d],a.opt_len+=h*(f+g),l&&(a.static_len+=h*(k[2*d+1]+g)));if(0!==p){do{for(f=o-1;0===a.bl_count[f];)f--;a.bl_count[f]--,a.bl_count[f+1]+=2,a.bl_count[o]--,p-=2}while(p>0);for(f=o;0!==f;f--)for(d=a.bl_count[f];0!==d;)e=a.heap[--c],e>j||(i[2*e+1]!==f&&(a.opt_len+=(f-i[2*e+1])*i[2*e],i[2*e+1]=f),d--)}}function l(a,b,c){var d,e,f=new Array(U+1),g=0;for(d=1;U>=d;d++)f[d]=g=g+c[d-1]<<1;for(e=0;b>=e;e++){var h=a[2*e+1];0!==h&&(a[2*e]=i(f[h]++,h))}}function m(){var a,b,c,d,e,f=new Array(U+1);for(c=0,d=0;O-1>d;d++)for(ib[d]=c,a=0;a<1<<_[d];a++)hb[c++]=d;for(hb[c-1]=d,e=0,d=0;16>d;d++)for(jb[d]=e,a=0;a<1<>=7;R>d;d++)for(jb[d]=e<<7,a=0;a<1<=b;b++)f[b]=0;for(a=0;143>=a;)eb[2*a+1]=8,a++,f[8]++;for(;255>=a;)eb[2*a+1]=9,a++,f[9]++;for(;279>=a;)eb[2*a+1]=7,a++,f[7]++;for(;287>=a;)eb[2*a+1]=8,a++,f[8]++;for(l(eb,Q+1,f),a=0;R>a;a++)fb[2*a+1]=5,fb[2*a]=i(a,5);kb=new nb(eb,_,P+1,Q,U),lb=new nb(fb,ab,0,R,U),mb=new nb(new Array(0),bb,0,S,W)}function n(a){var b;for(b=0;Q>b;b++)a.dyn_ltree[2*b]=0;for(b=0;R>b;b++)a.dyn_dtree[2*b]=0;for(b=0;S>b;b++)a.bl_tree[2*b]=0;a.dyn_ltree[2*X]=1,a.opt_len=a.static_len=0,a.last_lit=a.matches=0}function o(a){a.bi_valid>8?f(a,a.bi_buf):a.bi_valid>0&&(a.pending_buf[a.pending++]=a.bi_buf),a.bi_buf=0,a.bi_valid=0}function p(a,b,c,d){o(a),d&&(f(a,c),f(a,~c)),E.arraySet(a.pending_buf,a.window,b,c,a.pending),a.pending+=c}function q(a,b,c,d){var e=2*b,f=2*c;return a[e]c;c++)0!==f[2*c]?(a.heap[++a.heap_len]=j=c,a.depth[c]=0):f[2*c+1]=0;for(;a.heap_len<2;)e=a.heap[++a.heap_len]=2>j?++j:0,f[2*e]=1,a.depth[e]=0,a.opt_len--,h&&(a.static_len-=g[2*e+1]);for(b.max_code=j,c=a.heap_len>>1;c>=1;c--)r(a,f,c);e=i;do c=a.heap[1],a.heap[1]=a.heap[a.heap_len--],r(a,f,1),d=a.heap[1],a.heap[--a.heap_max]=c,a.heap[--a.heap_max]=d,f[2*e]=f[2*c]+f[2*d],a.depth[e]=(a.depth[c]>=a.depth[d]?a.depth[c]:a.depth[d])+1,f[2*c+1]=f[2*d+1]=e,a.heap[1]=e++,r(a,f,1);while(a.heap_len>=2);a.heap[--a.heap_max]=a.heap[1],k(a,b),l(f,j,a.bl_count)}function u(a,b,c){var d,e,f=-1,g=b[1],h=0,i=7,j=4;for(0===g&&(i=138,j=3),b[2*(c+1)+1]=65535,d=0;c>=d;d++)e=g,g=b[2*(d+1)+1],++hh?a.bl_tree[2*e]+=h:0!==e?(e!==f&&a.bl_tree[2*e]++,a.bl_tree[2*Y]++):10>=h?a.bl_tree[2*Z]++:a.bl_tree[2*$]++,h=0,f=e,0===g?(i=138,j=3):e===g?(i=6,j=3):(i=7,j=4))}function v(a,b,c){var d,e,f=-1,i=b[1],j=0,k=7,l=4;for(0===i&&(k=138,l=3),d=0;c>=d;d++)if(e=i,i=b[2*(d+1)+1],!(++jj){do h(a,e,a.bl_tree);while(0!==--j)}else 0!==e?(e!==f&&(h(a,e,a.bl_tree),j--),h(a,Y,a.bl_tree),g(a,j-3,2)):10>=j?(h(a,Z,a.bl_tree),g(a,j-3,3)):(h(a,$,a.bl_tree),g(a,j-11,7));j=0,f=e,0===i?(k=138,l=3):e===i?(k=6,l=3):(k=7,l=4)}}function w(a){var b;for(u(a,a.dyn_ltree,a.l_desc.max_code),u(a,a.dyn_dtree,a.d_desc.max_code),t(a,a.bl_desc),b=S-1;b>=3&&0===a.bl_tree[2*cb[b]+1];b--);return a.opt_len+=3*(b+1)+5+5+4,b}function x(a,b,c,d){var e;for(g(a,b-257,5),g(a,c-1,5),g(a,d-4,4),e=0;d>e;e++)g(a,a.bl_tree[2*cb[e]+1],3);v(a,a.dyn_ltree,b-1),v(a,a.dyn_dtree,c-1)}function y(a){var b,c=4093624447;for(b=0;31>=b;b++,c>>>=1)if(1&c&&0!==a.dyn_ltree[2*b])return G;if(0!==a.dyn_ltree[18]||0!==a.dyn_ltree[20]||0!==a.dyn_ltree[26])return H;for(b=32;P>b;b++)if(0!==a.dyn_ltree[2*b])return H;return G}function z(a){pb||(m(),pb=!0),a.l_desc=new ob(a.dyn_ltree,kb),a.d_desc=new ob(a.dyn_dtree,lb),a.bl_desc=new ob(a.bl_tree,mb),a.bi_buf=0,a.bi_valid=0,n(a)}function A(a,b,c,d){g(a,(J<<1)+(d?1:0),3),p(a,b,c,!0)}function B(a){g(a,K<<1,3),h(a,X,eb),j(a)}function C(a,b,c,d){var e,f,h=0;a.level>0?(a.strm.data_type===I&&(a.strm.data_type=y(a)),t(a,a.l_desc),t(a,a.d_desc),h=w(a),e=a.opt_len+3+7>>>3,f=a.static_len+3+7>>>3,e>=f&&(e=f)):e=f=c+5,e>=c+4&&-1!==b?A(a,b,c,d):a.strategy===F||f===e?(g(a,(K<<1)+(d?1:0),3),s(a,eb,fb)):(g(a,(L<<1)+(d?1:0),3),x(a,a.l_desc.max_code+1,a.d_desc.max_code+1,h+1),s(a,a.dyn_ltree,a.dyn_dtree)),n(a),d&&o(a)}function D(a,b,c){return a.pending_buf[a.d_buf+2*a.last_lit]=b>>>8&255,a.pending_buf[a.d_buf+2*a.last_lit+1]=255&b,a.pending_buf[a.l_buf+a.last_lit]=255&c,a.last_lit++,0===b?a.dyn_ltree[2*c]++:(a.matches++,b--,a.dyn_ltree[2*(hb[c]+P+1)]++,a.dyn_dtree[2*e(b)]++),a.last_lit===a.lit_bufsize-1}var E=a("../utils/common"),F=4,G=0,H=1,I=2,J=0,K=1,L=2,M=3,N=258,O=29,P=256,Q=P+1+O,R=30,S=19,T=2*Q+1,U=15,V=16,W=7,X=256,Y=16,Z=17,$=18,_=[0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0],ab=[0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13],bb=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7],cb=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15],db=512,eb=new Array(2*(Q+2));d(eb);var fb=new Array(2*R);d(fb);var gb=new Array(db);d(gb);var hb=new Array(N-M+1);d(hb);var ib=new Array(O);d(ib);var jb=new Array(R);d(jb);var kb,lb,mb,nb=function(a,b,c,d,e){this.static_tree=a,this.extra_bits=b,this.extra_base=c,this.elems=d,this.max_length=e,this.has_stree=a&&a.length},ob=function(a,b){this.dyn_tree=a,this.max_code=0,this.stat_desc=b},pb=!1;c._tr_init=z,c._tr_stored_block=A,c._tr_flush_block=C,c._tr_tally=D,c._tr_align=B},{"../utils/common":27}],39:[function(a,b){"use strict";function c(){this.input=null,this.next_in=0,this.avail_in=0,this.total_in=0,this.output=null,this.next_out=0,this.avail_out=0,this.total_out=0,this.msg="",this.state=null,this.data_type=2,this.adler=0}b.exports=c},{}]},{},[9])(9)}); \ No newline at end of file diff --git a/master/assets/pdfmake-1.11.3/pdfmake.js b/master/assets/pdfmake-1.11.3/pdfmake.js deleted file mode 100644 index c6041b90c..000000000 --- a/master/assets/pdfmake-1.11.3/pdfmake.js +++ /dev/null @@ -1,50468 +0,0 @@ -/*! pdfmake v0.1.36, @license MIT, @link http://pdfmake.org */ -(function webpackUniversalModuleDefinition(root, factory) { - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(); - else if(typeof define === 'function' && define.amd) - define([], factory); - else { - var a = factory(); - for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i]; - } -})(typeof self !== 'undefined' ? self : this, function() { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) { -/******/ return installedModules[moduleId].exports; -/******/ } -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 122); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -function isString(variable) { - return typeof variable === 'string' || variable instanceof String; -} - -function isNumber(variable) { - return typeof variable === 'number' || variable instanceof Number; -} - -function isBoolean(variable) { - return typeof variable === 'boolean'; -} - -function isArray(variable) { - return Array.isArray(variable); -} - -function isFunction(variable) { - return typeof variable === 'function'; -} - -function isObject(variable) { - return variable !== null && typeof variable === 'object'; -} - -function isNull(variable) { - return variable === null; -} - -function isUndefined(variable) { - return variable === undefined; -} - -function pack() { - var result = {}; - - for (var i = 0, l = arguments.length; i < l; i++) { - var obj = arguments[i]; - - if (obj) { - for (var key in obj) { - if (obj.hasOwnProperty(key)) { - result[key] = obj[key]; - } - } - } - } - - return result; -} - -function offsetVector(vector, x, y) { - switch (vector.type) { - case 'ellipse': - case 'rect': - vector.x += x; - vector.y += y; - break; - case 'line': - vector.x1 += x; - vector.x2 += x; - vector.y1 += y; - vector.y2 += y; - break; - case 'polyline': - for (var i = 0, l = vector.points.length; i < l; i++) { - vector.points[i].x += x; - vector.points[i].y += y; - } - break; - } -} - -function fontStringify(key, val) { - if (key === 'font') { - return 'font'; - } - return val; -} - -module.exports = { - isString: isString, - isNumber: isNumber, - isBoolean: isBoolean, - isArray: isArray, - isFunction: isFunction, - isObject: isObject, - isNull: isNull, - isUndefined: isUndefined, - pack: pack, - fontStringify: fontStringify, - offsetVector: offsetVector -}; - - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/* WEBPACK VAR INJECTION */(function(global) {/*! - * The buffer module from node.js, for the browser. - * - * @author Feross Aboukhadijeh - * @license MIT - */ -/* eslint-disable no-proto */ - - - -var base64 = __webpack_require__(124) -var ieee754 = __webpack_require__(125) -var isArray = __webpack_require__(76) - -exports.Buffer = Buffer -exports.SlowBuffer = SlowBuffer -exports.INSPECT_MAX_BYTES = 50 - -/** - * If `Buffer.TYPED_ARRAY_SUPPORT`: - * === true Use Uint8Array implementation (fastest) - * === false Use Object implementation (most compatible, even IE6) - * - * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+, - * Opera 11.6+, iOS 4.2+. - * - * Due to various browser bugs, sometimes the Object implementation will be used even - * when the browser supports typed arrays. - * - * Note: - * - * - Firefox 4-29 lacks support for adding new properties to `Uint8Array` instances, - * See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438. - * - * - Chrome 9-10 is missing the `TypedArray.prototype.subarray` function. - * - * - IE10 has a broken `TypedArray.prototype.subarray` function which returns arrays of - * incorrect length in some situations. - - * We detect these buggy browsers and set `Buffer.TYPED_ARRAY_SUPPORT` to `false` so they - * get the Object implementation, which is slower but behaves correctly. - */ -Buffer.TYPED_ARRAY_SUPPORT = global.TYPED_ARRAY_SUPPORT !== undefined - ? global.TYPED_ARRAY_SUPPORT - : typedArraySupport() - -/* - * Export kMaxLength after typed array support is determined. - */ -exports.kMaxLength = kMaxLength() - -function typedArraySupport () { - try { - var arr = new Uint8Array(1) - arr.__proto__ = {__proto__: Uint8Array.prototype, foo: function () { return 42 }} - return arr.foo() === 42 && // typed array instances can be augmented - typeof arr.subarray === 'function' && // chrome 9-10 lack `subarray` - arr.subarray(1, 1).byteLength === 0 // ie10 has broken `subarray` - } catch (e) { - return false - } -} - -function kMaxLength () { - return Buffer.TYPED_ARRAY_SUPPORT - ? 0x7fffffff - : 0x3fffffff -} - -function createBuffer (that, length) { - if (kMaxLength() < length) { - throw new RangeError('Invalid typed array length') - } - if (Buffer.TYPED_ARRAY_SUPPORT) { - // Return an augmented `Uint8Array` instance, for best performance - that = new Uint8Array(length) - that.__proto__ = Buffer.prototype - } else { - // Fallback: Return an object instance of the Buffer class - if (that === null) { - that = new Buffer(length) - } - that.length = length - } - - return that -} - -/** - * The Buffer constructor returns instances of `Uint8Array` that have their - * prototype changed to `Buffer.prototype`. Furthermore, `Buffer` is a subclass of - * `Uint8Array`, so the returned instances will have all the node `Buffer` methods - * and the `Uint8Array` methods. Square bracket notation works as expected -- it - * returns a single octet. - * - * The `Uint8Array` prototype remains unmodified. - */ - -function Buffer (arg, encodingOrOffset, length) { - if (!Buffer.TYPED_ARRAY_SUPPORT && !(this instanceof Buffer)) { - return new Buffer(arg, encodingOrOffset, length) - } - - // Common case. - if (typeof arg === 'number') { - if (typeof encodingOrOffset === 'string') { - throw new Error( - 'If encoding is specified then the first argument must be a string' - ) - } - return allocUnsafe(this, arg) - } - return from(this, arg, encodingOrOffset, length) -} - -Buffer.poolSize = 8192 // not used by this implementation - -// TODO: Legacy, not needed anymore. Remove in next major version. -Buffer._augment = function (arr) { - arr.__proto__ = Buffer.prototype - return arr -} - -function from (that, value, encodingOrOffset, length) { - if (typeof value === 'number') { - throw new TypeError('"value" argument must not be a number') - } - - if (typeof ArrayBuffer !== 'undefined' && value instanceof ArrayBuffer) { - return fromArrayBuffer(that, value, encodingOrOffset, length) - } - - if (typeof value === 'string') { - return fromString(that, value, encodingOrOffset) - } - - return fromObject(that, value) -} - -/** - * Functionally equivalent to Buffer(arg, encoding) but throws a TypeError - * if value is a number. - * Buffer.from(str[, encoding]) - * Buffer.from(array) - * Buffer.from(buffer) - * Buffer.from(arrayBuffer[, byteOffset[, length]]) - **/ -Buffer.from = function (value, encodingOrOffset, length) { - return from(null, value, encodingOrOffset, length) -} - -if (Buffer.TYPED_ARRAY_SUPPORT) { - Buffer.prototype.__proto__ = Uint8Array.prototype - Buffer.__proto__ = Uint8Array - if (typeof Symbol !== 'undefined' && Symbol.species && - Buffer[Symbol.species] === Buffer) { - // Fix subarray() in ES2016. See: https://github.com/feross/buffer/pull/97 - Object.defineProperty(Buffer, Symbol.species, { - value: null, - configurable: true - }) - } -} - -function assertSize (size) { - if (typeof size !== 'number') { - throw new TypeError('"size" argument must be a number') - } else if (size < 0) { - throw new RangeError('"size" argument must not be negative') - } -} - -function alloc (that, size, fill, encoding) { - assertSize(size) - if (size <= 0) { - return createBuffer(that, size) - } - if (fill !== undefined) { - // Only pay attention to encoding if it's a string. This - // prevents accidentally sending in a number that would - // be interpretted as a start offset. - return typeof encoding === 'string' - ? createBuffer(that, size).fill(fill, encoding) - : createBuffer(that, size).fill(fill) - } - return createBuffer(that, size) -} - -/** - * Creates a new filled Buffer instance. - * alloc(size[, fill[, encoding]]) - **/ -Buffer.alloc = function (size, fill, encoding) { - return alloc(null, size, fill, encoding) -} - -function allocUnsafe (that, size) { - assertSize(size) - that = createBuffer(that, size < 0 ? 0 : checked(size) | 0) - if (!Buffer.TYPED_ARRAY_SUPPORT) { - for (var i = 0; i < size; ++i) { - that[i] = 0 - } - } - return that -} - -/** - * Equivalent to Buffer(num), by default creates a non-zero-filled Buffer instance. - * */ -Buffer.allocUnsafe = function (size) { - return allocUnsafe(null, size) -} -/** - * Equivalent to SlowBuffer(num), by default creates a non-zero-filled Buffer instance. - */ -Buffer.allocUnsafeSlow = function (size) { - return allocUnsafe(null, size) -} - -function fromString (that, string, encoding) { - if (typeof encoding !== 'string' || encoding === '') { - encoding = 'utf8' - } - - if (!Buffer.isEncoding(encoding)) { - throw new TypeError('"encoding" must be a valid string encoding') - } - - var length = byteLength(string, encoding) | 0 - that = createBuffer(that, length) - - var actual = that.write(string, encoding) - - if (actual !== length) { - // Writing a hex string, for example, that contains invalid characters will - // cause everything after the first invalid character to be ignored. (e.g. - // 'abxxcd' will be treated as 'ab') - that = that.slice(0, actual) - } - - return that -} - -function fromArrayLike (that, array) { - var length = array.length < 0 ? 0 : checked(array.length) | 0 - that = createBuffer(that, length) - for (var i = 0; i < length; i += 1) { - that[i] = array[i] & 255 - } - return that -} - -function fromArrayBuffer (that, array, byteOffset, length) { - array.byteLength // this throws if `array` is not a valid ArrayBuffer - - if (byteOffset < 0 || array.byteLength < byteOffset) { - throw new RangeError('\'offset\' is out of bounds') - } - - if (array.byteLength < byteOffset + (length || 0)) { - throw new RangeError('\'length\' is out of bounds') - } - - if (byteOffset === undefined && length === undefined) { - array = new Uint8Array(array) - } else if (length === undefined) { - array = new Uint8Array(array, byteOffset) - } else { - array = new Uint8Array(array, byteOffset, length) - } - - if (Buffer.TYPED_ARRAY_SUPPORT) { - // Return an augmented `Uint8Array` instance, for best performance - that = array - that.__proto__ = Buffer.prototype - } else { - // Fallback: Return an object instance of the Buffer class - that = fromArrayLike(that, array) - } - return that -} - -function fromObject (that, obj) { - if (Buffer.isBuffer(obj)) { - var len = checked(obj.length) | 0 - that = createBuffer(that, len) - - if (that.length === 0) { - return that - } - - obj.copy(that, 0, 0, len) - return that - } - - if (obj) { - if ((typeof ArrayBuffer !== 'undefined' && - obj.buffer instanceof ArrayBuffer) || 'length' in obj) { - if (typeof obj.length !== 'number' || isnan(obj.length)) { - return createBuffer(that, 0) - } - return fromArrayLike(that, obj) - } - - if (obj.type === 'Buffer' && isArray(obj.data)) { - return fromArrayLike(that, obj.data) - } - } - - throw new TypeError('First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.') -} - -function checked (length) { - // Note: cannot use `length < kMaxLength()` here because that fails when - // length is NaN (which is otherwise coerced to zero.) - if (length >= kMaxLength()) { - throw new RangeError('Attempt to allocate Buffer larger than maximum ' + - 'size: 0x' + kMaxLength().toString(16) + ' bytes') - } - return length | 0 -} - -function SlowBuffer (length) { - if (+length != length) { // eslint-disable-line eqeqeq - length = 0 - } - return Buffer.alloc(+length) -} - -Buffer.isBuffer = function isBuffer (b) { - return !!(b != null && b._isBuffer) -} - -Buffer.compare = function compare (a, b) { - if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) { - throw new TypeError('Arguments must be Buffers') - } - - if (a === b) return 0 - - var x = a.length - var y = b.length - - for (var i = 0, len = Math.min(x, y); i < len; ++i) { - if (a[i] !== b[i]) { - x = a[i] - y = b[i] - break - } - } - - if (x < y) return -1 - if (y < x) return 1 - return 0 -} - -Buffer.isEncoding = function isEncoding (encoding) { - switch (String(encoding).toLowerCase()) { - case 'hex': - case 'utf8': - case 'utf-8': - case 'ascii': - case 'latin1': - case 'binary': - case 'base64': - case 'ucs2': - case 'ucs-2': - case 'utf16le': - case 'utf-16le': - return true - default: - return false - } -} - -Buffer.concat = function concat (list, length) { - if (!isArray(list)) { - throw new TypeError('"list" argument must be an Array of Buffers') - } - - if (list.length === 0) { - return Buffer.alloc(0) - } - - var i - if (length === undefined) { - length = 0 - for (i = 0; i < list.length; ++i) { - length += list[i].length - } - } - - var buffer = Buffer.allocUnsafe(length) - var pos = 0 - for (i = 0; i < list.length; ++i) { - var buf = list[i] - if (!Buffer.isBuffer(buf)) { - throw new TypeError('"list" argument must be an Array of Buffers') - } - buf.copy(buffer, pos) - pos += buf.length - } - return buffer -} - -function byteLength (string, encoding) { - if (Buffer.isBuffer(string)) { - return string.length - } - if (typeof ArrayBuffer !== 'undefined' && typeof ArrayBuffer.isView === 'function' && - (ArrayBuffer.isView(string) || string instanceof ArrayBuffer)) { - return string.byteLength - } - if (typeof string !== 'string') { - string = '' + string - } - - var len = string.length - if (len === 0) return 0 - - // Use a for loop to avoid recursion - var loweredCase = false - for (;;) { - switch (encoding) { - case 'ascii': - case 'latin1': - case 'binary': - return len - case 'utf8': - case 'utf-8': - case undefined: - return utf8ToBytes(string).length - case 'ucs2': - case 'ucs-2': - case 'utf16le': - case 'utf-16le': - return len * 2 - case 'hex': - return len >>> 1 - case 'base64': - return base64ToBytes(string).length - default: - if (loweredCase) return utf8ToBytes(string).length // assume utf8 - encoding = ('' + encoding).toLowerCase() - loweredCase = true - } - } -} -Buffer.byteLength = byteLength - -function slowToString (encoding, start, end) { - var loweredCase = false - - // No need to verify that "this.length <= MAX_UINT32" since it's a read-only - // property of a typed array. - - // This behaves neither like String nor Uint8Array in that we set start/end - // to their upper/lower bounds if the value passed is out of range. - // undefined is handled specially as per ECMA-262 6th Edition, - // Section 13.3.3.7 Runtime Semantics: KeyedBindingInitialization. - if (start === undefined || start < 0) { - start = 0 - } - // Return early if start > this.length. Done here to prevent potential uint32 - // coercion fail below. - if (start > this.length) { - return '' - } - - if (end === undefined || end > this.length) { - end = this.length - } - - if (end <= 0) { - return '' - } - - // Force coersion to uint32. This will also coerce falsey/NaN values to 0. - end >>>= 0 - start >>>= 0 - - if (end <= start) { - return '' - } - - if (!encoding) encoding = 'utf8' - - while (true) { - switch (encoding) { - case 'hex': - return hexSlice(this, start, end) - - case 'utf8': - case 'utf-8': - return utf8Slice(this, start, end) - - case 'ascii': - return asciiSlice(this, start, end) - - case 'latin1': - case 'binary': - return latin1Slice(this, start, end) - - case 'base64': - return base64Slice(this, start, end) - - case 'ucs2': - case 'ucs-2': - case 'utf16le': - case 'utf-16le': - return utf16leSlice(this, start, end) - - default: - if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding) - encoding = (encoding + '').toLowerCase() - loweredCase = true - } - } -} - -// The property is used by `Buffer.isBuffer` and `is-buffer` (in Safari 5-7) to detect -// Buffer instances. -Buffer.prototype._isBuffer = true - -function swap (b, n, m) { - var i = b[n] - b[n] = b[m] - b[m] = i -} - -Buffer.prototype.swap16 = function swap16 () { - var len = this.length - if (len % 2 !== 0) { - throw new RangeError('Buffer size must be a multiple of 16-bits') - } - for (var i = 0; i < len; i += 2) { - swap(this, i, i + 1) - } - return this -} - -Buffer.prototype.swap32 = function swap32 () { - var len = this.length - if (len % 4 !== 0) { - throw new RangeError('Buffer size must be a multiple of 32-bits') - } - for (var i = 0; i < len; i += 4) { - swap(this, i, i + 3) - swap(this, i + 1, i + 2) - } - return this -} - -Buffer.prototype.swap64 = function swap64 () { - var len = this.length - if (len % 8 !== 0) { - throw new RangeError('Buffer size must be a multiple of 64-bits') - } - for (var i = 0; i < len; i += 8) { - swap(this, i, i + 7) - swap(this, i + 1, i + 6) - swap(this, i + 2, i + 5) - swap(this, i + 3, i + 4) - } - return this -} - -Buffer.prototype.toString = function toString () { - var length = this.length | 0 - if (length === 0) return '' - if (arguments.length === 0) return utf8Slice(this, 0, length) - return slowToString.apply(this, arguments) -} - -Buffer.prototype.equals = function equals (b) { - if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer') - if (this === b) return true - return Buffer.compare(this, b) === 0 -} - -Buffer.prototype.inspect = function inspect () { - var str = '' - var max = exports.INSPECT_MAX_BYTES - if (this.length > 0) { - str = this.toString('hex', 0, max).match(/.{2}/g).join(' ') - if (this.length > max) str += ' ... ' - } - return '' -} - -Buffer.prototype.compare = function compare (target, start, end, thisStart, thisEnd) { - if (!Buffer.isBuffer(target)) { - throw new TypeError('Argument must be a Buffer') - } - - if (start === undefined) { - start = 0 - } - if (end === undefined) { - end = target ? target.length : 0 - } - if (thisStart === undefined) { - thisStart = 0 - } - if (thisEnd === undefined) { - thisEnd = this.length - } - - if (start < 0 || end > target.length || thisStart < 0 || thisEnd > this.length) { - throw new RangeError('out of range index') - } - - if (thisStart >= thisEnd && start >= end) { - return 0 - } - if (thisStart >= thisEnd) { - return -1 - } - if (start >= end) { - return 1 - } - - start >>>= 0 - end >>>= 0 - thisStart >>>= 0 - thisEnd >>>= 0 - - if (this === target) return 0 - - var x = thisEnd - thisStart - var y = end - start - var len = Math.min(x, y) - - var thisCopy = this.slice(thisStart, thisEnd) - var targetCopy = target.slice(start, end) - - for (var i = 0; i < len; ++i) { - if (thisCopy[i] !== targetCopy[i]) { - x = thisCopy[i] - y = targetCopy[i] - break - } - } - - if (x < y) return -1 - if (y < x) return 1 - return 0 -} - -// Finds either the first index of `val` in `buffer` at offset >= `byteOffset`, -// OR the last index of `val` in `buffer` at offset <= `byteOffset`. -// -// Arguments: -// - buffer - a Buffer to search -// - val - a string, Buffer, or number -// - byteOffset - an index into `buffer`; will be clamped to an int32 -// - encoding - an optional encoding, relevant is val is a string -// - dir - true for indexOf, false for lastIndexOf -function bidirectionalIndexOf (buffer, val, byteOffset, encoding, dir) { - // Empty buffer means no match - if (buffer.length === 0) return -1 - - // Normalize byteOffset - if (typeof byteOffset === 'string') { - encoding = byteOffset - byteOffset = 0 - } else if (byteOffset > 0x7fffffff) { - byteOffset = 0x7fffffff - } else if (byteOffset < -0x80000000) { - byteOffset = -0x80000000 - } - byteOffset = +byteOffset // Coerce to Number. - if (isNaN(byteOffset)) { - // byteOffset: it it's undefined, null, NaN, "foo", etc, search whole buffer - byteOffset = dir ? 0 : (buffer.length - 1) - } - - // Normalize byteOffset: negative offsets start from the end of the buffer - if (byteOffset < 0) byteOffset = buffer.length + byteOffset - if (byteOffset >= buffer.length) { - if (dir) return -1 - else byteOffset = buffer.length - 1 - } else if (byteOffset < 0) { - if (dir) byteOffset = 0 - else return -1 - } - - // Normalize val - if (typeof val === 'string') { - val = Buffer.from(val, encoding) - } - - // Finally, search either indexOf (if dir is true) or lastIndexOf - if (Buffer.isBuffer(val)) { - // Special case: looking for empty string/buffer always fails - if (val.length === 0) { - return -1 - } - return arrayIndexOf(buffer, val, byteOffset, encoding, dir) - } else if (typeof val === 'number') { - val = val & 0xFF // Search for a byte value [0-255] - if (Buffer.TYPED_ARRAY_SUPPORT && - typeof Uint8Array.prototype.indexOf === 'function') { - if (dir) { - return Uint8Array.prototype.indexOf.call(buffer, val, byteOffset) - } else { - return Uint8Array.prototype.lastIndexOf.call(buffer, val, byteOffset) - } - } - return arrayIndexOf(buffer, [ val ], byteOffset, encoding, dir) - } - - throw new TypeError('val must be string, number or Buffer') -} - -function arrayIndexOf (arr, val, byteOffset, encoding, dir) { - var indexSize = 1 - var arrLength = arr.length - var valLength = val.length - - if (encoding !== undefined) { - encoding = String(encoding).toLowerCase() - if (encoding === 'ucs2' || encoding === 'ucs-2' || - encoding === 'utf16le' || encoding === 'utf-16le') { - if (arr.length < 2 || val.length < 2) { - return -1 - } - indexSize = 2 - arrLength /= 2 - valLength /= 2 - byteOffset /= 2 - } - } - - function read (buf, i) { - if (indexSize === 1) { - return buf[i] - } else { - return buf.readUInt16BE(i * indexSize) - } - } - - var i - if (dir) { - var foundIndex = -1 - for (i = byteOffset; i < arrLength; i++) { - if (read(arr, i) === read(val, foundIndex === -1 ? 0 : i - foundIndex)) { - if (foundIndex === -1) foundIndex = i - if (i - foundIndex + 1 === valLength) return foundIndex * indexSize - } else { - if (foundIndex !== -1) i -= i - foundIndex - foundIndex = -1 - } - } - } else { - if (byteOffset + valLength > arrLength) byteOffset = arrLength - valLength - for (i = byteOffset; i >= 0; i--) { - var found = true - for (var j = 0; j < valLength; j++) { - if (read(arr, i + j) !== read(val, j)) { - found = false - break - } - } - if (found) return i - } - } - - return -1 -} - -Buffer.prototype.includes = function includes (val, byteOffset, encoding) { - return this.indexOf(val, byteOffset, encoding) !== -1 -} - -Buffer.prototype.indexOf = function indexOf (val, byteOffset, encoding) { - return bidirectionalIndexOf(this, val, byteOffset, encoding, true) -} - -Buffer.prototype.lastIndexOf = function lastIndexOf (val, byteOffset, encoding) { - return bidirectionalIndexOf(this, val, byteOffset, encoding, false) -} - -function hexWrite (buf, string, offset, length) { - offset = Number(offset) || 0 - var remaining = buf.length - offset - if (!length) { - length = remaining - } else { - length = Number(length) - if (length > remaining) { - length = remaining - } - } - - // must be an even number of digits - var strLen = string.length - if (strLen % 2 !== 0) throw new TypeError('Invalid hex string') - - if (length > strLen / 2) { - length = strLen / 2 - } - for (var i = 0; i < length; ++i) { - var parsed = parseInt(string.substr(i * 2, 2), 16) - if (isNaN(parsed)) return i - buf[offset + i] = parsed - } - return i -} - -function utf8Write (buf, string, offset, length) { - return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length) -} - -function asciiWrite (buf, string, offset, length) { - return blitBuffer(asciiToBytes(string), buf, offset, length) -} - -function latin1Write (buf, string, offset, length) { - return asciiWrite(buf, string, offset, length) -} - -function base64Write (buf, string, offset, length) { - return blitBuffer(base64ToBytes(string), buf, offset, length) -} - -function ucs2Write (buf, string, offset, length) { - return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length) -} - -Buffer.prototype.write = function write (string, offset, length, encoding) { - // Buffer#write(string) - if (offset === undefined) { - encoding = 'utf8' - length = this.length - offset = 0 - // Buffer#write(string, encoding) - } else if (length === undefined && typeof offset === 'string') { - encoding = offset - length = this.length - offset = 0 - // Buffer#write(string, offset[, length][, encoding]) - } else if (isFinite(offset)) { - offset = offset | 0 - if (isFinite(length)) { - length = length | 0 - if (encoding === undefined) encoding = 'utf8' - } else { - encoding = length - length = undefined - } - // legacy write(string, encoding, offset, length) - remove in v0.13 - } else { - throw new Error( - 'Buffer.write(string, encoding, offset[, length]) is no longer supported' - ) - } - - var remaining = this.length - offset - if (length === undefined || length > remaining) length = remaining - - if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) { - throw new RangeError('Attempt to write outside buffer bounds') - } - - if (!encoding) encoding = 'utf8' - - var loweredCase = false - for (;;) { - switch (encoding) { - case 'hex': - return hexWrite(this, string, offset, length) - - case 'utf8': - case 'utf-8': - return utf8Write(this, string, offset, length) - - case 'ascii': - return asciiWrite(this, string, offset, length) - - case 'latin1': - case 'binary': - return latin1Write(this, string, offset, length) - - case 'base64': - // Warning: maxLength not taken into account in base64Write - return base64Write(this, string, offset, length) - - case 'ucs2': - case 'ucs-2': - case 'utf16le': - case 'utf-16le': - return ucs2Write(this, string, offset, length) - - default: - if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding) - encoding = ('' + encoding).toLowerCase() - loweredCase = true - } - } -} - -Buffer.prototype.toJSON = function toJSON () { - return { - type: 'Buffer', - data: Array.prototype.slice.call(this._arr || this, 0) - } -} - -function base64Slice (buf, start, end) { - if (start === 0 && end === buf.length) { - return base64.fromByteArray(buf) - } else { - return base64.fromByteArray(buf.slice(start, end)) - } -} - -function utf8Slice (buf, start, end) { - end = Math.min(buf.length, end) - var res = [] - - var i = start - while (i < end) { - var firstByte = buf[i] - var codePoint = null - var bytesPerSequence = (firstByte > 0xEF) ? 4 - : (firstByte > 0xDF) ? 3 - : (firstByte > 0xBF) ? 2 - : 1 - - if (i + bytesPerSequence <= end) { - var secondByte, thirdByte, fourthByte, tempCodePoint - - switch (bytesPerSequence) { - case 1: - if (firstByte < 0x80) { - codePoint = firstByte - } - break - case 2: - secondByte = buf[i + 1] - if ((secondByte & 0xC0) === 0x80) { - tempCodePoint = (firstByte & 0x1F) << 0x6 | (secondByte & 0x3F) - if (tempCodePoint > 0x7F) { - codePoint = tempCodePoint - } - } - break - case 3: - secondByte = buf[i + 1] - thirdByte = buf[i + 2] - if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) { - tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | (thirdByte & 0x3F) - if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) { - codePoint = tempCodePoint - } - } - break - case 4: - secondByte = buf[i + 1] - thirdByte = buf[i + 2] - fourthByte = buf[i + 3] - if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) { - tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | (fourthByte & 0x3F) - if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) { - codePoint = tempCodePoint - } - } - } - } - - if (codePoint === null) { - // we did not generate a valid codePoint so insert a - // replacement char (U+FFFD) and advance only 1 byte - codePoint = 0xFFFD - bytesPerSequence = 1 - } else if (codePoint > 0xFFFF) { - // encode to utf16 (surrogate pair dance) - codePoint -= 0x10000 - res.push(codePoint >>> 10 & 0x3FF | 0xD800) - codePoint = 0xDC00 | codePoint & 0x3FF - } - - res.push(codePoint) - i += bytesPerSequence - } - - return decodeCodePointsArray(res) -} - -// Based on http://stackoverflow.com/a/22747272/680742, the browser with -// the lowest limit is Chrome, with 0x10000 args. -// We go 1 magnitude less, for safety -var MAX_ARGUMENTS_LENGTH = 0x1000 - -function decodeCodePointsArray (codePoints) { - var len = codePoints.length - if (len <= MAX_ARGUMENTS_LENGTH) { - return String.fromCharCode.apply(String, codePoints) // avoid extra slice() - } - - // Decode in chunks to avoid "call stack size exceeded". - var res = '' - var i = 0 - while (i < len) { - res += String.fromCharCode.apply( - String, - codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH) - ) - } - return res -} - -function asciiSlice (buf, start, end) { - var ret = '' - end = Math.min(buf.length, end) - - for (var i = start; i < end; ++i) { - ret += String.fromCharCode(buf[i] & 0x7F) - } - return ret -} - -function latin1Slice (buf, start, end) { - var ret = '' - end = Math.min(buf.length, end) - - for (var i = start; i < end; ++i) { - ret += String.fromCharCode(buf[i]) - } - return ret -} - -function hexSlice (buf, start, end) { - var len = buf.length - - if (!start || start < 0) start = 0 - if (!end || end < 0 || end > len) end = len - - var out = '' - for (var i = start; i < end; ++i) { - out += toHex(buf[i]) - } - return out -} - -function utf16leSlice (buf, start, end) { - var bytes = buf.slice(start, end) - var res = '' - for (var i = 0; i < bytes.length; i += 2) { - res += String.fromCharCode(bytes[i] + bytes[i + 1] * 256) - } - return res -} - -Buffer.prototype.slice = function slice (start, end) { - var len = this.length - start = ~~start - end = end === undefined ? len : ~~end - - if (start < 0) { - start += len - if (start < 0) start = 0 - } else if (start > len) { - start = len - } - - if (end < 0) { - end += len - if (end < 0) end = 0 - } else if (end > len) { - end = len - } - - if (end < start) end = start - - var newBuf - if (Buffer.TYPED_ARRAY_SUPPORT) { - newBuf = this.subarray(start, end) - newBuf.__proto__ = Buffer.prototype - } else { - var sliceLen = end - start - newBuf = new Buffer(sliceLen, undefined) - for (var i = 0; i < sliceLen; ++i) { - newBuf[i] = this[i + start] - } - } - - return newBuf -} - -/* - * Need to make sure that buffer isn't trying to write out of bounds. - */ -function checkOffset (offset, ext, length) { - if ((offset % 1) !== 0 || offset < 0) throw new RangeError('offset is not uint') - if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length') -} - -Buffer.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) { - offset = offset | 0 - byteLength = byteLength | 0 - if (!noAssert) checkOffset(offset, byteLength, this.length) - - var val = this[offset] - var mul = 1 - var i = 0 - while (++i < byteLength && (mul *= 0x100)) { - val += this[offset + i] * mul - } - - return val -} - -Buffer.prototype.readUIntBE = function readUIntBE (offset, byteLength, noAssert) { - offset = offset | 0 - byteLength = byteLength | 0 - if (!noAssert) { - checkOffset(offset, byteLength, this.length) - } - - var val = this[offset + --byteLength] - var mul = 1 - while (byteLength > 0 && (mul *= 0x100)) { - val += this[offset + --byteLength] * mul - } - - return val -} - -Buffer.prototype.readUInt8 = function readUInt8 (offset, noAssert) { - if (!noAssert) checkOffset(offset, 1, this.length) - return this[offset] -} - -Buffer.prototype.readUInt16LE = function readUInt16LE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 2, this.length) - return this[offset] | (this[offset + 1] << 8) -} - -Buffer.prototype.readUInt16BE = function readUInt16BE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 2, this.length) - return (this[offset] << 8) | this[offset + 1] -} - -Buffer.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 4, this.length) - - return ((this[offset]) | - (this[offset + 1] << 8) | - (this[offset + 2] << 16)) + - (this[offset + 3] * 0x1000000) -} - -Buffer.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 4, this.length) - - return (this[offset] * 0x1000000) + - ((this[offset + 1] << 16) | - (this[offset + 2] << 8) | - this[offset + 3]) -} - -Buffer.prototype.readIntLE = function readIntLE (offset, byteLength, noAssert) { - offset = offset | 0 - byteLength = byteLength | 0 - if (!noAssert) checkOffset(offset, byteLength, this.length) - - var val = this[offset] - var mul = 1 - var i = 0 - while (++i < byteLength && (mul *= 0x100)) { - val += this[offset + i] * mul - } - mul *= 0x80 - - if (val >= mul) val -= Math.pow(2, 8 * byteLength) - - return val -} - -Buffer.prototype.readIntBE = function readIntBE (offset, byteLength, noAssert) { - offset = offset | 0 - byteLength = byteLength | 0 - if (!noAssert) checkOffset(offset, byteLength, this.length) - - var i = byteLength - var mul = 1 - var val = this[offset + --i] - while (i > 0 && (mul *= 0x100)) { - val += this[offset + --i] * mul - } - mul *= 0x80 - - if (val >= mul) val -= Math.pow(2, 8 * byteLength) - - return val -} - -Buffer.prototype.readInt8 = function readInt8 (offset, noAssert) { - if (!noAssert) checkOffset(offset, 1, this.length) - if (!(this[offset] & 0x80)) return (this[offset]) - return ((0xff - this[offset] + 1) * -1) -} - -Buffer.prototype.readInt16LE = function readInt16LE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 2, this.length) - var val = this[offset] | (this[offset + 1] << 8) - return (val & 0x8000) ? val | 0xFFFF0000 : val -} - -Buffer.prototype.readInt16BE = function readInt16BE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 2, this.length) - var val = this[offset + 1] | (this[offset] << 8) - return (val & 0x8000) ? val | 0xFFFF0000 : val -} - -Buffer.prototype.readInt32LE = function readInt32LE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 4, this.length) - - return (this[offset]) | - (this[offset + 1] << 8) | - (this[offset + 2] << 16) | - (this[offset + 3] << 24) -} - -Buffer.prototype.readInt32BE = function readInt32BE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 4, this.length) - - return (this[offset] << 24) | - (this[offset + 1] << 16) | - (this[offset + 2] << 8) | - (this[offset + 3]) -} - -Buffer.prototype.readFloatLE = function readFloatLE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 4, this.length) - return ieee754.read(this, offset, true, 23, 4) -} - -Buffer.prototype.readFloatBE = function readFloatBE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 4, this.length) - return ieee754.read(this, offset, false, 23, 4) -} - -Buffer.prototype.readDoubleLE = function readDoubleLE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 8, this.length) - return ieee754.read(this, offset, true, 52, 8) -} - -Buffer.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 8, this.length) - return ieee754.read(this, offset, false, 52, 8) -} - -function checkInt (buf, value, offset, ext, max, min) { - if (!Buffer.isBuffer(buf)) throw new TypeError('"buffer" argument must be a Buffer instance') - if (value > max || value < min) throw new RangeError('"value" argument is out of bounds') - if (offset + ext > buf.length) throw new RangeError('Index out of range') -} - -Buffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) { - value = +value - offset = offset | 0 - byteLength = byteLength | 0 - if (!noAssert) { - var maxBytes = Math.pow(2, 8 * byteLength) - 1 - checkInt(this, value, offset, byteLength, maxBytes, 0) - } - - var mul = 1 - var i = 0 - this[offset] = value & 0xFF - while (++i < byteLength && (mul *= 0x100)) { - this[offset + i] = (value / mul) & 0xFF - } - - return offset + byteLength -} - -Buffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, noAssert) { - value = +value - offset = offset | 0 - byteLength = byteLength | 0 - if (!noAssert) { - var maxBytes = Math.pow(2, 8 * byteLength) - 1 - checkInt(this, value, offset, byteLength, maxBytes, 0) - } - - var i = byteLength - 1 - var mul = 1 - this[offset + i] = value & 0xFF - while (--i >= 0 && (mul *= 0x100)) { - this[offset + i] = (value / mul) & 0xFF - } - - return offset + byteLength -} - -Buffer.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0) - if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value) - this[offset] = (value & 0xff) - return offset + 1 -} - -function objectWriteUInt16 (buf, value, offset, littleEndian) { - if (value < 0) value = 0xffff + value + 1 - for (var i = 0, j = Math.min(buf.length - offset, 2); i < j; ++i) { - buf[offset + i] = (value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>> - (littleEndian ? i : 1 - i) * 8 - } -} - -Buffer.prototype.writeUInt16LE = function writeUInt16LE (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0) - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value & 0xff) - this[offset + 1] = (value >>> 8) - } else { - objectWriteUInt16(this, value, offset, true) - } - return offset + 2 -} - -Buffer.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0) - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value >>> 8) - this[offset + 1] = (value & 0xff) - } else { - objectWriteUInt16(this, value, offset, false) - } - return offset + 2 -} - -function objectWriteUInt32 (buf, value, offset, littleEndian) { - if (value < 0) value = 0xffffffff + value + 1 - for (var i = 0, j = Math.min(buf.length - offset, 4); i < j; ++i) { - buf[offset + i] = (value >>> (littleEndian ? i : 3 - i) * 8) & 0xff - } -} - -Buffer.prototype.writeUInt32LE = function writeUInt32LE (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0) - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset + 3] = (value >>> 24) - this[offset + 2] = (value >>> 16) - this[offset + 1] = (value >>> 8) - this[offset] = (value & 0xff) - } else { - objectWriteUInt32(this, value, offset, true) - } - return offset + 4 -} - -Buffer.prototype.writeUInt32BE = function writeUInt32BE (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0) - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value >>> 24) - this[offset + 1] = (value >>> 16) - this[offset + 2] = (value >>> 8) - this[offset + 3] = (value & 0xff) - } else { - objectWriteUInt32(this, value, offset, false) - } - return offset + 4 -} - -Buffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) { - var limit = Math.pow(2, 8 * byteLength - 1) - - checkInt(this, value, offset, byteLength, limit - 1, -limit) - } - - var i = 0 - var mul = 1 - var sub = 0 - this[offset] = value & 0xFF - while (++i < byteLength && (mul *= 0x100)) { - if (value < 0 && sub === 0 && this[offset + i - 1] !== 0) { - sub = 1 - } - this[offset + i] = ((value / mul) >> 0) - sub & 0xFF - } - - return offset + byteLength -} - -Buffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) { - var limit = Math.pow(2, 8 * byteLength - 1) - - checkInt(this, value, offset, byteLength, limit - 1, -limit) - } - - var i = byteLength - 1 - var mul = 1 - var sub = 0 - this[offset + i] = value & 0xFF - while (--i >= 0 && (mul *= 0x100)) { - if (value < 0 && sub === 0 && this[offset + i + 1] !== 0) { - sub = 1 - } - this[offset + i] = ((value / mul) >> 0) - sub & 0xFF - } - - return offset + byteLength -} - -Buffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80) - if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value) - if (value < 0) value = 0xff + value + 1 - this[offset] = (value & 0xff) - return offset + 1 -} - -Buffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000) - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value & 0xff) - this[offset + 1] = (value >>> 8) - } else { - objectWriteUInt16(this, value, offset, true) - } - return offset + 2 -} - -Buffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000) - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value >>> 8) - this[offset + 1] = (value & 0xff) - } else { - objectWriteUInt16(this, value, offset, false) - } - return offset + 2 -} - -Buffer.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000) - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value & 0xff) - this[offset + 1] = (value >>> 8) - this[offset + 2] = (value >>> 16) - this[offset + 3] = (value >>> 24) - } else { - objectWriteUInt32(this, value, offset, true) - } - return offset + 4 -} - -Buffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000) - if (value < 0) value = 0xffffffff + value + 1 - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value >>> 24) - this[offset + 1] = (value >>> 16) - this[offset + 2] = (value >>> 8) - this[offset + 3] = (value & 0xff) - } else { - objectWriteUInt32(this, value, offset, false) - } - return offset + 4 -} - -function checkIEEE754 (buf, value, offset, ext, max, min) { - if (offset + ext > buf.length) throw new RangeError('Index out of range') - if (offset < 0) throw new RangeError('Index out of range') -} - -function writeFloat (buf, value, offset, littleEndian, noAssert) { - if (!noAssert) { - checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38) - } - ieee754.write(buf, value, offset, littleEndian, 23, 4) - return offset + 4 -} - -Buffer.prototype.writeFloatLE = function writeFloatLE (value, offset, noAssert) { - return writeFloat(this, value, offset, true, noAssert) -} - -Buffer.prototype.writeFloatBE = function writeFloatBE (value, offset, noAssert) { - return writeFloat(this, value, offset, false, noAssert) -} - -function writeDouble (buf, value, offset, littleEndian, noAssert) { - if (!noAssert) { - checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308) - } - ieee754.write(buf, value, offset, littleEndian, 52, 8) - return offset + 8 -} - -Buffer.prototype.writeDoubleLE = function writeDoubleLE (value, offset, noAssert) { - return writeDouble(this, value, offset, true, noAssert) -} - -Buffer.prototype.writeDoubleBE = function writeDoubleBE (value, offset, noAssert) { - return writeDouble(this, value, offset, false, noAssert) -} - -// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length) -Buffer.prototype.copy = function copy (target, targetStart, start, end) { - if (!start) start = 0 - if (!end && end !== 0) end = this.length - if (targetStart >= target.length) targetStart = target.length - if (!targetStart) targetStart = 0 - if (end > 0 && end < start) end = start - - // Copy 0 bytes; we're done - if (end === start) return 0 - if (target.length === 0 || this.length === 0) return 0 - - // Fatal error conditions - if (targetStart < 0) { - throw new RangeError('targetStart out of bounds') - } - if (start < 0 || start >= this.length) throw new RangeError('sourceStart out of bounds') - if (end < 0) throw new RangeError('sourceEnd out of bounds') - - // Are we oob? - if (end > this.length) end = this.length - if (target.length - targetStart < end - start) { - end = target.length - targetStart + start - } - - var len = end - start - var i - - if (this === target && start < targetStart && targetStart < end) { - // descending copy from end - for (i = len - 1; i >= 0; --i) { - target[i + targetStart] = this[i + start] - } - } else if (len < 1000 || !Buffer.TYPED_ARRAY_SUPPORT) { - // ascending copy from start - for (i = 0; i < len; ++i) { - target[i + targetStart] = this[i + start] - } - } else { - Uint8Array.prototype.set.call( - target, - this.subarray(start, start + len), - targetStart - ) - } - - return len -} - -// Usage: -// buffer.fill(number[, offset[, end]]) -// buffer.fill(buffer[, offset[, end]]) -// buffer.fill(string[, offset[, end]][, encoding]) -Buffer.prototype.fill = function fill (val, start, end, encoding) { - // Handle string cases: - if (typeof val === 'string') { - if (typeof start === 'string') { - encoding = start - start = 0 - end = this.length - } else if (typeof end === 'string') { - encoding = end - end = this.length - } - if (val.length === 1) { - var code = val.charCodeAt(0) - if (code < 256) { - val = code - } - } - if (encoding !== undefined && typeof encoding !== 'string') { - throw new TypeError('encoding must be a string') - } - if (typeof encoding === 'string' && !Buffer.isEncoding(encoding)) { - throw new TypeError('Unknown encoding: ' + encoding) - } - } else if (typeof val === 'number') { - val = val & 255 - } - - // Invalid ranges are not set to a default, so can range check early. - if (start < 0 || this.length < start || this.length < end) { - throw new RangeError('Out of range index') - } - - if (end <= start) { - return this - } - - start = start >>> 0 - end = end === undefined ? this.length : end >>> 0 - - if (!val) val = 0 - - var i - if (typeof val === 'number') { - for (i = start; i < end; ++i) { - this[i] = val - } - } else { - var bytes = Buffer.isBuffer(val) - ? val - : utf8ToBytes(new Buffer(val, encoding).toString()) - var len = bytes.length - for (i = 0; i < end - start; ++i) { - this[i + start] = bytes[i % len] - } - } - - return this -} - -// HELPER FUNCTIONS -// ================ - -var INVALID_BASE64_RE = /[^+\/0-9A-Za-z-_]/g - -function base64clean (str) { - // Node strips out invalid characters like \n and \t from the string, base64-js does not - str = stringtrim(str).replace(INVALID_BASE64_RE, '') - // Node converts strings with length < 2 to '' - if (str.length < 2) return '' - // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not - while (str.length % 4 !== 0) { - str = str + '=' - } - return str -} - -function stringtrim (str) { - if (str.trim) return str.trim() - return str.replace(/^\s+|\s+$/g, '') -} - -function toHex (n) { - if (n < 16) return '0' + n.toString(16) - return n.toString(16) -} - -function utf8ToBytes (string, units) { - units = units || Infinity - var codePoint - var length = string.length - var leadSurrogate = null - var bytes = [] - - for (var i = 0; i < length; ++i) { - codePoint = string.charCodeAt(i) - - // is surrogate component - if (codePoint > 0xD7FF && codePoint < 0xE000) { - // last char was a lead - if (!leadSurrogate) { - // no lead yet - if (codePoint > 0xDBFF) { - // unexpected trail - if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) - continue - } else if (i + 1 === length) { - // unpaired lead - if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) - continue - } - - // valid lead - leadSurrogate = codePoint - - continue - } - - // 2 leads in a row - if (codePoint < 0xDC00) { - if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) - leadSurrogate = codePoint - continue - } - - // valid surrogate pair - codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000 - } else if (leadSurrogate) { - // valid bmp char, but last char was a lead - if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) - } - - leadSurrogate = null - - // encode utf8 - if (codePoint < 0x80) { - if ((units -= 1) < 0) break - bytes.push(codePoint) - } else if (codePoint < 0x800) { - if ((units -= 2) < 0) break - bytes.push( - codePoint >> 0x6 | 0xC0, - codePoint & 0x3F | 0x80 - ) - } else if (codePoint < 0x10000) { - if ((units -= 3) < 0) break - bytes.push( - codePoint >> 0xC | 0xE0, - codePoint >> 0x6 & 0x3F | 0x80, - codePoint & 0x3F | 0x80 - ) - } else if (codePoint < 0x110000) { - if ((units -= 4) < 0) break - bytes.push( - codePoint >> 0x12 | 0xF0, - codePoint >> 0xC & 0x3F | 0x80, - codePoint >> 0x6 & 0x3F | 0x80, - codePoint & 0x3F | 0x80 - ) - } else { - throw new Error('Invalid code point') - } - } - - return bytes -} - -function asciiToBytes (str) { - var byteArray = [] - for (var i = 0; i < str.length; ++i) { - // Node's code seems to be doing this and not & 0x7F.. - byteArray.push(str.charCodeAt(i) & 0xFF) - } - return byteArray -} - -function utf16leToBytes (str, units) { - var c, hi, lo - var byteArray = [] - for (var i = 0; i < str.length; ++i) { - if ((units -= 2) < 0) break - - c = str.charCodeAt(i) - hi = c >> 8 - lo = c % 256 - byteArray.push(lo) - byteArray.push(hi) - } - - return byteArray -} - -function base64ToBytes (str) { - return base64.toByteArray(base64clean(str)) -} - -function blitBuffer (src, dst, offset, length) { - for (var i = 0; i < length; ++i) { - if ((i + offset >= dst.length) || (i >= src.length)) break - dst[i + offset] = src[i] - } - return i -} - -function isnan (val) { - return val !== val // eslint-disable-line no-self-compare -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(7))) - -/***/ }), -/* 2 */ -/***/ (function(module, exports) { - -var core = module.exports = { version: '2.5.3' }; -if (typeof __e == 'number') __e = core; // eslint-disable-line no-undef - - -/***/ }), -/* 3 */ -/***/ (function(module, exports, __webpack_require__) { - -var global = __webpack_require__(10); -var core = __webpack_require__(2); -var ctx = __webpack_require__(20); -var hide = __webpack_require__(13); -var PROTOTYPE = 'prototype'; - -var $export = function (type, name, source) { - var IS_FORCED = type & $export.F; - var IS_GLOBAL = type & $export.G; - var IS_STATIC = type & $export.S; - var IS_PROTO = type & $export.P; - var IS_BIND = type & $export.B; - var IS_WRAP = type & $export.W; - var exports = IS_GLOBAL ? core : core[name] || (core[name] = {}); - var expProto = exports[PROTOTYPE]; - var target = IS_GLOBAL ? global : IS_STATIC ? global[name] : (global[name] || {})[PROTOTYPE]; - var key, own, out; - if (IS_GLOBAL) source = name; - for (key in source) { - // contains in native - own = !IS_FORCED && target && target[key] !== undefined; - if (own && key in exports) continue; - // export native or passed - out = own ? target[key] : source[key]; - // prevent global pollution for namespaces - exports[key] = IS_GLOBAL && typeof target[key] != 'function' ? source[key] - // bind timers to global for call from export context - : IS_BIND && own ? ctx(out, global) - // wrap global constructors for prevent change them in library - : IS_WRAP && target[key] == out ? (function (C) { - var F = function (a, b, c) { - if (this instanceof C) { - switch (arguments.length) { - case 0: return new C(); - case 1: return new C(a); - case 2: return new C(a, b); - } return new C(a, b, c); - } return C.apply(this, arguments); - }; - F[PROTOTYPE] = C[PROTOTYPE]; - return F; - // make static versions for prototype methods - })(out) : IS_PROTO && typeof out == 'function' ? ctx(Function.call, out) : out; - // export proto methods to core.%CONSTRUCTOR%.methods.%NAME% - if (IS_PROTO) { - (exports.virtual || (exports.virtual = {}))[key] = out; - // export proto methods to core.%CONSTRUCTOR%.prototype.%NAME% - if (type & $export.R && expProto && !expProto[key]) hide(expProto, key, out); - } - } -}; -// type bitmap -$export.F = 1; // forced -$export.G = 2; // global -$export.S = 4; // static -$export.P = 8; // proto -$export.B = 16; // bind -$export.W = 32; // wrap -$export.U = 64; // safe -$export.R = 128; // real proto method for `library` -module.exports = $export; - - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - -var store = __webpack_require__(65)('wks'); -var uid = __webpack_require__(38); -var Symbol = __webpack_require__(10).Symbol; -var USE_SYMBOL = typeof Symbol == 'function'; - -var $exports = module.exports = function (name) { - return store[name] || (store[name] = - USE_SYMBOL && Symbol[name] || (USE_SYMBOL ? Symbol : uid)('Symbol.' + name)); -}; - -$exports.store = store; - - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -// Thank's IE8 for his funny defineProperty -module.exports = !__webpack_require__(19)(function () { - return Object.defineProperty({}, 'a', { get: function () { return 7; } }).a != 7; -}); - - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -var anObject = __webpack_require__(14); -var IE8_DOM_DEFINE = __webpack_require__(95); -var toPrimitive = __webpack_require__(58); -var dP = Object.defineProperty; - -exports.f = __webpack_require__(5) ? Object.defineProperty : function defineProperty(O, P, Attributes) { - anObject(O); - P = toPrimitive(P, true); - anObject(Attributes); - if (IE8_DOM_DEFINE) try { - return dP(O, P, Attributes); - } catch (e) { /* empty */ } - if ('get' in Attributes || 'set' in Attributes) throw TypeError('Accessors not supported!'); - if ('value' in Attributes) O[P] = Attributes.value; - return O; -}; - - -/***/ }), -/* 7 */ -/***/ (function(module, exports) { - -var g; - -// This works in non-strict mode -g = (function() { - return this; -})(); - -try { - // This works if eval is allowed (see CSP) - g = g || Function("return this")() || (1,eval)("this"); -} catch(e) { - // This works if the window reference is available - if(typeof window === "object") - g = window; -} - -// g can still be undefined, but nothing to do about it... -// We return undefined, instead of nothing here, so it's -// easier to handle this case. if(!global) { ...} - -module.exports = g; - - -/***/ }), -/* 8 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/* WEBPACK VAR INJECTION */(function(Buffer, __dirname) { - -function VirtualFileSystem() { - this.fileSystem = {}; - this.baseSystem = {}; -} - -VirtualFileSystem.prototype.readFileSync = function (filename) { - filename = fixFilename(filename); - - var base64content = this.baseSystem[filename]; - if (base64content) { - return new Buffer(base64content, 'base64'); - } - - var content = this.fileSystem[filename]; - if (content) { - return content; - } - - throw 'File \'' + filename + '\' not found in virtual file system'; -}; - -VirtualFileSystem.prototype.writeFileSync = function (filename, content) { - this.fileSystem[fixFilename(filename)] = content; -}; - -VirtualFileSystem.prototype.bindFS = function (data) { - this.baseSystem = data || {}; -}; - - -function fixFilename(filename) { - if (filename.indexOf(__dirname) === 0) { - filename = filename.substring(__dirname.length); - } - - if (filename.indexOf('/') === 0) { - filename = filename.substring(1); - } - - return filename; -} - -module.exports = new VirtualFileSystem(); - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1).Buffer, "/")) - -/***/ }), -/* 9 */ -/***/ (function(module, exports) { - -module.exports = function (it) { - return typeof it === 'object' ? it !== null : typeof it === 'function'; -}; - - -/***/ }), -/* 10 */ -/***/ (function(module, exports) { - -// https://github.com/zloirock/core-js/issues/86#issuecomment-115759028 -var global = module.exports = typeof window != 'undefined' && window.Math == Math - ? window : typeof self != 'undefined' && self.Math == Math ? self - // eslint-disable-next-line no-new-func - : Function('return this')(); -if (typeof __g == 'number') __g = global; // eslint-disable-line no-undef - - -/***/ }), -/* 11 */ -/***/ (function(module, exports) { - -// shim for using process in browser -var process = module.exports = {}; - -// cached from whatever global is present so that test runners that stub it -// don't break things. But we need to wrap it in a try catch in case it is -// wrapped in strict mode code which doesn't define any globals. It's inside a -// function because try/catches deoptimize in certain engines. - -var cachedSetTimeout; -var cachedClearTimeout; - -function defaultSetTimout() { - throw new Error('setTimeout has not been defined'); -} -function defaultClearTimeout () { - throw new Error('clearTimeout has not been defined'); -} -(function () { - try { - if (typeof setTimeout === 'function') { - cachedSetTimeout = setTimeout; - } else { - cachedSetTimeout = defaultSetTimout; - } - } catch (e) { - cachedSetTimeout = defaultSetTimout; - } - try { - if (typeof clearTimeout === 'function') { - cachedClearTimeout = clearTimeout; - } else { - cachedClearTimeout = defaultClearTimeout; - } - } catch (e) { - cachedClearTimeout = defaultClearTimeout; - } -} ()) -function runTimeout(fun) { - if (cachedSetTimeout === setTimeout) { - //normal enviroments in sane situations - return setTimeout(fun, 0); - } - // if setTimeout wasn't available but was latter defined - if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { - cachedSetTimeout = setTimeout; - return setTimeout(fun, 0); - } - try { - // when when somebody has screwed with setTimeout but no I.E. maddness - return cachedSetTimeout(fun, 0); - } catch(e){ - try { - // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally - return cachedSetTimeout.call(null, fun, 0); - } catch(e){ - // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error - return cachedSetTimeout.call(this, fun, 0); - } - } - - -} -function runClearTimeout(marker) { - if (cachedClearTimeout === clearTimeout) { - //normal enviroments in sane situations - return clearTimeout(marker); - } - // if clearTimeout wasn't available but was latter defined - if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { - cachedClearTimeout = clearTimeout; - return clearTimeout(marker); - } - try { - // when when somebody has screwed with setTimeout but no I.E. maddness - return cachedClearTimeout(marker); - } catch (e){ - try { - // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally - return cachedClearTimeout.call(null, marker); - } catch (e){ - // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. - // Some versions of I.E. have different rules for clearTimeout vs setTimeout - return cachedClearTimeout.call(this, marker); - } - } - - - -} -var queue = []; -var draining = false; -var currentQueue; -var queueIndex = -1; - -function cleanUpNextTick() { - if (!draining || !currentQueue) { - return; - } - draining = false; - if (currentQueue.length) { - queue = currentQueue.concat(queue); - } else { - queueIndex = -1; - } - if (queue.length) { - drainQueue(); - } -} - -function drainQueue() { - if (draining) { - return; - } - var timeout = runTimeout(cleanUpNextTick); - draining = true; - - var len = queue.length; - while(len) { - currentQueue = queue; - queue = []; - while (++queueIndex < len) { - if (currentQueue) { - currentQueue[queueIndex].run(); - } - } - queueIndex = -1; - len = queue.length; - } - currentQueue = null; - draining = false; - runClearTimeout(timeout); -} - -process.nextTick = function (fun) { - var args = new Array(arguments.length - 1); - if (arguments.length > 1) { - for (var i = 1; i < arguments.length; i++) { - args[i - 1] = arguments[i]; - } - } - queue.push(new Item(fun, args)); - if (queue.length === 1 && !draining) { - runTimeout(drainQueue); - } -}; - -// v8 likes predictible objects -function Item(fun, array) { - this.fun = fun; - this.array = array; -} -Item.prototype.run = function () { - this.fun.apply(null, this.array); -}; -process.title = 'browser'; -process.browser = true; -process.env = {}; -process.argv = []; -process.version = ''; // empty string to avoid regexp issues -process.versions = {}; - -function noop() {} - -process.on = noop; -process.addListener = noop; -process.once = noop; -process.off = noop; -process.removeListener = noop; -process.removeAllListeners = noop; -process.emit = noop; -process.prependListener = noop; -process.prependOnceListener = noop; - -process.listeners = function (name) { return [] } - -process.binding = function (name) { - throw new Error('process.binding is not supported'); -}; - -process.cwd = function () { return '/' }; -process.chdir = function (dir) { - throw new Error('process.chdir is not supported'); -}; -process.umask = function() { return 0; }; - - -/***/ }), -/* 12 */ -/***/ (function(module, exports, __webpack_require__) { - -// Generated by CoffeeScript 1.7.1 -(function() { - var NumberT, PropertyDescriptor; - - NumberT = __webpack_require__(22).Number; - - exports.resolveLength = function(length, stream, parent) { - var res; - if (typeof length === 'number') { - res = length; - } else if (typeof length === 'function') { - res = length.call(parent, parent); - } else if (parent && typeof length === 'string') { - res = parent[length]; - } else if (stream && length instanceof NumberT) { - res = length.decode(stream); - } - if (isNaN(res)) { - throw new Error('Not a fixed size'); - } - return res; - }; - - PropertyDescriptor = (function() { - function PropertyDescriptor(opts) { - var key, val; - if (opts == null) { - opts = {}; - } - this.enumerable = true; - this.configurable = true; - for (key in opts) { - val = opts[key]; - this[key] = val; - } - } - - return PropertyDescriptor; - - })(); - - exports.PropertyDescriptor = PropertyDescriptor; - -}).call(this); - - -/***/ }), -/* 13 */ -/***/ (function(module, exports, __webpack_require__) { - -var dP = __webpack_require__(6); -var createDesc = __webpack_require__(27); -module.exports = __webpack_require__(5) ? function (object, key, value) { - return dP.f(object, key, createDesc(1, value)); -} : function (object, key, value) { - object[key] = value; - return object; -}; - - -/***/ }), -/* 14 */ -/***/ (function(module, exports, __webpack_require__) { - -var isObject = __webpack_require__(9); -module.exports = function (it) { - if (!isObject(it)) throw TypeError(it + ' is not an object!'); - return it; -}; - - -/***/ }), -/* 15 */ -/***/ (function(module, exports, __webpack_require__) { - -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -module.exports = Stream; - -var EE = __webpack_require__(31).EventEmitter; -var inherits = __webpack_require__(21); - -inherits(Stream, EE); -Stream.Readable = __webpack_require__(45); -Stream.Writable = __webpack_require__(146); -Stream.Duplex = __webpack_require__(147); -Stream.Transform = __webpack_require__(148); -Stream.PassThrough = __webpack_require__(149); - -// Backwards-compat with node 0.4.x -Stream.Stream = Stream; - - - -// old-style streams. Note that the pipe method (the only relevant -// part of this class) is overridden in the Readable class. - -function Stream() { - EE.call(this); -} - -Stream.prototype.pipe = function(dest, options) { - var source = this; - - function ondata(chunk) { - if (dest.writable) { - if (false === dest.write(chunk) && source.pause) { - source.pause(); - } - } - } - - source.on('data', ondata); - - function ondrain() { - if (source.readable && source.resume) { - source.resume(); - } - } - - dest.on('drain', ondrain); - - // If the 'end' option is not supplied, dest.end() will be called when - // source gets the 'end' or 'close' events. Only dest.end() once. - if (!dest._isStdio && (!options || options.end !== false)) { - source.on('end', onend); - source.on('close', onclose); - } - - var didOnEnd = false; - function onend() { - if (didOnEnd) return; - didOnEnd = true; - - dest.end(); - } - - - function onclose() { - if (didOnEnd) return; - didOnEnd = true; - - if (typeof dest.destroy === 'function') dest.destroy(); - } - - // don't leave dangling pipes when there are errors. - function onerror(er) { - cleanup(); - if (EE.listenerCount(this, 'error') === 0) { - throw er; // Unhandled stream error in pipe. - } - } - - source.on('error', onerror); - dest.on('error', onerror); - - // remove all the event listeners that were added. - function cleanup() { - source.removeListener('data', ondata); - dest.removeListener('drain', ondrain); - - source.removeListener('end', onend); - source.removeListener('close', onclose); - - source.removeListener('error', onerror); - dest.removeListener('error', onerror); - - source.removeListener('end', cleanup); - source.removeListener('close', cleanup); - - dest.removeListener('close', cleanup); - } - - source.on('end', cleanup); - source.on('close', cleanup); - - dest.on('close', cleanup); - - dest.emit('pipe', source); - - // Allow for unix-like usage: A.pipe(B).pipe(C) - return dest; -}; - - -/***/ }), -/* 16 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -// a duplex stream is just a stream that is both readable and writable. -// Since JS doesn't have multiple prototypal inheritance, this class -// prototypally inherits from Readable, and then parasitically from -// Writable. - - - -/**/ - -var processNextTick = __webpack_require__(32).nextTick; -/**/ - -/**/ -var objectKeys = Object.keys || function (obj) { - var keys = []; - for (var key in obj) { - keys.push(key); - }return keys; -}; -/**/ - -module.exports = Duplex; - -/**/ -var util = __webpack_require__(25); -util.inherits = __webpack_require__(21); -/**/ - -var Readable = __webpack_require__(83); -var Writable = __webpack_require__(46); - -util.inherits(Duplex, Readable); - -var keys = objectKeys(Writable.prototype); -for (var v = 0; v < keys.length; v++) { - var method = keys[v]; - if (!Duplex.prototype[method]) Duplex.prototype[method] = Writable.prototype[method]; -} - -function Duplex(options) { - if (!(this instanceof Duplex)) return new Duplex(options); - - Readable.call(this, options); - Writable.call(this, options); - - if (options && options.readable === false) this.readable = false; - - if (options && options.writable === false) this.writable = false; - - this.allowHalfOpen = true; - if (options && options.allowHalfOpen === false) this.allowHalfOpen = false; - - this.once('end', onend); -} - -// the no-half-open enforcer -function onend() { - // if we allow half-open state, or if the writable side ended, - // then we're ok. - if (this.allowHalfOpen || this._writableState.ended) return; - - // no more data can be written. - // But allow more writes to happen in this tick. - processNextTick(onEndNT, this); -} - -function onEndNT(self) { - self.end(); -} - -Object.defineProperty(Duplex.prototype, 'destroyed', { - get: function () { - if (this._readableState === undefined || this._writableState === undefined) { - return false; - } - return this._readableState.destroyed && this._writableState.destroyed; - }, - set: function (value) { - // we ignore the value if the stream - // has not been initialized yet - if (this._readableState === undefined || this._writableState === undefined) { - return; - } - - // backward compatibility, the user is explicitly - // managing destroyed - this._readableState.destroyed = value; - this._writableState.destroyed = value; - } -}); - -Duplex.prototype._destroy = function (err, cb) { - this.push(null); - this.end(); - - processNextTick(cb, err); -}; - -function forEach(xs, f) { - for (var i = 0, l = xs.length; i < l; i++) { - f(xs[i], i); - } -} - -/***/ }), -/* 17 */ -/***/ (function(module, exports, __webpack_require__) { - -// to indexed object, toObject with fallback for non-array-like ES3 strings -var IObject = __webpack_require__(54); -var defined = __webpack_require__(56); -module.exports = function (it) { - return IObject(defined(it)); -}; - - -/***/ }), -/* 18 */ -/***/ (function(module, exports) { - -var hasOwnProperty = {}.hasOwnProperty; -module.exports = function (it, key) { - return hasOwnProperty.call(it, key); -}; - - -/***/ }), -/* 19 */ -/***/ (function(module, exports) { - -module.exports = function (exec) { - try { - return !!exec(); - } catch (e) { - return true; - } -}; - - -/***/ }), -/* 20 */ -/***/ (function(module, exports, __webpack_require__) { - -// optional / simple context binding -var aFunction = __webpack_require__(97); -module.exports = function (fn, that, length) { - aFunction(fn); - if (that === undefined) return fn; - switch (length) { - case 1: return function (a) { - return fn.call(that, a); - }; - case 2: return function (a, b) { - return fn.call(that, a, b); - }; - case 3: return function (a, b, c) { - return fn.call(that, a, b, c); - }; - } - return function (/* ...args */) { - return fn.apply(that, arguments); - }; -}; - - -/***/ }), -/* 21 */ -/***/ (function(module, exports) { - -if (typeof Object.create === 'function') { - // implementation from standard node.js 'util' module - module.exports = function inherits(ctor, superCtor) { - ctor.super_ = superCtor - ctor.prototype = Object.create(superCtor.prototype, { - constructor: { - value: ctor, - enumerable: false, - writable: true, - configurable: true - } - }); - }; -} else { - // old school shim for old browsers - module.exports = function inherits(ctor, superCtor) { - ctor.super_ = superCtor - var TempCtor = function () {} - TempCtor.prototype = superCtor.prototype - ctor.prototype = new TempCtor() - ctor.prototype.constructor = ctor - } -} - - -/***/ }), -/* 22 */ -/***/ (function(module, exports, __webpack_require__) { - -// Generated by CoffeeScript 1.7.1 -(function() { - var DecodeStream, Fixed, NumberT, - __hasProp = {}.hasOwnProperty, - __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; - - DecodeStream = __webpack_require__(51); - - NumberT = (function() { - function NumberT(type, endian) { - this.type = type; - this.endian = endian != null ? endian : 'BE'; - this.fn = this.type; - if (this.type[this.type.length - 1] !== '8') { - this.fn += this.endian; - } - } - - NumberT.prototype.size = function() { - return DecodeStream.TYPES[this.type]; - }; - - NumberT.prototype.decode = function(stream) { - return stream['read' + this.fn](); - }; - - NumberT.prototype.encode = function(stream, val) { - return stream['write' + this.fn](val); - }; - - return NumberT; - - })(); - - exports.Number = NumberT; - - exports.uint8 = new NumberT('UInt8'); - - exports.uint16be = exports.uint16 = new NumberT('UInt16', 'BE'); - - exports.uint16le = new NumberT('UInt16', 'LE'); - - exports.uint24be = exports.uint24 = new NumberT('UInt24', 'BE'); - - exports.uint24le = new NumberT('UInt24', 'LE'); - - exports.uint32be = exports.uint32 = new NumberT('UInt32', 'BE'); - - exports.uint32le = new NumberT('UInt32', 'LE'); - - exports.int8 = new NumberT('Int8'); - - exports.int16be = exports.int16 = new NumberT('Int16', 'BE'); - - exports.int16le = new NumberT('Int16', 'LE'); - - exports.int24be = exports.int24 = new NumberT('Int24', 'BE'); - - exports.int24le = new NumberT('Int24', 'LE'); - - exports.int32be = exports.int32 = new NumberT('Int32', 'BE'); - - exports.int32le = new NumberT('Int32', 'LE'); - - exports.floatbe = exports.float = new NumberT('Float', 'BE'); - - exports.floatle = new NumberT('Float', 'LE'); - - exports.doublebe = exports.double = new NumberT('Double', 'BE'); - - exports.doublele = new NumberT('Double', 'LE'); - - Fixed = (function(_super) { - __extends(Fixed, _super); - - function Fixed(size, endian, fracBits) { - if (fracBits == null) { - fracBits = size >> 1; - } - Fixed.__super__.constructor.call(this, "Int" + size, endian); - this._point = 1 << fracBits; - } - - Fixed.prototype.decode = function(stream) { - return Fixed.__super__.decode.call(this, stream) / this._point; - }; - - Fixed.prototype.encode = function(stream, val) { - return Fixed.__super__.encode.call(this, stream, val * this._point | 0); - }; - - return Fixed; - - })(NumberT); - - exports.Fixed = Fixed; - - exports.fixed16be = exports.fixed16 = new Fixed(16, 'BE'); - - exports.fixed16le = new Fixed(16, 'LE'); - - exports.fixed32be = exports.fixed32 = new Fixed(32, 'BE'); - - exports.fixed32le = new Fixed(32, 'LE'); - -}).call(this); - - -/***/ }), -/* 23 */ -/***/ (function(module, exports) { - -module.exports = {}; - - -/***/ }), -/* 24 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var $at = __webpack_require__(207)(true); - -// 21.1.3.27 String.prototype[@@iterator]() -__webpack_require__(61)(String, 'String', function (iterated) { - this._t = String(iterated); // target - this._i = 0; // next index -// 21.1.5.2.1 %StringIteratorPrototype%.next() -}, function () { - var O = this._t; - var index = this._i; - var point; - if (index >= O.length) return { value: undefined, done: true }; - point = $at(O, index); - this._i += point.length; - return { value: point, done: false }; -}); - - -/***/ }), -/* 25 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(Buffer) {// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -// NOTE: These type checking functions intentionally don't use `instanceof` -// because it is fragile and can be easily faked with `Object.create()`. - -function isArray(arg) { - if (Array.isArray) { - return Array.isArray(arg); - } - return objectToString(arg) === '[object Array]'; -} -exports.isArray = isArray; - -function isBoolean(arg) { - return typeof arg === 'boolean'; -} -exports.isBoolean = isBoolean; - -function isNull(arg) { - return arg === null; -} -exports.isNull = isNull; - -function isNullOrUndefined(arg) { - return arg == null; -} -exports.isNullOrUndefined = isNullOrUndefined; - -function isNumber(arg) { - return typeof arg === 'number'; -} -exports.isNumber = isNumber; - -function isString(arg) { - return typeof arg === 'string'; -} -exports.isString = isString; - -function isSymbol(arg) { - return typeof arg === 'symbol'; -} -exports.isSymbol = isSymbol; - -function isUndefined(arg) { - return arg === void 0; -} -exports.isUndefined = isUndefined; - -function isRegExp(re) { - return objectToString(re) === '[object RegExp]'; -} -exports.isRegExp = isRegExp; - -function isObject(arg) { - return typeof arg === 'object' && arg !== null; -} -exports.isObject = isObject; - -function isDate(d) { - return objectToString(d) === '[object Date]'; -} -exports.isDate = isDate; - -function isError(e) { - return (objectToString(e) === '[object Error]' || e instanceof Error); -} -exports.isError = isError; - -function isFunction(arg) { - return typeof arg === 'function'; -} -exports.isFunction = isFunction; - -function isPrimitive(arg) { - return arg === null || - typeof arg === 'boolean' || - typeof arg === 'number' || - typeof arg === 'string' || - typeof arg === 'symbol' || // ES6 symbol - typeof arg === 'undefined'; -} -exports.isPrimitive = isPrimitive; - -exports.isBuffer = Buffer.isBuffer; - -function objectToString(o) { - return Object.prototype.toString.call(o); -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1).Buffer)) - -/***/ }), -/* 26 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(Buffer) {// Generated by CoffeeScript 1.12.6 - -/* -PDFObject - converts JavaScript types into their corrisponding PDF types. -By Devon Govett - */ - -(function() { - var PDFObject, PDFReference; - - PDFObject = (function() { - var escapable, escapableRe, pad, swapBytes; - - function PDFObject() {} - - pad = function(str, length) { - return (Array(length + 1).join('0') + str).slice(-length); - }; - - escapableRe = /[\n\r\t\b\f\(\)\\]/g; - - escapable = { - '\n': '\\n', - '\r': '\\r', - '\t': '\\t', - '\b': '\\b', - '\f': '\\f', - '\\': '\\\\', - '(': '\\(', - ')': '\\)' - }; - - swapBytes = function(buff) { - var a, i, j, l, ref; - l = buff.length; - if (l & 0x01) { - throw new Error("Buffer length must be even"); - } else { - for (i = j = 0, ref = l - 1; j < ref; i = j += 2) { - a = buff[i]; - buff[i] = buff[i + 1]; - buff[i + 1] = a; - } - } - return buff; - }; - - PDFObject.convert = function(object) { - var e, i, isUnicode, items, j, key, out, ref, string, val; - if (typeof object === 'string') { - return '/' + object; - } else if (object instanceof String) { - string = object; - isUnicode = false; - for (i = j = 0, ref = string.length; j < ref; i = j += 1) { - if (string.charCodeAt(i) > 0x7f) { - isUnicode = true; - break; - } - } - if (isUnicode) { - string = swapBytes(new Buffer('\ufeff' + string, 'utf16le')).toString('binary'); - } - string = string.replace(escapableRe, function(c) { - return escapable[c]; - }); - return '(' + string + ')'; - } else if (Buffer.isBuffer(object)) { - return '<' + object.toString('hex') + '>'; - } else if (object instanceof PDFReference) { - return object.toString(); - } else if (object instanceof Date) { - return '(D:' + pad(object.getUTCFullYear(), 4) + pad(object.getUTCMonth() + 1, 2) + pad(object.getUTCDate(), 2) + pad(object.getUTCHours(), 2) + pad(object.getUTCMinutes(), 2) + pad(object.getUTCSeconds(), 2) + 'Z)'; - } else if (Array.isArray(object)) { - items = ((function() { - var k, len, results; - results = []; - for (k = 0, len = object.length; k < len; k++) { - e = object[k]; - results.push(PDFObject.convert(e)); - } - return results; - })()).join(' '); - return '[' + items + ']'; - } else if ({}.toString.call(object) === '[object Object]') { - out = ['<<']; - for (key in object) { - val = object[key]; - out.push('/' + key + ' ' + PDFObject.convert(val)); - } - out.push('>>'); - return out.join('\n'); - } else if (typeof object === 'number') { - return PDFObject.number(object); - } else { - return '' + object; - } - }; - - PDFObject.number = function(n) { - if (n > -1e21 && n < 1e21) { - return Math.round(n * 1e6) / 1e6; - } - throw new Error("unsupported number: " + n); - }; - - return PDFObject; - - })(); - - module.exports = PDFObject; - - PDFReference = __webpack_require__(87); - -}).call(this); - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1).Buffer)) - -/***/ }), -/* 27 */ -/***/ (function(module, exports) { - -module.exports = function (bitmap, value) { - return { - enumerable: !(bitmap & 1), - configurable: !(bitmap & 2), - writable: !(bitmap & 4), - value: value - }; -}; - - -/***/ }), -/* 28 */ -/***/ (function(module, exports, __webpack_require__) { - -__webpack_require__(201); -var global = __webpack_require__(10); -var hide = __webpack_require__(13); -var Iterators = __webpack_require__(23); -var TO_STRING_TAG = __webpack_require__(4)('toStringTag'); - -var DOMIterables = ('CSSRuleList,CSSStyleDeclaration,CSSValueList,ClientRectList,DOMRectList,DOMStringList,' + - 'DOMTokenList,DataTransferItemList,FileList,HTMLAllCollection,HTMLCollection,HTMLFormElement,HTMLSelectElement,' + - 'MediaList,MimeTypeArray,NamedNodeMap,NodeList,PaintRequestList,Plugin,PluginArray,SVGLengthList,SVGNumberList,' + - 'SVGPathSegList,SVGPointList,SVGStringList,SVGTransformList,SourceBufferList,StyleSheetList,TextTrackCueList,' + - 'TextTrackList,TouchList').split(','); - -for (var i = 0; i < DOMIterables.length; i++) { - var NAME = DOMIterables[i]; - var Collection = global[NAME]; - var proto = Collection && Collection.prototype; - if (proto && !proto[TO_STRING_TAG]) hide(proto, TO_STRING_TAG, NAME); - Iterators[NAME] = Iterators.Array; -} - - -/***/ }), -/* 29 */ -/***/ (function(module, exports, __webpack_require__) { - -// 19.1.2.14 / 15.2.3.14 Object.keys(O) -var $keys = __webpack_require__(101); -var enumBugKeys = __webpack_require__(66); - -module.exports = Object.keys || function keys(O) { - return $keys(O, enumBugKeys); -}; - - -/***/ }), -/* 30 */ -/***/ (function(module, exports, __webpack_require__) { - -// 7.1.13 ToObject(argument) -var defined = __webpack_require__(56); -module.exports = function (it) { - return Object(defined(it)); -}; - - -/***/ }), -/* 31 */ -/***/ (function(module, exports) { - -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -function EventEmitter() { - this._events = this._events || {}; - this._maxListeners = this._maxListeners || undefined; -} -module.exports = EventEmitter; - -// Backwards-compat with node 0.10.x -EventEmitter.EventEmitter = EventEmitter; - -EventEmitter.prototype._events = undefined; -EventEmitter.prototype._maxListeners = undefined; - -// By default EventEmitters will print a warning if more than 10 listeners are -// added to it. This is a useful default which helps finding memory leaks. -EventEmitter.defaultMaxListeners = 10; - -// Obviously not all Emitters should be limited to 10. This function allows -// that to be increased. Set to zero for unlimited. -EventEmitter.prototype.setMaxListeners = function(n) { - if (!isNumber(n) || n < 0 || isNaN(n)) - throw TypeError('n must be a positive number'); - this._maxListeners = n; - return this; -}; - -EventEmitter.prototype.emit = function(type) { - var er, handler, len, args, i, listeners; - - if (!this._events) - this._events = {}; - - // If there is no 'error' event listener then throw. - if (type === 'error') { - if (!this._events.error || - (isObject(this._events.error) && !this._events.error.length)) { - er = arguments[1]; - if (er instanceof Error) { - throw er; // Unhandled 'error' event - } else { - // At least give some kind of context to the user - var err = new Error('Uncaught, unspecified "error" event. (' + er + ')'); - err.context = er; - throw err; - } - } - } - - handler = this._events[type]; - - if (isUndefined(handler)) - return false; - - if (isFunction(handler)) { - switch (arguments.length) { - // fast cases - case 1: - handler.call(this); - break; - case 2: - handler.call(this, arguments[1]); - break; - case 3: - handler.call(this, arguments[1], arguments[2]); - break; - // slower - default: - args = Array.prototype.slice.call(arguments, 1); - handler.apply(this, args); - } - } else if (isObject(handler)) { - args = Array.prototype.slice.call(arguments, 1); - listeners = handler.slice(); - len = listeners.length; - for (i = 0; i < len; i++) - listeners[i].apply(this, args); - } - - return true; -}; - -EventEmitter.prototype.addListener = function(type, listener) { - var m; - - if (!isFunction(listener)) - throw TypeError('listener must be a function'); - - if (!this._events) - this._events = {}; - - // To avoid recursion in the case that type === "newListener"! Before - // adding it to the listeners, first emit "newListener". - if (this._events.newListener) - this.emit('newListener', type, - isFunction(listener.listener) ? - listener.listener : listener); - - if (!this._events[type]) - // Optimize the case of one listener. Don't need the extra array object. - this._events[type] = listener; - else if (isObject(this._events[type])) - // If we've already got an array, just append. - this._events[type].push(listener); - else - // Adding the second element, need to change to array. - this._events[type] = [this._events[type], listener]; - - // Check for listener leak - if (isObject(this._events[type]) && !this._events[type].warned) { - if (!isUndefined(this._maxListeners)) { - m = this._maxListeners; - } else { - m = EventEmitter.defaultMaxListeners; - } - - if (m && m > 0 && this._events[type].length > m) { - this._events[type].warned = true; - console.error('(node) warning: possible EventEmitter memory ' + - 'leak detected. %d listeners added. ' + - 'Use emitter.setMaxListeners() to increase limit.', - this._events[type].length); - if (typeof console.trace === 'function') { - // not supported in IE 10 - console.trace(); - } - } - } - - return this; -}; - -EventEmitter.prototype.on = EventEmitter.prototype.addListener; - -EventEmitter.prototype.once = function(type, listener) { - if (!isFunction(listener)) - throw TypeError('listener must be a function'); - - var fired = false; - - function g() { - this.removeListener(type, g); - - if (!fired) { - fired = true; - listener.apply(this, arguments); - } - } - - g.listener = listener; - this.on(type, g); - - return this; -}; - -// emits a 'removeListener' event iff the listener was removed -EventEmitter.prototype.removeListener = function(type, listener) { - var list, position, length, i; - - if (!isFunction(listener)) - throw TypeError('listener must be a function'); - - if (!this._events || !this._events[type]) - return this; - - list = this._events[type]; - length = list.length; - position = -1; - - if (list === listener || - (isFunction(list.listener) && list.listener === listener)) { - delete this._events[type]; - if (this._events.removeListener) - this.emit('removeListener', type, listener); - - } else if (isObject(list)) { - for (i = length; i-- > 0;) { - if (list[i] === listener || - (list[i].listener && list[i].listener === listener)) { - position = i; - break; - } - } - - if (position < 0) - return this; - - if (list.length === 1) { - list.length = 0; - delete this._events[type]; - } else { - list.splice(position, 1); - } - - if (this._events.removeListener) - this.emit('removeListener', type, listener); - } - - return this; -}; - -EventEmitter.prototype.removeAllListeners = function(type) { - var key, listeners; - - if (!this._events) - return this; - - // not listening for removeListener, no need to emit - if (!this._events.removeListener) { - if (arguments.length === 0) - this._events = {}; - else if (this._events[type]) - delete this._events[type]; - return this; - } - - // emit removeListener for all listeners on all events - if (arguments.length === 0) { - for (key in this._events) { - if (key === 'removeListener') continue; - this.removeAllListeners(key); - } - this.removeAllListeners('removeListener'); - this._events = {}; - return this; - } - - listeners = this._events[type]; - - if (isFunction(listeners)) { - this.removeListener(type, listeners); - } else if (listeners) { - // LIFO order - while (listeners.length) - this.removeListener(type, listeners[listeners.length - 1]); - } - delete this._events[type]; - - return this; -}; - -EventEmitter.prototype.listeners = function(type) { - var ret; - if (!this._events || !this._events[type]) - ret = []; - else if (isFunction(this._events[type])) - ret = [this._events[type]]; - else - ret = this._events[type].slice(); - return ret; -}; - -EventEmitter.prototype.listenerCount = function(type) { - if (this._events) { - var evlistener = this._events[type]; - - if (isFunction(evlistener)) - return 1; - else if (evlistener) - return evlistener.length; - } - return 0; -}; - -EventEmitter.listenerCount = function(emitter, type) { - return emitter.listenerCount(type); -}; - -function isFunction(arg) { - return typeof arg === 'function'; -} - -function isNumber(arg) { - return typeof arg === 'number'; -} - -function isObject(arg) { - return typeof arg === 'object' && arg !== null; -} - -function isUndefined(arg) { - return arg === void 0; -} - - -/***/ }), -/* 32 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/* WEBPACK VAR INJECTION */(function(process) { - -if (!process.version || - process.version.indexOf('v0.') === 0 || - process.version.indexOf('v1.') === 0 && process.version.indexOf('v1.8.') !== 0) { - module.exports = { nextTick: nextTick }; -} else { - module.exports = process -} - -function nextTick(fn, arg1, arg2, arg3) { - if (typeof fn !== 'function') { - throw new TypeError('"callback" argument must be a function'); - } - var len = arguments.length; - var args, i; - switch (len) { - case 0: - case 1: - return process.nextTick(fn); - case 2: - return process.nextTick(function afterTickOne() { - fn.call(null, arg1); - }); - case 3: - return process.nextTick(function afterTickTwo() { - fn.call(null, arg1, arg2); - }); - case 4: - return process.nextTick(function afterTickThree() { - fn.call(null, arg1, arg2, arg3); - }); - default: - args = new Array(len - 1); - i = 0; - while (i < args.length) { - args[i++] = arguments[i]; - } - return process.nextTick(function afterTick() { - fn.apply(null, args); - }); - } -} - - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(11))) - -/***/ }), -/* 33 */ -/***/ (function(module, exports, __webpack_require__) { - -/* eslint-disable node/no-deprecated-api */ -var buffer = __webpack_require__(1) -var Buffer = buffer.Buffer - -// alternative to using Object.keys for old browsers -function copyProps (src, dst) { - for (var key in src) { - dst[key] = src[key] - } -} -if (Buffer.from && Buffer.alloc && Buffer.allocUnsafe && Buffer.allocUnsafeSlow) { - module.exports = buffer -} else { - // Copy properties from require('buffer') - copyProps(buffer, exports) - exports.Buffer = SafeBuffer -} - -function SafeBuffer (arg, encodingOrOffset, length) { - return Buffer(arg, encodingOrOffset, length) -} - -// Copy static methods from Buffer -copyProps(Buffer, SafeBuffer) - -SafeBuffer.from = function (arg, encodingOrOffset, length) { - if (typeof arg === 'number') { - throw new TypeError('Argument must not be a number') - } - return Buffer(arg, encodingOrOffset, length) -} - -SafeBuffer.alloc = function (size, fill, encoding) { - if (typeof size !== 'number') { - throw new TypeError('Argument must be a number') - } - var buf = Buffer(size) - if (fill !== undefined) { - if (typeof encoding === 'string') { - buf.fill(fill, encoding) - } else { - buf.fill(fill) - } - } else { - buf.fill(0) - } - return buf -} - -SafeBuffer.allocUnsafe = function (size) { - if (typeof size !== 'number') { - throw new TypeError('Argument must be a number') - } - return Buffer(size) -} - -SafeBuffer.allocUnsafeSlow = function (size) { - if (typeof size !== 'number') { - throw new TypeError('Argument must be a number') - } - return buffer.SlowBuffer(size) -} - - -/***/ }), -/* 34 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - - -var TYPED_OK = (typeof Uint8Array !== 'undefined') && - (typeof Uint16Array !== 'undefined') && - (typeof Int32Array !== 'undefined'); - -function _has(obj, key) { - return Object.prototype.hasOwnProperty.call(obj, key); -} - -exports.assign = function (obj /*from1, from2, from3, ...*/) { - var sources = Array.prototype.slice.call(arguments, 1); - while (sources.length) { - var source = sources.shift(); - if (!source) { continue; } - - if (typeof source !== 'object') { - throw new TypeError(source + 'must be non-object'); - } - - for (var p in source) { - if (_has(source, p)) { - obj[p] = source[p]; - } - } - } - - return obj; -}; - - -// reduce buffer size, avoiding mem copy -exports.shrinkBuf = function (buf, size) { - if (buf.length === size) { return buf; } - if (buf.subarray) { return buf.subarray(0, size); } - buf.length = size; - return buf; -}; - - -var fnTyped = { - arraySet: function (dest, src, src_offs, len, dest_offs) { - if (src.subarray && dest.subarray) { - dest.set(src.subarray(src_offs, src_offs + len), dest_offs); - return; - } - // Fallback to ordinary array - for (var i = 0; i < len; i++) { - dest[dest_offs + i] = src[src_offs + i]; - } - }, - // Join array of chunks to single array. - flattenChunks: function (chunks) { - var i, l, len, pos, chunk, result; - - // calculate data length - len = 0; - for (i = 0, l = chunks.length; i < l; i++) { - len += chunks[i].length; - } - - // join chunks - result = new Uint8Array(len); - pos = 0; - for (i = 0, l = chunks.length; i < l; i++) { - chunk = chunks[i]; - result.set(chunk, pos); - pos += chunk.length; - } - - return result; - } -}; - -var fnUntyped = { - arraySet: function (dest, src, src_offs, len, dest_offs) { - for (var i = 0; i < len; i++) { - dest[dest_offs + i] = src[src_offs + i]; - } - }, - // Join array of chunks to single array. - flattenChunks: function (chunks) { - return [].concat.apply([], chunks); - } -}; - - -// Enable/Disable typed arrays use, for testing -// -exports.setTyped = function (on) { - if (on) { - exports.Buf8 = Uint8Array; - exports.Buf16 = Uint16Array; - exports.Buf32 = Int32Array; - exports.assign(exports, fnTyped); - } else { - exports.Buf8 = Array; - exports.Buf16 = Array; - exports.Buf32 = Array; - exports.assign(exports, fnUntyped); - } -}; - -exports.setTyped(TYPED_OK); - - -/***/ }), -/* 35 */ -/***/ (function(module, exports) { - -exports.f = {}.propertyIsEnumerable; - - -/***/ }), -/* 36 */ -/***/ (function(module, exports, __webpack_require__) { - -// 19.1.2.2 / 15.2.3.5 Object.create(O [, Properties]) -var anObject = __webpack_require__(14); -var dPs = __webpack_require__(100); -var enumBugKeys = __webpack_require__(66); -var IE_PROTO = __webpack_require__(64)('IE_PROTO'); -var Empty = function () { /* empty */ }; -var PROTOTYPE = 'prototype'; - -// Create object with fake `null` prototype: use iframe Object with cleared prototype -var createDict = function () { - // Thrash, waste and sodomy: IE GC bug - var iframe = __webpack_require__(96)('iframe'); - var i = enumBugKeys.length; - var lt = '<'; - var gt = '>'; - var iframeDocument; - iframe.style.display = 'none'; - __webpack_require__(205).appendChild(iframe); - iframe.src = 'javascript:'; // eslint-disable-line no-script-url - // createDict = iframe.contentWindow.Object; - // html.removeChild(iframe); - iframeDocument = iframe.contentWindow.document; - iframeDocument.open(); - iframeDocument.write(lt + 'script' + gt + 'document.F=Object' + lt + '/script' + gt); - iframeDocument.close(); - createDict = iframeDocument.F; - while (i--) delete createDict[PROTOTYPE][enumBugKeys[i]]; - return createDict(); -}; - -module.exports = Object.create || function create(O, Properties) { - var result; - if (O !== null) { - Empty[PROTOTYPE] = anObject(O); - result = new Empty(); - Empty[PROTOTYPE] = null; - // add "__proto__" for Object.getPrototypeOf polyfill - result[IE_PROTO] = O; - } else result = createDict(); - return Properties === undefined ? result : dPs(result, Properties); -}; - - -/***/ }), -/* 37 */ -/***/ (function(module, exports, __webpack_require__) { - -// 7.1.15 ToLength -var toInteger = __webpack_require__(63); -var min = Math.min; -module.exports = function (it) { - return it > 0 ? min(toInteger(it), 0x1fffffffffffff) : 0; // pow(2, 53) - 1 == 9007199254740991 -}; - - -/***/ }), -/* 38 */ -/***/ (function(module, exports) { - -var id = 0; -var px = Math.random(); -module.exports = function (key) { - return 'Symbol('.concat(key === undefined ? '' : key, ')_', (++id + px).toString(36)); -}; - - -/***/ }), -/* 39 */ -/***/ (function(module, exports, __webpack_require__) { - -var def = __webpack_require__(6).f; -var has = __webpack_require__(18); -var TAG = __webpack_require__(4)('toStringTag'); - -module.exports = function (it, tag, stat) { - if (it && !has(it = stat ? it : it.prototype, TAG)) def(it, TAG, { configurable: true, value: tag }); -}; - - -/***/ }), -/* 40 */ -/***/ (function(module, exports, __webpack_require__) { - -var META = __webpack_require__(38)('meta'); -var isObject = __webpack_require__(9); -var has = __webpack_require__(18); -var setDesc = __webpack_require__(6).f; -var id = 0; -var isExtensible = Object.isExtensible || function () { - return true; -}; -var FREEZE = !__webpack_require__(19)(function () { - return isExtensible(Object.preventExtensions({})); -}); -var setMeta = function (it) { - setDesc(it, META, { value: { - i: 'O' + ++id, // object ID - w: {} // weak collections IDs - } }); -}; -var fastKey = function (it, create) { - // return primitive with prefix - if (!isObject(it)) return typeof it == 'symbol' ? it : (typeof it == 'string' ? 'S' : 'P') + it; - if (!has(it, META)) { - // can't set metadata to uncaught frozen object - if (!isExtensible(it)) return 'F'; - // not necessary to add metadata - if (!create) return 'E'; - // add missing metadata - setMeta(it); - // return object ID - } return it[META].i; -}; -var getWeak = function (it, create) { - if (!has(it, META)) { - // can't set metadata to uncaught frozen object - if (!isExtensible(it)) return true; - // not necessary to add metadata - if (!create) return false; - // add missing metadata - setMeta(it); - // return hash weak collections IDs - } return it[META].w; -}; -// add metadata on freeze-family methods calling -var onFreeze = function (it) { - if (FREEZE && meta.NEED && isExtensible(it) && !has(it, META)) setMeta(it); - return it; -}; -var meta = module.exports = { - KEY: META, - NEED: false, - fastKey: fastKey, - getWeak: getWeak, - onFreeze: onFreeze -}; - - -/***/ }), -/* 41 */ -/***/ (function(module, exports, __webpack_require__) { - -var ctx = __webpack_require__(20); -var call = __webpack_require__(111); -var isArrayIter = __webpack_require__(112); -var anObject = __webpack_require__(14); -var toLength = __webpack_require__(37); -var getIterFn = __webpack_require__(67); -var BREAK = {}; -var RETURN = {}; -var exports = module.exports = function (iterable, entries, fn, that, ITERATOR) { - var iterFn = ITERATOR ? function () { return iterable; } : getIterFn(iterable); - var f = ctx(fn, that, entries ? 2 : 1); - var index = 0; - var length, step, iterator, result; - if (typeof iterFn != 'function') throw TypeError(iterable + ' is not iterable!'); - // fast case for arrays with default iterator - if (isArrayIter(iterFn)) for (length = toLength(iterable.length); length > index; index++) { - result = entries ? f(anObject(step = iterable[index])[0], step[1]) : f(iterable[index]); - if (result === BREAK || result === RETURN) return result; - } else for (iterator = iterFn.call(iterable); !(step = iterator.next()).done;) { - result = call(iterator, f, step.value, entries); - if (result === BREAK || result === RETURN) return result; - } -}; -exports.BREAK = BREAK; -exports.RETURN = RETURN; - - -/***/ }), -/* 42 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var isString = __webpack_require__(0).isString; -var isNumber = __webpack_require__(0).isNumber; -var isObject = __webpack_require__(0).isObject; -var isArray = __webpack_require__(0).isArray; -var LineBreaker = __webpack_require__(78); - -var LEADING = /^(\s)+/g; -var TRAILING = /(\s)+$/g; - -/** - * Creates an instance of TextTools - text measurement utility - * - * @constructor - * @param {FontProvider} fontProvider - */ -function TextTools(fontProvider) { - this.fontProvider = fontProvider; -} - -/** - * Converts an array of strings (or inline-definition-objects) into a collection - * of inlines and calculated minWidth/maxWidth. - * and their min/max widths - * @param {Object} textArray - an array of inline-definition-objects (or strings) - * @param {Object} styleContextStack current style stack - * @return {Object} collection of inlines, minWidth, maxWidth - */ -TextTools.prototype.buildInlines = function (textArray, styleContextStack) { - var measured = measure(this.fontProvider, textArray, styleContextStack); - - var minWidth = 0, - maxWidth = 0, - currentLineWidth; - - measured.forEach(function (inline) { - minWidth = Math.max(minWidth, inline.width - inline.leadingCut - inline.trailingCut); - - if (!currentLineWidth) { - currentLineWidth = {width: 0, leadingCut: inline.leadingCut, trailingCut: 0}; - } - - currentLineWidth.width += inline.width; - currentLineWidth.trailingCut = inline.trailingCut; - - maxWidth = Math.max(maxWidth, getTrimmedWidth(currentLineWidth)); - - if (inline.lineEnd) { - currentLineWidth = null; - } - }); - - if (getStyleProperty({}, styleContextStack, 'noWrap', false)) { - minWidth = maxWidth; - } - - return { - items: measured, - minWidth: minWidth, - maxWidth: maxWidth - }; - - function getTrimmedWidth(item) { - return Math.max(0, item.width - item.leadingCut - item.trailingCut); - } -}; - -/** - * Returns size of the specified string (without breaking it) using the current style - * @param {String} text text to be measured - * @param {Object} styleContextStack current style stack - * @return {Object} size of the specified string - */ -TextTools.prototype.sizeOfString = function (text, styleContextStack) { - text = text ? text.toString().replace(/\t/g, ' ') : ''; - - //TODO: refactor - extract from measure - var fontName = getStyleProperty({}, styleContextStack, 'font', 'Roboto'); - var fontSize = getStyleProperty({}, styleContextStack, 'fontSize', 12); - var fontFeatures = getStyleProperty({}, styleContextStack, 'fontFeatures', null); - var bold = getStyleProperty({}, styleContextStack, 'bold', false); - var italics = getStyleProperty({}, styleContextStack, 'italics', false); - var lineHeight = getStyleProperty({}, styleContextStack, 'lineHeight', 1); - var characterSpacing = getStyleProperty({}, styleContextStack, 'characterSpacing', 0); - - var font = this.fontProvider.provideFont(fontName, bold, italics); - - return { - width: widthOfString(text, font, fontSize, characterSpacing, fontFeatures), - height: font.lineHeight(fontSize) * lineHeight, - fontSize: fontSize, - lineHeight: lineHeight, - ascender: font.ascender / 1000 * fontSize, - descender: font.descender / 1000 * fontSize - }; -}; - -TextTools.prototype.widthOfString = function (text, font, fontSize, characterSpacing, fontFeatures) { - return widthOfString(text, font, fontSize, characterSpacing, fontFeatures); -}; - -function splitWords(text, noWrap) { - var results = []; - text = text.replace(/\t/g, ' '); - - if (noWrap) { - results.push({text: text}); - return results; - } - - var breaker = new LineBreaker(text); - var last = 0; - var bk; - - while (bk = breaker.nextBreak()) { - var word = text.slice(last, bk.position); - - if (bk.required || word.match(/\r?\n$|\r$/)) { // new line - word = word.replace(/\r?\n$|\r$/, ''); - results.push({text: word, lineEnd: true}); - } else { - results.push({text: word}); - } - - last = bk.position; - } - - return results; -} - -function copyStyle(source, destination) { - destination = destination || {}; - source = source || {}; //TODO: default style - - for (var key in source) { - if (key != 'text' && source.hasOwnProperty(key)) { - destination[key] = source[key]; - } - } - - return destination; -} - -function normalizeTextArray(array, styleContextStack) { - function flatten(array) { - return array.reduce(function (prev, cur) { - var current = isArray(cur.text) ? flatten(cur.text) : cur; - var more = [].concat(current).some(Array.isArray); - return prev.concat(more ? flatten(current) : current); - }, []); - } - - var results = []; - - if (!isArray(array)) { - array = [array]; - } - - array = flatten(array); - - for (var i = 0, l = array.length; i < l; i++) { - var item = array[i]; - var style = null; - var words; - - var noWrap = getStyleProperty(item || {}, styleContextStack, 'noWrap', false); - if (isObject(item)) { - words = splitWords(normalizeString(item.text), noWrap); - style = copyStyle(item); - } else { - words = splitWords(normalizeString(item), noWrap); - } - - for (var i2 = 0, l2 = words.length; i2 < l2; i2++) { - var result = { - text: words[i2].text - }; - - if (words[i2].lineEnd) { - result.lineEnd = true; - } - - copyStyle(style, result); - - results.push(result); - } - } - - return results; -} - -function normalizeString(value) { - if (value === undefined || value === null) { - return ''; - } else if (isNumber(value)) { - return value.toString(); - } else if (isString(value)) { - return value; - } else { - return value.toString(); - } -} - -function getStyleProperty(item, styleContextStack, property, defaultValue) { - var value; - - if (item[property] !== undefined && item[property] !== null) { - // item defines this property - return item[property]; - } - - if (!styleContextStack) { - return defaultValue; - } - - styleContextStack.auto(item, function () { - value = styleContextStack.getProperty(property); - }); - - if (value !== null && value !== undefined) { - return value; - } else { - return defaultValue; - } -} - -function measure(fontProvider, textArray, styleContextStack) { - var normalized = normalizeTextArray(textArray, styleContextStack); - - if (normalized.length) { - var leadingIndent = getStyleProperty(normalized[0], styleContextStack, 'leadingIndent', 0); - - if (leadingIndent) { - normalized[0].leadingCut = -leadingIndent; - normalized[0].leadingIndent = leadingIndent; - } - } - - normalized.forEach(function (item) { - var fontName = getStyleProperty(item, styleContextStack, 'font', 'Roboto'); - var fontSize = getStyleProperty(item, styleContextStack, 'fontSize', 12); - var fontFeatures = getStyleProperty(item, styleContextStack, 'fontFeatures', null); - var bold = getStyleProperty(item, styleContextStack, 'bold', false); - var italics = getStyleProperty(item, styleContextStack, 'italics', false); - var color = getStyleProperty(item, styleContextStack, 'color', 'black'); - var decoration = getStyleProperty(item, styleContextStack, 'decoration', null); - var decorationColor = getStyleProperty(item, styleContextStack, 'decorationColor', null); - var decorationStyle = getStyleProperty(item, styleContextStack, 'decorationStyle', null); - var background = getStyleProperty(item, styleContextStack, 'background', null); - var lineHeight = getStyleProperty(item, styleContextStack, 'lineHeight', 1); - var characterSpacing = getStyleProperty(item, styleContextStack, 'characterSpacing', 0); - var link = getStyleProperty(item, styleContextStack, 'link', null); - var linkToPage = getStyleProperty(item, styleContextStack, 'linkToPage', null); - var noWrap = getStyleProperty(item, styleContextStack, 'noWrap', null); - var preserveLeadingSpaces = getStyleProperty(item, styleContextStack, 'preserveLeadingSpaces', false); - - var font = fontProvider.provideFont(fontName, bold, italics); - - item.width = widthOfString(item.text, font, fontSize, characterSpacing, fontFeatures); - item.height = font.lineHeight(fontSize) * lineHeight; - - var leadingSpaces = item.text.match(LEADING); - - if (!item.leadingCut) { - item.leadingCut = 0; - } - - if (leadingSpaces && !preserveLeadingSpaces) { - item.leadingCut += widthOfString(leadingSpaces[0], font, fontSize, characterSpacing, fontFeatures); - } - - var trailingSpaces = item.text.match(TRAILING); - if (trailingSpaces) { - item.trailingCut = widthOfString(trailingSpaces[0], font, fontSize, characterSpacing, fontFeatures); - } else { - item.trailingCut = 0; - } - - item.alignment = getStyleProperty(item, styleContextStack, 'alignment', 'left'); - item.font = font; - item.fontSize = fontSize; - item.fontFeatures = fontFeatures; - item.characterSpacing = characterSpacing; - item.color = color; - item.decoration = decoration; - item.decorationColor = decorationColor; - item.decorationStyle = decorationStyle; - item.background = background; - item.link = link; - item.linkToPage = linkToPage; - item.noWrap = noWrap; - }); - - return normalized; -} - -function widthOfString(text, font, fontSize, characterSpacing, fontFeatures) { - return font.widthOfString(text, fontSize, fontFeatures) + ((characterSpacing || 0) * (text.length - 1)); -} - -module.exports = TextTools; - - -/***/ }), -/* 43 */ -/***/ (function(module, exports, __webpack_require__) { - -// Generated by CoffeeScript 1.7.1 -var UnicodeTrie, inflate; - -inflate = __webpack_require__(79); - -UnicodeTrie = (function() { - var DATA_BLOCK_LENGTH, DATA_GRANULARITY, DATA_MASK, INDEX_1_OFFSET, INDEX_2_BLOCK_LENGTH, INDEX_2_BMP_LENGTH, INDEX_2_MASK, INDEX_SHIFT, LSCP_INDEX_2_LENGTH, LSCP_INDEX_2_OFFSET, OMITTED_BMP_INDEX_1_LENGTH, SHIFT_1, SHIFT_1_2, SHIFT_2, UTF8_2B_INDEX_2_LENGTH, UTF8_2B_INDEX_2_OFFSET; - - SHIFT_1 = 6 + 5; - - SHIFT_2 = 5; - - SHIFT_1_2 = SHIFT_1 - SHIFT_2; - - OMITTED_BMP_INDEX_1_LENGTH = 0x10000 >> SHIFT_1; - - INDEX_2_BLOCK_LENGTH = 1 << SHIFT_1_2; - - INDEX_2_MASK = INDEX_2_BLOCK_LENGTH - 1; - - INDEX_SHIFT = 2; - - DATA_BLOCK_LENGTH = 1 << SHIFT_2; - - DATA_MASK = DATA_BLOCK_LENGTH - 1; - - LSCP_INDEX_2_OFFSET = 0x10000 >> SHIFT_2; - - LSCP_INDEX_2_LENGTH = 0x400 >> SHIFT_2; - - INDEX_2_BMP_LENGTH = LSCP_INDEX_2_OFFSET + LSCP_INDEX_2_LENGTH; - - UTF8_2B_INDEX_2_OFFSET = INDEX_2_BMP_LENGTH; - - UTF8_2B_INDEX_2_LENGTH = 0x800 >> 6; - - INDEX_1_OFFSET = UTF8_2B_INDEX_2_OFFSET + UTF8_2B_INDEX_2_LENGTH; - - DATA_GRANULARITY = 1 << INDEX_SHIFT; - - function UnicodeTrie(data) { - var isBuffer, uncompressedLength, view; - isBuffer = typeof data.readUInt32BE === 'function' && typeof data.slice === 'function'; - if (isBuffer || data instanceof Uint8Array) { - if (isBuffer) { - this.highStart = data.readUInt32BE(0); - this.errorValue = data.readUInt32BE(4); - uncompressedLength = data.readUInt32BE(8); - data = data.slice(12); - } else { - view = new DataView(data.buffer); - this.highStart = view.getUint32(0); - this.errorValue = view.getUint32(4); - uncompressedLength = view.getUint32(8); - data = data.subarray(12); - } - data = inflate(data, new Uint8Array(uncompressedLength)); - data = inflate(data, new Uint8Array(uncompressedLength)); - this.data = new Uint32Array(data.buffer); - } else { - this.data = data.data, this.highStart = data.highStart, this.errorValue = data.errorValue; - } - } - - UnicodeTrie.prototype.get = function(codePoint) { - var index; - if (codePoint < 0 || codePoint > 0x10ffff) { - return this.errorValue; - } - if (codePoint < 0xd800 || (codePoint > 0xdbff && codePoint <= 0xffff)) { - index = (this.data[codePoint >> SHIFT_2] << INDEX_SHIFT) + (codePoint & DATA_MASK); - return this.data[index]; - } - if (codePoint <= 0xffff) { - index = (this.data[LSCP_INDEX_2_OFFSET + ((codePoint - 0xd800) >> SHIFT_2)] << INDEX_SHIFT) + (codePoint & DATA_MASK); - return this.data[index]; - } - if (codePoint < this.highStart) { - index = this.data[(INDEX_1_OFFSET - OMITTED_BMP_INDEX_1_LENGTH) + (codePoint >> SHIFT_1)]; - index = this.data[index + ((codePoint >> SHIFT_2) & INDEX_2_MASK)]; - index = (index << INDEX_SHIFT) + (codePoint & DATA_MASK); - return this.data[index]; - } - return this.data[this.data.length - DATA_GRANULARITY]; - }; - - return UnicodeTrie; - -})(); - -module.exports = UnicodeTrie; - - -/***/ }), -/* 44 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var isString = __webpack_require__(0).isString; - -function buildColumnWidths(columns, availableWidth) { - var autoColumns = [], - autoMin = 0, autoMax = 0, - starColumns = [], - starMaxMin = 0, - starMaxMax = 0, - fixedColumns = [], - initial_availableWidth = availableWidth; - - columns.forEach(function (column) { - if (isAutoColumn(column)) { - autoColumns.push(column); - autoMin += column._minWidth; - autoMax += column._maxWidth; - } else if (isStarColumn(column)) { - starColumns.push(column); - starMaxMin = Math.max(starMaxMin, column._minWidth); - starMaxMax = Math.max(starMaxMax, column._maxWidth); - } else { - fixedColumns.push(column); - } - }); - - fixedColumns.forEach(function (col) { - // width specified as % - if (isString(col.width) && /\d+%/.test(col.width)) { - col.width = parseFloat(col.width) * initial_availableWidth / 100; - } - if (col.width < (col._minWidth) && col.elasticWidth) { - col._calcWidth = col._minWidth; - } else { - col._calcWidth = col.width; - } - - availableWidth -= col._calcWidth; - }); - - // http://www.freesoft.org/CIE/RFC/1942/18.htm - // http://www.w3.org/TR/CSS2/tables.html#width-layout - // http://dev.w3.org/csswg/css3-tables-algorithms/Overview.src.htm - var minW = autoMin + starMaxMin * starColumns.length; - var maxW = autoMax + starMaxMax * starColumns.length; - if (minW >= availableWidth) { - // case 1 - there's no way to fit all columns within available width - // that's actually pretty bad situation with PDF as we have no horizontal scroll - // no easy workaround (unless we decide, in the future, to split single words) - // currently we simply use minWidths for all columns - autoColumns.forEach(function (col) { - col._calcWidth = col._minWidth; - }); - - starColumns.forEach(function (col) { - col._calcWidth = starMaxMin; // starMaxMin already contains padding - }); - } else { - if (maxW < availableWidth) { - // case 2 - we can fit rest of the table within available space - autoColumns.forEach(function (col) { - col._calcWidth = col._maxWidth; - availableWidth -= col._calcWidth; - }); - } else { - // maxW is too large, but minW fits within available width - var W = availableWidth - minW; - var D = maxW - minW; - - autoColumns.forEach(function (col) { - var d = col._maxWidth - col._minWidth; - col._calcWidth = col._minWidth + d * W / D; - availableWidth -= col._calcWidth; - }); - } - - if (starColumns.length > 0) { - var starSize = availableWidth / starColumns.length; - - starColumns.forEach(function (col) { - col._calcWidth = starSize; - }); - } - } -} - -function isAutoColumn(column) { - return column.width === 'auto'; -} - -function isStarColumn(column) { - return column.width === null || column.width === undefined || column.width === '*' || column.width === 'star'; -} - -//TODO: refactor and reuse in measureTable -function measureMinMax(columns) { - var result = {min: 0, max: 0}; - - var maxStar = {min: 0, max: 0}; - var starCount = 0; - - for (var i = 0, l = columns.length; i < l; i++) { - var c = columns[i]; - - if (isStarColumn(c)) { - maxStar.min = Math.max(maxStar.min, c._minWidth); - maxStar.max = Math.max(maxStar.max, c._maxWidth); - starCount++; - } else if (isAutoColumn(c)) { - result.min += c._minWidth; - result.max += c._maxWidth; - } else { - result.min += ((c.width !== undefined && c.width) || c._minWidth); - result.max += ((c.width !== undefined && c.width) || c._maxWidth); - } - } - - if (starCount) { - result.min += starCount * maxStar.min; - result.max += starCount * maxStar.max; - } - - return result; -} - -/** - * Calculates column widths - * @private - */ -module.exports = { - buildColumnWidths: buildColumnWidths, - measureMinMax: measureMinMax, - isAutoColumn: isAutoColumn, - isStarColumn: isStarColumn -}; - - -/***/ }), -/* 45 */ -/***/ (function(module, exports, __webpack_require__) { - -exports = module.exports = __webpack_require__(83); -exports.Stream = exports; -exports.Readable = exports; -exports.Writable = __webpack_require__(46); -exports.Duplex = __webpack_require__(16); -exports.Transform = __webpack_require__(86); -exports.PassThrough = __webpack_require__(145); - - -/***/ }), -/* 46 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/* WEBPACK VAR INJECTION */(function(process, setImmediate, global) {// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -// A bit simpler than readable streams. -// Implement an async ._write(chunk, encoding, cb), and it'll handle all -// the drain event emission and buffering. - - - -/**/ - -var processNextTick = __webpack_require__(32).nextTick; -/**/ - -module.exports = Writable; - -/* */ -function WriteReq(chunk, encoding, cb) { - this.chunk = chunk; - this.encoding = encoding; - this.callback = cb; - this.next = null; -} - -// It seems a linked list but it is not -// there will be only 2 of these for each stream -function CorkedRequest(state) { - var _this = this; - - this.next = null; - this.entry = null; - this.finish = function () { - onCorkedFinish(_this, state); - }; -} -/* */ - -/**/ -var asyncWrite = !process.browser && ['v0.10', 'v0.9.'].indexOf(process.version.slice(0, 5)) > -1 ? setImmediate : processNextTick; -/**/ - -/**/ -var Duplex; -/**/ - -Writable.WritableState = WritableState; - -/**/ -var util = __webpack_require__(25); -util.inherits = __webpack_require__(21); -/**/ - -/**/ -var internalUtil = { - deprecate: __webpack_require__(144) -}; -/**/ - -/**/ -var Stream = __webpack_require__(84); -/**/ - -/**/ - -var Buffer = __webpack_require__(33).Buffer; -var OurUint8Array = global.Uint8Array || function () {}; -function _uint8ArrayToBuffer(chunk) { - return Buffer.from(chunk); -} -function _isUint8Array(obj) { - return Buffer.isBuffer(obj) || obj instanceof OurUint8Array; -} - -/**/ - -var destroyImpl = __webpack_require__(85); - -util.inherits(Writable, Stream); - -function nop() {} - -function WritableState(options, stream) { - Duplex = Duplex || __webpack_require__(16); - - options = options || {}; - - // Duplex streams are both readable and writable, but share - // the same options object. - // However, some cases require setting options to different - // values for the readable and the writable sides of the duplex stream. - // These options can be provided separately as readableXXX and writableXXX. - var isDuplex = stream instanceof Duplex; - - // object stream flag to indicate whether or not this stream - // contains buffers or objects. - this.objectMode = !!options.objectMode; - - if (isDuplex) this.objectMode = this.objectMode || !!options.writableObjectMode; - - // the point at which write() starts returning false - // Note: 0 is a valid value, means that we always return false if - // the entire buffer is not flushed immediately on write() - var hwm = options.highWaterMark; - var writableHwm = options.writableHighWaterMark; - var defaultHwm = this.objectMode ? 16 : 16 * 1024; - - if (hwm || hwm === 0) this.highWaterMark = hwm;else if (isDuplex && (writableHwm || writableHwm === 0)) this.highWaterMark = writableHwm;else this.highWaterMark = defaultHwm; - - // cast to ints. - this.highWaterMark = Math.floor(this.highWaterMark); - - // if _final has been called - this.finalCalled = false; - - // drain event flag. - this.needDrain = false; - // at the start of calling end() - this.ending = false; - // when end() has been called, and returned - this.ended = false; - // when 'finish' is emitted - this.finished = false; - - // has it been destroyed - this.destroyed = false; - - // should we decode strings into buffers before passing to _write? - // this is here so that some node-core streams can optimize string - // handling at a lower level. - var noDecode = options.decodeStrings === false; - this.decodeStrings = !noDecode; - - // Crypto is kind of old and crusty. Historically, its default string - // encoding is 'binary' so we have to make this configurable. - // Everything else in the universe uses 'utf8', though. - this.defaultEncoding = options.defaultEncoding || 'utf8'; - - // not an actual buffer we keep track of, but a measurement - // of how much we're waiting to get pushed to some underlying - // socket or file. - this.length = 0; - - // a flag to see when we're in the middle of a write. - this.writing = false; - - // when true all writes will be buffered until .uncork() call - this.corked = 0; - - // a flag to be able to tell if the onwrite cb is called immediately, - // or on a later tick. We set this to true at first, because any - // actions that shouldn't happen until "later" should generally also - // not happen before the first write call. - this.sync = true; - - // a flag to know if we're processing previously buffered items, which - // may call the _write() callback in the same tick, so that we don't - // end up in an overlapped onwrite situation. - this.bufferProcessing = false; - - // the callback that's passed to _write(chunk,cb) - this.onwrite = function (er) { - onwrite(stream, er); - }; - - // the callback that the user supplies to write(chunk,encoding,cb) - this.writecb = null; - - // the amount that is being written when _write is called. - this.writelen = 0; - - this.bufferedRequest = null; - this.lastBufferedRequest = null; - - // number of pending user-supplied write callbacks - // this must be 0 before 'finish' can be emitted - this.pendingcb = 0; - - // emit prefinish if the only thing we're waiting for is _write cbs - // This is relevant for synchronous Transform streams - this.prefinished = false; - - // True if the error was already emitted and should not be thrown again - this.errorEmitted = false; - - // count buffered requests - this.bufferedRequestCount = 0; - - // allocate the first CorkedRequest, there is always - // one allocated and free to use, and we maintain at most two - this.corkedRequestsFree = new CorkedRequest(this); -} - -WritableState.prototype.getBuffer = function getBuffer() { - var current = this.bufferedRequest; - var out = []; - while (current) { - out.push(current); - current = current.next; - } - return out; -}; - -(function () { - try { - Object.defineProperty(WritableState.prototype, 'buffer', { - get: internalUtil.deprecate(function () { - return this.getBuffer(); - }, '_writableState.buffer is deprecated. Use _writableState.getBuffer ' + 'instead.', 'DEP0003') - }); - } catch (_) {} -})(); - -// Test _writableState for inheritance to account for Duplex streams, -// whose prototype chain only points to Readable. -var realHasInstance; -if (typeof Symbol === 'function' && Symbol.hasInstance && typeof Function.prototype[Symbol.hasInstance] === 'function') { - realHasInstance = Function.prototype[Symbol.hasInstance]; - Object.defineProperty(Writable, Symbol.hasInstance, { - value: function (object) { - if (realHasInstance.call(this, object)) return true; - if (this !== Writable) return false; - - return object && object._writableState instanceof WritableState; - } - }); -} else { - realHasInstance = function (object) { - return object instanceof this; - }; -} - -function Writable(options) { - Duplex = Duplex || __webpack_require__(16); - - // Writable ctor is applied to Duplexes, too. - // `realHasInstance` is necessary because using plain `instanceof` - // would return false, as no `_writableState` property is attached. - - // Trying to use the custom `instanceof` for Writable here will also break the - // Node.js LazyTransform implementation, which has a non-trivial getter for - // `_writableState` that would lead to infinite recursion. - if (!realHasInstance.call(Writable, this) && !(this instanceof Duplex)) { - return new Writable(options); - } - - this._writableState = new WritableState(options, this); - - // legacy. - this.writable = true; - - if (options) { - if (typeof options.write === 'function') this._write = options.write; - - if (typeof options.writev === 'function') this._writev = options.writev; - - if (typeof options.destroy === 'function') this._destroy = options.destroy; - - if (typeof options.final === 'function') this._final = options.final; - } - - Stream.call(this); -} - -// Otherwise people can pipe Writable streams, which is just wrong. -Writable.prototype.pipe = function () { - this.emit('error', new Error('Cannot pipe, not readable')); -}; - -function writeAfterEnd(stream, cb) { - var er = new Error('write after end'); - // TODO: defer error events consistently everywhere, not just the cb - stream.emit('error', er); - processNextTick(cb, er); -} - -// Checks that a user-supplied chunk is valid, especially for the particular -// mode the stream is in. Currently this means that `null` is never accepted -// and undefined/non-string values are only allowed in object mode. -function validChunk(stream, state, chunk, cb) { - var valid = true; - var er = false; - - if (chunk === null) { - er = new TypeError('May not write null values to stream'); - } else if (typeof chunk !== 'string' && chunk !== undefined && !state.objectMode) { - er = new TypeError('Invalid non-string/buffer chunk'); - } - if (er) { - stream.emit('error', er); - processNextTick(cb, er); - valid = false; - } - return valid; -} - -Writable.prototype.write = function (chunk, encoding, cb) { - var state = this._writableState; - var ret = false; - var isBuf = !state.objectMode && _isUint8Array(chunk); - - if (isBuf && !Buffer.isBuffer(chunk)) { - chunk = _uint8ArrayToBuffer(chunk); - } - - if (typeof encoding === 'function') { - cb = encoding; - encoding = null; - } - - if (isBuf) encoding = 'buffer';else if (!encoding) encoding = state.defaultEncoding; - - if (typeof cb !== 'function') cb = nop; - - if (state.ended) writeAfterEnd(this, cb);else if (isBuf || validChunk(this, state, chunk, cb)) { - state.pendingcb++; - ret = writeOrBuffer(this, state, isBuf, chunk, encoding, cb); - } - - return ret; -}; - -Writable.prototype.cork = function () { - var state = this._writableState; - - state.corked++; -}; - -Writable.prototype.uncork = function () { - var state = this._writableState; - - if (state.corked) { - state.corked--; - - if (!state.writing && !state.corked && !state.finished && !state.bufferProcessing && state.bufferedRequest) clearBuffer(this, state); - } -}; - -Writable.prototype.setDefaultEncoding = function setDefaultEncoding(encoding) { - // node::ParseEncoding() requires lower case. - if (typeof encoding === 'string') encoding = encoding.toLowerCase(); - if (!(['hex', 'utf8', 'utf-8', 'ascii', 'binary', 'base64', 'ucs2', 'ucs-2', 'utf16le', 'utf-16le', 'raw'].indexOf((encoding + '').toLowerCase()) > -1)) throw new TypeError('Unknown encoding: ' + encoding); - this._writableState.defaultEncoding = encoding; - return this; -}; - -function decodeChunk(state, chunk, encoding) { - if (!state.objectMode && state.decodeStrings !== false && typeof chunk === 'string') { - chunk = Buffer.from(chunk, encoding); - } - return chunk; -} - -// if we're already writing something, then just put this -// in the queue, and wait our turn. Otherwise, call _write -// If we return false, then we need a drain event, so set that flag. -function writeOrBuffer(stream, state, isBuf, chunk, encoding, cb) { - if (!isBuf) { - var newChunk = decodeChunk(state, chunk, encoding); - if (chunk !== newChunk) { - isBuf = true; - encoding = 'buffer'; - chunk = newChunk; - } - } - var len = state.objectMode ? 1 : chunk.length; - - state.length += len; - - var ret = state.length < state.highWaterMark; - // we must ensure that previous needDrain will not be reset to false. - if (!ret) state.needDrain = true; - - if (state.writing || state.corked) { - var last = state.lastBufferedRequest; - state.lastBufferedRequest = { - chunk: chunk, - encoding: encoding, - isBuf: isBuf, - callback: cb, - next: null - }; - if (last) { - last.next = state.lastBufferedRequest; - } else { - state.bufferedRequest = state.lastBufferedRequest; - } - state.bufferedRequestCount += 1; - } else { - doWrite(stream, state, false, len, chunk, encoding, cb); - } - - return ret; -} - -function doWrite(stream, state, writev, len, chunk, encoding, cb) { - state.writelen = len; - state.writecb = cb; - state.writing = true; - state.sync = true; - if (writev) stream._writev(chunk, state.onwrite);else stream._write(chunk, encoding, state.onwrite); - state.sync = false; -} - -function onwriteError(stream, state, sync, er, cb) { - --state.pendingcb; - - if (sync) { - // defer the callback if we are being called synchronously - // to avoid piling up things on the stack - processNextTick(cb, er); - // this can emit finish, and it will always happen - // after error - processNextTick(finishMaybe, stream, state); - stream._writableState.errorEmitted = true; - stream.emit('error', er); - } else { - // the caller expect this to happen before if - // it is async - cb(er); - stream._writableState.errorEmitted = true; - stream.emit('error', er); - // this can emit finish, but finish must - // always follow error - finishMaybe(stream, state); - } -} - -function onwriteStateUpdate(state) { - state.writing = false; - state.writecb = null; - state.length -= state.writelen; - state.writelen = 0; -} - -function onwrite(stream, er) { - var state = stream._writableState; - var sync = state.sync; - var cb = state.writecb; - - onwriteStateUpdate(state); - - if (er) onwriteError(stream, state, sync, er, cb);else { - // Check if we're actually ready to finish, but don't emit yet - var finished = needFinish(state); - - if (!finished && !state.corked && !state.bufferProcessing && state.bufferedRequest) { - clearBuffer(stream, state); - } - - if (sync) { - /**/ - asyncWrite(afterWrite, stream, state, finished, cb); - /**/ - } else { - afterWrite(stream, state, finished, cb); - } - } -} - -function afterWrite(stream, state, finished, cb) { - if (!finished) onwriteDrain(stream, state); - state.pendingcb--; - cb(); - finishMaybe(stream, state); -} - -// Must force callback to be called on nextTick, so that we don't -// emit 'drain' before the write() consumer gets the 'false' return -// value, and has a chance to attach a 'drain' listener. -function onwriteDrain(stream, state) { - if (state.length === 0 && state.needDrain) { - state.needDrain = false; - stream.emit('drain'); - } -} - -// if there's something in the buffer waiting, then process it -function clearBuffer(stream, state) { - state.bufferProcessing = true; - var entry = state.bufferedRequest; - - if (stream._writev && entry && entry.next) { - // Fast case, write everything using _writev() - var l = state.bufferedRequestCount; - var buffer = new Array(l); - var holder = state.corkedRequestsFree; - holder.entry = entry; - - var count = 0; - var allBuffers = true; - while (entry) { - buffer[count] = entry; - if (!entry.isBuf) allBuffers = false; - entry = entry.next; - count += 1; - } - buffer.allBuffers = allBuffers; - - doWrite(stream, state, true, state.length, buffer, '', holder.finish); - - // doWrite is almost always async, defer these to save a bit of time - // as the hot path ends with doWrite - state.pendingcb++; - state.lastBufferedRequest = null; - if (holder.next) { - state.corkedRequestsFree = holder.next; - holder.next = null; - } else { - state.corkedRequestsFree = new CorkedRequest(state); - } - state.bufferedRequestCount = 0; - } else { - // Slow case, write chunks one-by-one - while (entry) { - var chunk = entry.chunk; - var encoding = entry.encoding; - var cb = entry.callback; - var len = state.objectMode ? 1 : chunk.length; - - doWrite(stream, state, false, len, chunk, encoding, cb); - entry = entry.next; - state.bufferedRequestCount--; - // if we didn't call the onwrite immediately, then - // it means that we need to wait until it does. - // also, that means that the chunk and cb are currently - // being processed, so move the buffer counter past them. - if (state.writing) { - break; - } - } - - if (entry === null) state.lastBufferedRequest = null; - } - - state.bufferedRequest = entry; - state.bufferProcessing = false; -} - -Writable.prototype._write = function (chunk, encoding, cb) { - cb(new Error('_write() is not implemented')); -}; - -Writable.prototype._writev = null; - -Writable.prototype.end = function (chunk, encoding, cb) { - var state = this._writableState; - - if (typeof chunk === 'function') { - cb = chunk; - chunk = null; - encoding = null; - } else if (typeof encoding === 'function') { - cb = encoding; - encoding = null; - } - - if (chunk !== null && chunk !== undefined) this.write(chunk, encoding); - - // .end() fully uncorks - if (state.corked) { - state.corked = 1; - this.uncork(); - } - - // ignore unnecessary end() calls. - if (!state.ending && !state.finished) endWritable(this, state, cb); -}; - -function needFinish(state) { - return state.ending && state.length === 0 && state.bufferedRequest === null && !state.finished && !state.writing; -} -function callFinal(stream, state) { - stream._final(function (err) { - state.pendingcb--; - if (err) { - stream.emit('error', err); - } - state.prefinished = true; - stream.emit('prefinish'); - finishMaybe(stream, state); - }); -} -function prefinish(stream, state) { - if (!state.prefinished && !state.finalCalled) { - if (typeof stream._final === 'function') { - state.pendingcb++; - state.finalCalled = true; - processNextTick(callFinal, stream, state); - } else { - state.prefinished = true; - stream.emit('prefinish'); - } - } -} - -function finishMaybe(stream, state) { - var need = needFinish(state); - if (need) { - prefinish(stream, state); - if (state.pendingcb === 0) { - state.finished = true; - stream.emit('finish'); - } - } - return need; -} - -function endWritable(stream, state, cb) { - state.ending = true; - finishMaybe(stream, state); - if (cb) { - if (state.finished) processNextTick(cb);else stream.once('finish', cb); - } - state.ended = true; - stream.writable = false; -} - -function onCorkedFinish(corkReq, state, err) { - var entry = corkReq.entry; - corkReq.entry = null; - while (entry) { - var cb = entry.callback; - state.pendingcb--; - cb(err); - entry = entry.next; - } - if (state.corkedRequestsFree) { - state.corkedRequestsFree.next = corkReq; - } else { - state.corkedRequestsFree = corkReq; - } -} - -Object.defineProperty(Writable.prototype, 'destroyed', { - get: function () { - if (this._writableState === undefined) { - return false; - } - return this._writableState.destroyed; - }, - set: function (value) { - // we ignore the value if the stream - // has not been initialized yet - if (!this._writableState) { - return; - } - - // backward compatibility, the user is explicitly - // managing destroyed - this._writableState.destroyed = value; - } -}); - -Writable.prototype.destroy = destroyImpl.destroy; -Writable.prototype._undestroy = destroyImpl.undestroy; -Writable.prototype._destroy = function (err, cb) { - this.end(); - cb(err); -}; -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(11), __webpack_require__(142).setImmediate, __webpack_require__(7))) - -/***/ }), -/* 47 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var Buffer = __webpack_require__(33).Buffer; - -var isEncoding = Buffer.isEncoding || function (encoding) { - encoding = '' + encoding; - switch (encoding && encoding.toLowerCase()) { - case 'hex':case 'utf8':case 'utf-8':case 'ascii':case 'binary':case 'base64':case 'ucs2':case 'ucs-2':case 'utf16le':case 'utf-16le':case 'raw': - return true; - default: - return false; - } -}; - -function _normalizeEncoding(enc) { - if (!enc) return 'utf8'; - var retried; - while (true) { - switch (enc) { - case 'utf8': - case 'utf-8': - return 'utf8'; - case 'ucs2': - case 'ucs-2': - case 'utf16le': - case 'utf-16le': - return 'utf16le'; - case 'latin1': - case 'binary': - return 'latin1'; - case 'base64': - case 'ascii': - case 'hex': - return enc; - default: - if (retried) return; // undefined - enc = ('' + enc).toLowerCase(); - retried = true; - } - } -}; - -// Do not cache `Buffer.isEncoding` when checking encoding names as some -// modules monkey-patch it to support additional encodings -function normalizeEncoding(enc) { - var nenc = _normalizeEncoding(enc); - if (typeof nenc !== 'string' && (Buffer.isEncoding === isEncoding || !isEncoding(enc))) throw new Error('Unknown encoding: ' + enc); - return nenc || enc; -} - -// StringDecoder provides an interface for efficiently splitting a series of -// buffers into a series of JS strings without breaking apart multi-byte -// characters. -exports.StringDecoder = StringDecoder; -function StringDecoder(encoding) { - this.encoding = normalizeEncoding(encoding); - var nb; - switch (this.encoding) { - case 'utf16le': - this.text = utf16Text; - this.end = utf16End; - nb = 4; - break; - case 'utf8': - this.fillLast = utf8FillLast; - nb = 4; - break; - case 'base64': - this.text = base64Text; - this.end = base64End; - nb = 3; - break; - default: - this.write = simpleWrite; - this.end = simpleEnd; - return; - } - this.lastNeed = 0; - this.lastTotal = 0; - this.lastChar = Buffer.allocUnsafe(nb); -} - -StringDecoder.prototype.write = function (buf) { - if (buf.length === 0) return ''; - var r; - var i; - if (this.lastNeed) { - r = this.fillLast(buf); - if (r === undefined) return ''; - i = this.lastNeed; - this.lastNeed = 0; - } else { - i = 0; - } - if (i < buf.length) return r ? r + this.text(buf, i) : this.text(buf, i); - return r || ''; -}; - -StringDecoder.prototype.end = utf8End; - -// Returns only complete characters in a Buffer -StringDecoder.prototype.text = utf8Text; - -// Attempts to complete a partial non-UTF-8 character using bytes from a Buffer -StringDecoder.prototype.fillLast = function (buf) { - if (this.lastNeed <= buf.length) { - buf.copy(this.lastChar, this.lastTotal - this.lastNeed, 0, this.lastNeed); - return this.lastChar.toString(this.encoding, 0, this.lastTotal); - } - buf.copy(this.lastChar, this.lastTotal - this.lastNeed, 0, buf.length); - this.lastNeed -= buf.length; -}; - -// Checks the type of a UTF-8 byte, whether it's ASCII, a leading byte, or a -// continuation byte. -function utf8CheckByte(byte) { - if (byte <= 0x7F) return 0;else if (byte >> 5 === 0x06) return 2;else if (byte >> 4 === 0x0E) return 3;else if (byte >> 3 === 0x1E) return 4; - return -1; -} - -// Checks at most 3 bytes at the end of a Buffer in order to detect an -// incomplete multi-byte UTF-8 character. The total number of bytes (2, 3, or 4) -// needed to complete the UTF-8 character (if applicable) are returned. -function utf8CheckIncomplete(self, buf, i) { - var j = buf.length - 1; - if (j < i) return 0; - var nb = utf8CheckByte(buf[j]); - if (nb >= 0) { - if (nb > 0) self.lastNeed = nb - 1; - return nb; - } - if (--j < i) return 0; - nb = utf8CheckByte(buf[j]); - if (nb >= 0) { - if (nb > 0) self.lastNeed = nb - 2; - return nb; - } - if (--j < i) return 0; - nb = utf8CheckByte(buf[j]); - if (nb >= 0) { - if (nb > 0) { - if (nb === 2) nb = 0;else self.lastNeed = nb - 3; - } - return nb; - } - return 0; -} - -// Validates as many continuation bytes for a multi-byte UTF-8 character as -// needed or are available. If we see a non-continuation byte where we expect -// one, we "replace" the validated continuation bytes we've seen so far with -// UTF-8 replacement characters ('\ufffd'), to match v8's UTF-8 decoding -// behavior. The continuation byte check is included three times in the case -// where all of the continuation bytes for a character exist in the same buffer. -// It is also done this way as a slight performance increase instead of using a -// loop. -function utf8CheckExtraBytes(self, buf, p) { - if ((buf[0] & 0xC0) !== 0x80) { - self.lastNeed = 0; - return '\ufffd'.repeat(p); - } - if (self.lastNeed > 1 && buf.length > 1) { - if ((buf[1] & 0xC0) !== 0x80) { - self.lastNeed = 1; - return '\ufffd'.repeat(p + 1); - } - if (self.lastNeed > 2 && buf.length > 2) { - if ((buf[2] & 0xC0) !== 0x80) { - self.lastNeed = 2; - return '\ufffd'.repeat(p + 2); - } - } - } -} - -// Attempts to complete a multi-byte UTF-8 character using bytes from a Buffer. -function utf8FillLast(buf) { - var p = this.lastTotal - this.lastNeed; - var r = utf8CheckExtraBytes(this, buf, p); - if (r !== undefined) return r; - if (this.lastNeed <= buf.length) { - buf.copy(this.lastChar, p, 0, this.lastNeed); - return this.lastChar.toString(this.encoding, 0, this.lastTotal); - } - buf.copy(this.lastChar, p, 0, buf.length); - this.lastNeed -= buf.length; -} - -// Returns all complete UTF-8 characters in a Buffer. If the Buffer ended on a -// partial character, the character's bytes are buffered until the required -// number of bytes are available. -function utf8Text(buf, i) { - var total = utf8CheckIncomplete(this, buf, i); - if (!this.lastNeed) return buf.toString('utf8', i); - this.lastTotal = total; - var end = buf.length - (total - this.lastNeed); - buf.copy(this.lastChar, 0, end); - return buf.toString('utf8', i, end); -} - -// For UTF-8, a replacement character for each buffered byte of a (partial) -// character needs to be added to the output. -function utf8End(buf) { - var r = buf && buf.length ? this.write(buf) : ''; - if (this.lastNeed) return r + '\ufffd'.repeat(this.lastTotal - this.lastNeed); - return r; -} - -// UTF-16LE typically needs two bytes per character, but even if we have an even -// number of bytes available, we need to check if we end on a leading/high -// surrogate. In that case, we need to wait for the next two bytes in order to -// decode the last character properly. -function utf16Text(buf, i) { - if ((buf.length - i) % 2 === 0) { - var r = buf.toString('utf16le', i); - if (r) { - var c = r.charCodeAt(r.length - 1); - if (c >= 0xD800 && c <= 0xDBFF) { - this.lastNeed = 2; - this.lastTotal = 4; - this.lastChar[0] = buf[buf.length - 2]; - this.lastChar[1] = buf[buf.length - 1]; - return r.slice(0, -1); - } - } - return r; - } - this.lastNeed = 1; - this.lastTotal = 2; - this.lastChar[0] = buf[buf.length - 1]; - return buf.toString('utf16le', i, buf.length - 1); -} - -// For UTF-16LE we do not explicitly append special replacement characters if we -// end on a partial character, we simply let v8 handle that. -function utf16End(buf) { - var r = buf && buf.length ? this.write(buf) : ''; - if (this.lastNeed) { - var end = this.lastTotal - this.lastNeed; - return r + this.lastChar.toString('utf16le', 0, end); - } - return r; -} - -function base64Text(buf, i) { - var n = (buf.length - i) % 3; - if (n === 0) return buf.toString('base64', i); - this.lastNeed = 3 - n; - this.lastTotal = 3; - if (n === 1) { - this.lastChar[0] = buf[buf.length - 1]; - } else { - this.lastChar[0] = buf[buf.length - 2]; - this.lastChar[1] = buf[buf.length - 1]; - } - return buf.toString('base64', i, buf.length - n); -} - -function base64End(buf) { - var r = buf && buf.length ? this.write(buf) : ''; - if (this.lastNeed) return r + this.lastChar.toString('base64', 0, 3 - this.lastNeed); - return r; -} - -// Pass bytes on through for single-byte encodings (e.g. ascii, latin1, hex) -function simpleWrite(buf) { - return buf.toString(this.encoding); -} - -function simpleEnd(buf) { - return buf && buf.length ? this.write(buf) : ''; -} - -/***/ }), -/* 48 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/* WEBPACK VAR INJECTION */(function(process) { - -var Buffer = __webpack_require__(1).Buffer; -var Transform = __webpack_require__(15).Transform; -var binding = __webpack_require__(150); -var util = __webpack_require__(49); -var assert = __webpack_require__(88).ok; -var kMaxLength = __webpack_require__(1).kMaxLength; -var kRangeErrorMessage = 'Cannot create final Buffer. It would be larger ' + 'than 0x' + kMaxLength.toString(16) + ' bytes'; - -// zlib doesn't provide these, so kludge them in following the same -// const naming scheme zlib uses. -binding.Z_MIN_WINDOWBITS = 8; -binding.Z_MAX_WINDOWBITS = 15; -binding.Z_DEFAULT_WINDOWBITS = 15; - -// fewer than 64 bytes per chunk is stupid. -// technically it could work with as few as 8, but even 64 bytes -// is absurdly low. Usually a MB or more is best. -binding.Z_MIN_CHUNK = 64; -binding.Z_MAX_CHUNK = Infinity; -binding.Z_DEFAULT_CHUNK = 16 * 1024; - -binding.Z_MIN_MEMLEVEL = 1; -binding.Z_MAX_MEMLEVEL = 9; -binding.Z_DEFAULT_MEMLEVEL = 8; - -binding.Z_MIN_LEVEL = -1; -binding.Z_MAX_LEVEL = 9; -binding.Z_DEFAULT_LEVEL = binding.Z_DEFAULT_COMPRESSION; - -// expose all the zlib constants -var bkeys = Object.keys(binding); -for (var bk = 0; bk < bkeys.length; bk++) { - var bkey = bkeys[bk]; - if (bkey.match(/^Z/)) { - Object.defineProperty(exports, bkey, { - enumerable: true, value: binding[bkey], writable: false - }); - } -} - -// translation table for return codes. -var codes = { - Z_OK: binding.Z_OK, - Z_STREAM_END: binding.Z_STREAM_END, - Z_NEED_DICT: binding.Z_NEED_DICT, - Z_ERRNO: binding.Z_ERRNO, - Z_STREAM_ERROR: binding.Z_STREAM_ERROR, - Z_DATA_ERROR: binding.Z_DATA_ERROR, - Z_MEM_ERROR: binding.Z_MEM_ERROR, - Z_BUF_ERROR: binding.Z_BUF_ERROR, - Z_VERSION_ERROR: binding.Z_VERSION_ERROR -}; - -var ckeys = Object.keys(codes); -for (var ck = 0; ck < ckeys.length; ck++) { - var ckey = ckeys[ck]; - codes[codes[ckey]] = ckey; -} - -Object.defineProperty(exports, 'codes', { - enumerable: true, value: Object.freeze(codes), writable: false -}); - -exports.Deflate = Deflate; -exports.Inflate = Inflate; -exports.Gzip = Gzip; -exports.Gunzip = Gunzip; -exports.DeflateRaw = DeflateRaw; -exports.InflateRaw = InflateRaw; -exports.Unzip = Unzip; - -exports.createDeflate = function (o) { - return new Deflate(o); -}; - -exports.createInflate = function (o) { - return new Inflate(o); -}; - -exports.createDeflateRaw = function (o) { - return new DeflateRaw(o); -}; - -exports.createInflateRaw = function (o) { - return new InflateRaw(o); -}; - -exports.createGzip = function (o) { - return new Gzip(o); -}; - -exports.createGunzip = function (o) { - return new Gunzip(o); -}; - -exports.createUnzip = function (o) { - return new Unzip(o); -}; - -// Convenience methods. -// compress/decompress a string or buffer in one step. -exports.deflate = function (buffer, opts, callback) { - if (typeof opts === 'function') { - callback = opts; - opts = {}; - } - return zlibBuffer(new Deflate(opts), buffer, callback); -}; - -exports.deflateSync = function (buffer, opts) { - return zlibBufferSync(new Deflate(opts), buffer); -}; - -exports.gzip = function (buffer, opts, callback) { - if (typeof opts === 'function') { - callback = opts; - opts = {}; - } - return zlibBuffer(new Gzip(opts), buffer, callback); -}; - -exports.gzipSync = function (buffer, opts) { - return zlibBufferSync(new Gzip(opts), buffer); -}; - -exports.deflateRaw = function (buffer, opts, callback) { - if (typeof opts === 'function') { - callback = opts; - opts = {}; - } - return zlibBuffer(new DeflateRaw(opts), buffer, callback); -}; - -exports.deflateRawSync = function (buffer, opts) { - return zlibBufferSync(new DeflateRaw(opts), buffer); -}; - -exports.unzip = function (buffer, opts, callback) { - if (typeof opts === 'function') { - callback = opts; - opts = {}; - } - return zlibBuffer(new Unzip(opts), buffer, callback); -}; - -exports.unzipSync = function (buffer, opts) { - return zlibBufferSync(new Unzip(opts), buffer); -}; - -exports.inflate = function (buffer, opts, callback) { - if (typeof opts === 'function') { - callback = opts; - opts = {}; - } - return zlibBuffer(new Inflate(opts), buffer, callback); -}; - -exports.inflateSync = function (buffer, opts) { - return zlibBufferSync(new Inflate(opts), buffer); -}; - -exports.gunzip = function (buffer, opts, callback) { - if (typeof opts === 'function') { - callback = opts; - opts = {}; - } - return zlibBuffer(new Gunzip(opts), buffer, callback); -}; - -exports.gunzipSync = function (buffer, opts) { - return zlibBufferSync(new Gunzip(opts), buffer); -}; - -exports.inflateRaw = function (buffer, opts, callback) { - if (typeof opts === 'function') { - callback = opts; - opts = {}; - } - return zlibBuffer(new InflateRaw(opts), buffer, callback); -}; - -exports.inflateRawSync = function (buffer, opts) { - return zlibBufferSync(new InflateRaw(opts), buffer); -}; - -function zlibBuffer(engine, buffer, callback) { - var buffers = []; - var nread = 0; - - engine.on('error', onError); - engine.on('end', onEnd); - - engine.end(buffer); - flow(); - - function flow() { - var chunk; - while (null !== (chunk = engine.read())) { - buffers.push(chunk); - nread += chunk.length; - } - engine.once('readable', flow); - } - - function onError(err) { - engine.removeListener('end', onEnd); - engine.removeListener('readable', flow); - callback(err); - } - - function onEnd() { - var buf; - var err = null; - - if (nread >= kMaxLength) { - err = new RangeError(kRangeErrorMessage); - } else { - buf = Buffer.concat(buffers, nread); - } - - buffers = []; - engine.close(); - callback(err, buf); - } -} - -function zlibBufferSync(engine, buffer) { - if (typeof buffer === 'string') buffer = Buffer.from(buffer); - - if (!Buffer.isBuffer(buffer)) throw new TypeError('Not a string or buffer'); - - var flushFlag = engine._finishFlushFlag; - - return engine._processChunk(buffer, flushFlag); -} - -// generic zlib -// minimal 2-byte header -function Deflate(opts) { - if (!(this instanceof Deflate)) return new Deflate(opts); - Zlib.call(this, opts, binding.DEFLATE); -} - -function Inflate(opts) { - if (!(this instanceof Inflate)) return new Inflate(opts); - Zlib.call(this, opts, binding.INFLATE); -} - -// gzip - bigger header, same deflate compression -function Gzip(opts) { - if (!(this instanceof Gzip)) return new Gzip(opts); - Zlib.call(this, opts, binding.GZIP); -} - -function Gunzip(opts) { - if (!(this instanceof Gunzip)) return new Gunzip(opts); - Zlib.call(this, opts, binding.GUNZIP); -} - -// raw - no header -function DeflateRaw(opts) { - if (!(this instanceof DeflateRaw)) return new DeflateRaw(opts); - Zlib.call(this, opts, binding.DEFLATERAW); -} - -function InflateRaw(opts) { - if (!(this instanceof InflateRaw)) return new InflateRaw(opts); - Zlib.call(this, opts, binding.INFLATERAW); -} - -// auto-detect header. -function Unzip(opts) { - if (!(this instanceof Unzip)) return new Unzip(opts); - Zlib.call(this, opts, binding.UNZIP); -} - -function isValidFlushFlag(flag) { - return flag === binding.Z_NO_FLUSH || flag === binding.Z_PARTIAL_FLUSH || flag === binding.Z_SYNC_FLUSH || flag === binding.Z_FULL_FLUSH || flag === binding.Z_FINISH || flag === binding.Z_BLOCK; -} - -// the Zlib class they all inherit from -// This thing manages the queue of requests, and returns -// true or false if there is anything in the queue when -// you call the .write() method. - -function Zlib(opts, mode) { - var _this = this; - - this._opts = opts = opts || {}; - this._chunkSize = opts.chunkSize || exports.Z_DEFAULT_CHUNK; - - Transform.call(this, opts); - - if (opts.flush && !isValidFlushFlag(opts.flush)) { - throw new Error('Invalid flush flag: ' + opts.flush); - } - if (opts.finishFlush && !isValidFlushFlag(opts.finishFlush)) { - throw new Error('Invalid flush flag: ' + opts.finishFlush); - } - - this._flushFlag = opts.flush || binding.Z_NO_FLUSH; - this._finishFlushFlag = typeof opts.finishFlush !== 'undefined' ? opts.finishFlush : binding.Z_FINISH; - - if (opts.chunkSize) { - if (opts.chunkSize < exports.Z_MIN_CHUNK || opts.chunkSize > exports.Z_MAX_CHUNK) { - throw new Error('Invalid chunk size: ' + opts.chunkSize); - } - } - - if (opts.windowBits) { - if (opts.windowBits < exports.Z_MIN_WINDOWBITS || opts.windowBits > exports.Z_MAX_WINDOWBITS) { - throw new Error('Invalid windowBits: ' + opts.windowBits); - } - } - - if (opts.level) { - if (opts.level < exports.Z_MIN_LEVEL || opts.level > exports.Z_MAX_LEVEL) { - throw new Error('Invalid compression level: ' + opts.level); - } - } - - if (opts.memLevel) { - if (opts.memLevel < exports.Z_MIN_MEMLEVEL || opts.memLevel > exports.Z_MAX_MEMLEVEL) { - throw new Error('Invalid memLevel: ' + opts.memLevel); - } - } - - if (opts.strategy) { - if (opts.strategy != exports.Z_FILTERED && opts.strategy != exports.Z_HUFFMAN_ONLY && opts.strategy != exports.Z_RLE && opts.strategy != exports.Z_FIXED && opts.strategy != exports.Z_DEFAULT_STRATEGY) { - throw new Error('Invalid strategy: ' + opts.strategy); - } - } - - if (opts.dictionary) { - if (!Buffer.isBuffer(opts.dictionary)) { - throw new Error('Invalid dictionary: it should be a Buffer instance'); - } - } - - this._handle = new binding.Zlib(mode); - - var self = this; - this._hadError = false; - this._handle.onerror = function (message, errno) { - // there is no way to cleanly recover. - // continuing only obscures problems. - _close(self); - self._hadError = true; - - var error = new Error(message); - error.errno = errno; - error.code = exports.codes[errno]; - self.emit('error', error); - }; - - var level = exports.Z_DEFAULT_COMPRESSION; - if (typeof opts.level === 'number') level = opts.level; - - var strategy = exports.Z_DEFAULT_STRATEGY; - if (typeof opts.strategy === 'number') strategy = opts.strategy; - - this._handle.init(opts.windowBits || exports.Z_DEFAULT_WINDOWBITS, level, opts.memLevel || exports.Z_DEFAULT_MEMLEVEL, strategy, opts.dictionary); - - this._buffer = Buffer.allocUnsafe(this._chunkSize); - this._offset = 0; - this._level = level; - this._strategy = strategy; - - this.once('end', this.close); - - Object.defineProperty(this, '_closed', { - get: function () { - return !_this._handle; - }, - configurable: true, - enumerable: true - }); -} - -util.inherits(Zlib, Transform); - -Zlib.prototype.params = function (level, strategy, callback) { - if (level < exports.Z_MIN_LEVEL || level > exports.Z_MAX_LEVEL) { - throw new RangeError('Invalid compression level: ' + level); - } - if (strategy != exports.Z_FILTERED && strategy != exports.Z_HUFFMAN_ONLY && strategy != exports.Z_RLE && strategy != exports.Z_FIXED && strategy != exports.Z_DEFAULT_STRATEGY) { - throw new TypeError('Invalid strategy: ' + strategy); - } - - if (this._level !== level || this._strategy !== strategy) { - var self = this; - this.flush(binding.Z_SYNC_FLUSH, function () { - assert(self._handle, 'zlib binding closed'); - self._handle.params(level, strategy); - if (!self._hadError) { - self._level = level; - self._strategy = strategy; - if (callback) callback(); - } - }); - } else { - process.nextTick(callback); - } -}; - -Zlib.prototype.reset = function () { - assert(this._handle, 'zlib binding closed'); - return this._handle.reset(); -}; - -// This is the _flush function called by the transform class, -// internally, when the last chunk has been written. -Zlib.prototype._flush = function (callback) { - this._transform(Buffer.alloc(0), '', callback); -}; - -Zlib.prototype.flush = function (kind, callback) { - var _this2 = this; - - var ws = this._writableState; - - if (typeof kind === 'function' || kind === undefined && !callback) { - callback = kind; - kind = binding.Z_FULL_FLUSH; - } - - if (ws.ended) { - if (callback) process.nextTick(callback); - } else if (ws.ending) { - if (callback) this.once('end', callback); - } else if (ws.needDrain) { - if (callback) { - this.once('drain', function () { - return _this2.flush(kind, callback); - }); - } - } else { - this._flushFlag = kind; - this.write(Buffer.alloc(0), '', callback); - } -}; - -Zlib.prototype.close = function (callback) { - _close(this, callback); - process.nextTick(emitCloseNT, this); -}; - -function _close(engine, callback) { - if (callback) process.nextTick(callback); - - // Caller may invoke .close after a zlib error (which will null _handle). - if (!engine._handle) return; - - engine._handle.close(); - engine._handle = null; -} - -function emitCloseNT(self) { - self.emit('close'); -} - -Zlib.prototype._transform = function (chunk, encoding, cb) { - var flushFlag; - var ws = this._writableState; - var ending = ws.ending || ws.ended; - var last = ending && (!chunk || ws.length === chunk.length); - - if (chunk !== null && !Buffer.isBuffer(chunk)) return cb(new Error('invalid input')); - - if (!this._handle) return cb(new Error('zlib binding closed')); - - // If it's the last chunk, or a final flush, we use the Z_FINISH flush flag - // (or whatever flag was provided using opts.finishFlush). - // If it's explicitly flushing at some other time, then we use - // Z_FULL_FLUSH. Otherwise, use Z_NO_FLUSH for maximum compression - // goodness. - if (last) flushFlag = this._finishFlushFlag;else { - flushFlag = this._flushFlag; - // once we've flushed the last of the queue, stop flushing and - // go back to the normal behavior. - if (chunk.length >= ws.length) { - this._flushFlag = this._opts.flush || binding.Z_NO_FLUSH; - } - } - - this._processChunk(chunk, flushFlag, cb); -}; - -Zlib.prototype._processChunk = function (chunk, flushFlag, cb) { - var availInBefore = chunk && chunk.length; - var availOutBefore = this._chunkSize - this._offset; - var inOff = 0; - - var self = this; - - var async = typeof cb === 'function'; - - if (!async) { - var buffers = []; - var nread = 0; - - var error; - this.on('error', function (er) { - error = er; - }); - - assert(this._handle, 'zlib binding closed'); - do { - var res = this._handle.writeSync(flushFlag, chunk, // in - inOff, // in_off - availInBefore, // in_len - this._buffer, // out - this._offset, //out_off - availOutBefore); // out_len - } while (!this._hadError && callback(res[0], res[1])); - - if (this._hadError) { - throw error; - } - - if (nread >= kMaxLength) { - _close(this); - throw new RangeError(kRangeErrorMessage); - } - - var buf = Buffer.concat(buffers, nread); - _close(this); - - return buf; - } - - assert(this._handle, 'zlib binding closed'); - var req = this._handle.write(flushFlag, chunk, // in - inOff, // in_off - availInBefore, // in_len - this._buffer, // out - this._offset, //out_off - availOutBefore); // out_len - - req.buffer = chunk; - req.callback = callback; - - function callback(availInAfter, availOutAfter) { - // When the callback is used in an async write, the callback's - // context is the `req` object that was created. The req object - // is === this._handle, and that's why it's important to null - // out the values after they are done being used. `this._handle` - // can stay in memory longer than the callback and buffer are needed. - if (this) { - this.buffer = null; - this.callback = null; - } - - if (self._hadError) return; - - var have = availOutBefore - availOutAfter; - assert(have >= 0, 'have should not go down'); - - if (have > 0) { - var out = self._buffer.slice(self._offset, self._offset + have); - self._offset += have; - // serve some output to the consumer. - if (async) { - self.push(out); - } else { - buffers.push(out); - nread += out.length; - } - } - - // exhausted the output buffer, or used all the input create a new one. - if (availOutAfter === 0 || self._offset >= self._chunkSize) { - availOutBefore = self._chunkSize; - self._offset = 0; - self._buffer = Buffer.allocUnsafe(self._chunkSize); - } - - if (availOutAfter === 0) { - // Not actually done. Need to reprocess. - // Also, update the availInBefore to the availInAfter value, - // so that if we have to hit it a third (fourth, etc.) time, - // it'll have the correct byte counts. - inOff += availInBefore - availInAfter; - availInBefore = availInAfter; - - if (!async) return true; - - var newReq = self._handle.write(flushFlag, chunk, inOff, availInBefore, self._buffer, self._offset, self._chunkSize); - newReq.callback = callback; // this same function - newReq.buffer = chunk; - return; - } - - if (!async) return false; - - // finished with the chunk. - cb(); - } -}; - -util.inherits(Deflate, Zlib); -util.inherits(Inflate, Zlib); -util.inherits(Gzip, Zlib); -util.inherits(Gunzip, Zlib); -util.inherits(DeflateRaw, Zlib); -util.inherits(InflateRaw, Zlib); -util.inherits(Unzip, Zlib); -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(11))) - -/***/ }), -/* 49 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(global, process) {// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -var formatRegExp = /%[sdj%]/g; -exports.format = function(f) { - if (!isString(f)) { - var objects = []; - for (var i = 0; i < arguments.length; i++) { - objects.push(inspect(arguments[i])); - } - return objects.join(' '); - } - - var i = 1; - var args = arguments; - var len = args.length; - var str = String(f).replace(formatRegExp, function(x) { - if (x === '%%') return '%'; - if (i >= len) return x; - switch (x) { - case '%s': return String(args[i++]); - case '%d': return Number(args[i++]); - case '%j': - try { - return JSON.stringify(args[i++]); - } catch (_) { - return '[Circular]'; - } - default: - return x; - } - }); - for (var x = args[i]; i < len; x = args[++i]) { - if (isNull(x) || !isObject(x)) { - str += ' ' + x; - } else { - str += ' ' + inspect(x); - } - } - return str; -}; - - -// Mark that a method should not be used. -// Returns a modified function which warns once by default. -// If --no-deprecation is set, then it is a no-op. -exports.deprecate = function(fn, msg) { - // Allow for deprecating things in the process of starting up. - if (isUndefined(global.process)) { - return function() { - return exports.deprecate(fn, msg).apply(this, arguments); - }; - } - - if (process.noDeprecation === true) { - return fn; - } - - var warned = false; - function deprecated() { - if (!warned) { - if (process.throwDeprecation) { - throw new Error(msg); - } else if (process.traceDeprecation) { - console.trace(msg); - } else { - console.error(msg); - } - warned = true; - } - return fn.apply(this, arguments); - } - - return deprecated; -}; - - -var debugs = {}; -var debugEnviron; -exports.debuglog = function(set) { - if (isUndefined(debugEnviron)) - debugEnviron = process.env.NODE_DEBUG || ''; - set = set.toUpperCase(); - if (!debugs[set]) { - if (new RegExp('\\b' + set + '\\b', 'i').test(debugEnviron)) { - var pid = process.pid; - debugs[set] = function() { - var msg = exports.format.apply(exports, arguments); - console.error('%s %d: %s', set, pid, msg); - }; - } else { - debugs[set] = function() {}; - } - } - return debugs[set]; -}; - - -/** - * Echos the value of a value. Trys to print the value out - * in the best way possible given the different types. - * - * @param {Object} obj The object to print out. - * @param {Object} opts Optional options object that alters the output. - */ -/* legacy: obj, showHidden, depth, colors*/ -function inspect(obj, opts) { - // default options - var ctx = { - seen: [], - stylize: stylizeNoColor - }; - // legacy... - if (arguments.length >= 3) ctx.depth = arguments[2]; - if (arguments.length >= 4) ctx.colors = arguments[3]; - if (isBoolean(opts)) { - // legacy... - ctx.showHidden = opts; - } else if (opts) { - // got an "options" object - exports._extend(ctx, opts); - } - // set default options - if (isUndefined(ctx.showHidden)) ctx.showHidden = false; - if (isUndefined(ctx.depth)) ctx.depth = 2; - if (isUndefined(ctx.colors)) ctx.colors = false; - if (isUndefined(ctx.customInspect)) ctx.customInspect = true; - if (ctx.colors) ctx.stylize = stylizeWithColor; - return formatValue(ctx, obj, ctx.depth); -} -exports.inspect = inspect; - - -// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics -inspect.colors = { - 'bold' : [1, 22], - 'italic' : [3, 23], - 'underline' : [4, 24], - 'inverse' : [7, 27], - 'white' : [37, 39], - 'grey' : [90, 39], - 'black' : [30, 39], - 'blue' : [34, 39], - 'cyan' : [36, 39], - 'green' : [32, 39], - 'magenta' : [35, 39], - 'red' : [31, 39], - 'yellow' : [33, 39] -}; - -// Don't use 'blue' not visible on cmd.exe -inspect.styles = { - 'special': 'cyan', - 'number': 'yellow', - 'boolean': 'yellow', - 'undefined': 'grey', - 'null': 'bold', - 'string': 'green', - 'date': 'magenta', - // "name": intentionally not styling - 'regexp': 'red' -}; - - -function stylizeWithColor(str, styleType) { - var style = inspect.styles[styleType]; - - if (style) { - return '\u001b[' + inspect.colors[style][0] + 'm' + str + - '\u001b[' + inspect.colors[style][1] + 'm'; - } else { - return str; - } -} - - -function stylizeNoColor(str, styleType) { - return str; -} - - -function arrayToHash(array) { - var hash = {}; - - array.forEach(function(val, idx) { - hash[val] = true; - }); - - return hash; -} - - -function formatValue(ctx, value, recurseTimes) { - // Provide a hook for user-specified inspect functions. - // Check that value is an object with an inspect function on it - if (ctx.customInspect && - value && - isFunction(value.inspect) && - // Filter out the util module, it's inspect function is special - value.inspect !== exports.inspect && - // Also filter out any prototype objects using the circular check. - !(value.constructor && value.constructor.prototype === value)) { - var ret = value.inspect(recurseTimes, ctx); - if (!isString(ret)) { - ret = formatValue(ctx, ret, recurseTimes); - } - return ret; - } - - // Primitive types cannot have properties - var primitive = formatPrimitive(ctx, value); - if (primitive) { - return primitive; - } - - // Look up the keys of the object. - var keys = Object.keys(value); - var visibleKeys = arrayToHash(keys); - - if (ctx.showHidden) { - keys = Object.getOwnPropertyNames(value); - } - - // IE doesn't make error fields non-enumerable - // http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx - if (isError(value) - && (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) { - return formatError(value); - } - - // Some type of object without properties can be shortcutted. - if (keys.length === 0) { - if (isFunction(value)) { - var name = value.name ? ': ' + value.name : ''; - return ctx.stylize('[Function' + name + ']', 'special'); - } - if (isRegExp(value)) { - return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); - } - if (isDate(value)) { - return ctx.stylize(Date.prototype.toString.call(value), 'date'); - } - if (isError(value)) { - return formatError(value); - } - } - - var base = '', array = false, braces = ['{', '}']; - - // Make Array say that they are Array - if (isArray(value)) { - array = true; - braces = ['[', ']']; - } - - // Make functions say that they are functions - if (isFunction(value)) { - var n = value.name ? ': ' + value.name : ''; - base = ' [Function' + n + ']'; - } - - // Make RegExps say that they are RegExps - if (isRegExp(value)) { - base = ' ' + RegExp.prototype.toString.call(value); - } - - // Make dates with properties first say the date - if (isDate(value)) { - base = ' ' + Date.prototype.toUTCString.call(value); - } - - // Make error with message first say the error - if (isError(value)) { - base = ' ' + formatError(value); - } - - if (keys.length === 0 && (!array || value.length == 0)) { - return braces[0] + base + braces[1]; - } - - if (recurseTimes < 0) { - if (isRegExp(value)) { - return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); - } else { - return ctx.stylize('[Object]', 'special'); - } - } - - ctx.seen.push(value); - - var output; - if (array) { - output = formatArray(ctx, value, recurseTimes, visibleKeys, keys); - } else { - output = keys.map(function(key) { - return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array); - }); - } - - ctx.seen.pop(); - - return reduceToSingleString(output, base, braces); -} - - -function formatPrimitive(ctx, value) { - if (isUndefined(value)) - return ctx.stylize('undefined', 'undefined'); - if (isString(value)) { - var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '') - .replace(/'/g, "\\'") - .replace(/\\"/g, '"') + '\''; - return ctx.stylize(simple, 'string'); - } - if (isNumber(value)) - return ctx.stylize('' + value, 'number'); - if (isBoolean(value)) - return ctx.stylize('' + value, 'boolean'); - // For some reason typeof null is "object", so special case here. - if (isNull(value)) - return ctx.stylize('null', 'null'); -} - - -function formatError(value) { - return '[' + Error.prototype.toString.call(value) + ']'; -} - - -function formatArray(ctx, value, recurseTimes, visibleKeys, keys) { - var output = []; - for (var i = 0, l = value.length; i < l; ++i) { - if (hasOwnProperty(value, String(i))) { - output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, - String(i), true)); - } else { - output.push(''); - } - } - keys.forEach(function(key) { - if (!key.match(/^\d+$/)) { - output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, - key, true)); - } - }); - return output; -} - - -function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) { - var name, str, desc; - desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] }; - if (desc.get) { - if (desc.set) { - str = ctx.stylize('[Getter/Setter]', 'special'); - } else { - str = ctx.stylize('[Getter]', 'special'); - } - } else { - if (desc.set) { - str = ctx.stylize('[Setter]', 'special'); - } - } - if (!hasOwnProperty(visibleKeys, key)) { - name = '[' + key + ']'; - } - if (!str) { - if (ctx.seen.indexOf(desc.value) < 0) { - if (isNull(recurseTimes)) { - str = formatValue(ctx, desc.value, null); - } else { - str = formatValue(ctx, desc.value, recurseTimes - 1); - } - if (str.indexOf('\n') > -1) { - if (array) { - str = str.split('\n').map(function(line) { - return ' ' + line; - }).join('\n').substr(2); - } else { - str = '\n' + str.split('\n').map(function(line) { - return ' ' + line; - }).join('\n'); - } - } - } else { - str = ctx.stylize('[Circular]', 'special'); - } - } - if (isUndefined(name)) { - if (array && key.match(/^\d+$/)) { - return str; - } - name = JSON.stringify('' + key); - if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) { - name = name.substr(1, name.length - 2); - name = ctx.stylize(name, 'name'); - } else { - name = name.replace(/'/g, "\\'") - .replace(/\\"/g, '"') - .replace(/(^"|"$)/g, "'"); - name = ctx.stylize(name, 'string'); - } - } - - return name + ': ' + str; -} - - -function reduceToSingleString(output, base, braces) { - var numLinesEst = 0; - var length = output.reduce(function(prev, cur) { - numLinesEst++; - if (cur.indexOf('\n') >= 0) numLinesEst++; - return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1; - }, 0); - - if (length > 60) { - return braces[0] + - (base === '' ? '' : base + '\n ') + - ' ' + - output.join(',\n ') + - ' ' + - braces[1]; - } - - return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1]; -} - - -// NOTE: These type checking functions intentionally don't use `instanceof` -// because it is fragile and can be easily faked with `Object.create()`. -function isArray(ar) { - return Array.isArray(ar); -} -exports.isArray = isArray; - -function isBoolean(arg) { - return typeof arg === 'boolean'; -} -exports.isBoolean = isBoolean; - -function isNull(arg) { - return arg === null; -} -exports.isNull = isNull; - -function isNullOrUndefined(arg) { - return arg == null; -} -exports.isNullOrUndefined = isNullOrUndefined; - -function isNumber(arg) { - return typeof arg === 'number'; -} -exports.isNumber = isNumber; - -function isString(arg) { - return typeof arg === 'string'; -} -exports.isString = isString; - -function isSymbol(arg) { - return typeof arg === 'symbol'; -} -exports.isSymbol = isSymbol; - -function isUndefined(arg) { - return arg === void 0; -} -exports.isUndefined = isUndefined; - -function isRegExp(re) { - return isObject(re) && objectToString(re) === '[object RegExp]'; -} -exports.isRegExp = isRegExp; - -function isObject(arg) { - return typeof arg === 'object' && arg !== null; -} -exports.isObject = isObject; - -function isDate(d) { - return isObject(d) && objectToString(d) === '[object Date]'; -} -exports.isDate = isDate; - -function isError(e) { - return isObject(e) && - (objectToString(e) === '[object Error]' || e instanceof Error); -} -exports.isError = isError; - -function isFunction(arg) { - return typeof arg === 'function'; -} -exports.isFunction = isFunction; - -function isPrimitive(arg) { - return arg === null || - typeof arg === 'boolean' || - typeof arg === 'number' || - typeof arg === 'string' || - typeof arg === 'symbol' || // ES6 symbol - typeof arg === 'undefined'; -} -exports.isPrimitive = isPrimitive; - -exports.isBuffer = __webpack_require__(151); - -function objectToString(o) { - return Object.prototype.toString.call(o); -} - - -function pad(n) { - return n < 10 ? '0' + n.toString(10) : n.toString(10); -} - - -var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', - 'Oct', 'Nov', 'Dec']; - -// 26 Feb 16:19:34 -function timestamp() { - var d = new Date(); - var time = [pad(d.getHours()), - pad(d.getMinutes()), - pad(d.getSeconds())].join(':'); - return [d.getDate(), months[d.getMonth()], time].join(' '); -} - - -// log is just a thin wrapper to console.log that prepends a timestamp -exports.log = function() { - console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments)); -}; - - -/** - * Inherit the prototype methods from one constructor into another. - * - * The Function.prototype.inherits from lang.js rewritten as a standalone - * function (not on Function.prototype). NOTE: If this file is to be loaded - * during bootstrapping this function needs to be rewritten using some native - * functions as prototype setup using normal JavaScript does not work as - * expected during bootstrapping (see mirror.js in r114903). - * - * @param {function} ctor Constructor function which needs to inherit the - * prototype. - * @param {function} superCtor Constructor function to inherit prototype from. - */ -exports.inherits = __webpack_require__(152); - -exports._extend = function(origin, add) { - // Don't do anything if add isn't an object - if (!add || !isObject(add)) return origin; - - var keys = Object.keys(add); - var i = keys.length; - while (i--) { - origin[keys[i]] = add[keys[i]]; - } - return origin; -}; - -function hasOwnProperty(obj, prop) { - return Object.prototype.hasOwnProperty.call(obj, prop); -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(7), __webpack_require__(11))) - -/***/ }), -/* 50 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(Buffer) {// Generated by CoffeeScript 1.12.6 -(function() { - var EmbeddedFont, PDFFont, StandardFont, fontkit; - - fontkit = __webpack_require__(167); - - PDFFont = (function() { - PDFFont.open = function(document, src, family, id) { - var font; - if (typeof src === 'string') { - if (StandardFont.isStandardFont(src)) { - return new StandardFont(document, src, id); - } - font = fontkit.openSync(src, family); - } else if (Buffer.isBuffer(src)) { - font = fontkit.create(src, family); - } else if (src instanceof Uint8Array) { - font = fontkit.create(new Buffer(src), family); - } else if (src instanceof ArrayBuffer) { - font = fontkit.create(new Buffer(new Uint8Array(src)), family); - } - if (font == null) { - throw new Error('Not a supported font format or standard PDF font.'); - } - return new EmbeddedFont(document, font, id); - }; - - function PDFFont() { - throw new Error('Cannot construct a PDFFont directly.'); - } - - PDFFont.prototype.encode = function(text) { - throw new Error('Must be implemented by subclasses'); - }; - - PDFFont.prototype.widthOfString = function(text) { - throw new Error('Must be implemented by subclasses'); - }; - - PDFFont.prototype.ref = function() { - return this.dictionary != null ? this.dictionary : this.dictionary = this.document.ref(); - }; - - PDFFont.prototype.finalize = function() { - if (this.embedded || (this.dictionary == null)) { - return; - } - this.embed(); - return this.embedded = true; - }; - - PDFFont.prototype.embed = function() { - throw new Error('Must be implemented by subclasses'); - }; - - PDFFont.prototype.lineHeight = function(size, includeGap) { - var gap; - if (includeGap == null) { - includeGap = false; - } - gap = includeGap ? this.lineGap : 0; - return (this.ascender + gap - this.descender) / 1000 * size; - }; - - return PDFFont; - - })(); - - module.exports = PDFFont; - - StandardFont = __webpack_require__(292); - - EmbeddedFont = __webpack_require__(294); - -}).call(this); - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1).Buffer)) - -/***/ }), -/* 51 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(Buffer) {// Generated by CoffeeScript 1.7.1 -(function() { - var DecodeStream, iconv; - - try { - iconv = __webpack_require__(52); - } catch (_error) {} - - DecodeStream = (function() { - var key; - - function DecodeStream(buffer) { - this.buffer = buffer; - this.pos = 0; - this.length = this.buffer.length; - } - - DecodeStream.TYPES = { - UInt8: 1, - UInt16: 2, - UInt24: 3, - UInt32: 4, - Int8: 1, - Int16: 2, - Int24: 3, - Int32: 4, - Float: 4, - Double: 8 - }; - - for (key in Buffer.prototype) { - if (key.slice(0, 4) === 'read') { - (function(key) { - var bytes; - bytes = DecodeStream.TYPES[key.replace(/read|[BL]E/g, '')]; - return DecodeStream.prototype[key] = function() { - var ret; - ret = this.buffer[key](this.pos); - this.pos += bytes; - return ret; - }; - })(key); - } - } - - DecodeStream.prototype.readString = function(length, encoding) { - var buf, byte, i, _i, _ref; - if (encoding == null) { - encoding = 'ascii'; - } - switch (encoding) { - case 'utf16le': - case 'ucs2': - case 'utf8': - case 'ascii': - return this.buffer.toString(encoding, this.pos, this.pos += length); - case 'utf16be': - buf = new Buffer(this.readBuffer(length)); - for (i = _i = 0, _ref = buf.length - 1; _i < _ref; i = _i += 2) { - byte = buf[i]; - buf[i] = buf[i + 1]; - buf[i + 1] = byte; - } - return buf.toString('utf16le'); - default: - buf = this.readBuffer(length); - if (iconv) { - try { - return iconv.decode(buf, encoding); - } catch (_error) {} - } - return buf; - } - }; - - DecodeStream.prototype.readBuffer = function(length) { - return this.buffer.slice(this.pos, this.pos += length); - }; - - DecodeStream.prototype.readUInt24BE = function() { - return (this.readUInt16BE() << 8) + this.readUInt8(); - }; - - DecodeStream.prototype.readUInt24LE = function() { - return this.readUInt16LE() + (this.readUInt8() << 16); - }; - - DecodeStream.prototype.readInt24BE = function() { - return (this.readInt16BE() << 8) + this.readUInt8(); - }; - - DecodeStream.prototype.readInt24LE = function() { - return this.readUInt16LE() + (this.readInt8() << 16); - }; - - return DecodeStream; - - })(); - - module.exports = DecodeStream; - -}).call(this); - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1).Buffer)) - -/***/ }), -/* 52 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/* WEBPACK VAR INJECTION */(function(process) { - -// Some environments don't have global Buffer (e.g. React Native). -// Solution would be installing npm modules "buffer" and "stream" explicitly. -var Buffer = __webpack_require__(1).Buffer; - -var bomHandling = __webpack_require__(170), - iconv = module.exports; - -// All codecs and aliases are kept here, keyed by encoding name/alias. -// They are lazy loaded in `iconv.getCodec` from `encodings/index.js`. -iconv.encodings = null; - -// Characters emitted in case of error. -iconv.defaultCharUnicode = '�'; -iconv.defaultCharSingleByte = '?'; - -// Public API. -iconv.encode = function encode(str, encoding, options) { - str = "" + (str || ""); // Ensure string. - - var encoder = iconv.getEncoder(encoding, options); - - var res = encoder.write(str); - var trail = encoder.end(); - - return (trail && trail.length > 0) ? Buffer.concat([res, trail]) : res; -} - -iconv.decode = function decode(buf, encoding, options) { - if (typeof buf === 'string') { - if (!iconv.skipDecodeWarning) { - console.error('Iconv-lite warning: decode()-ing strings is deprecated. Refer to https://github.com/ashtuchkin/iconv-lite/wiki/Use-Buffers-when-decoding'); - iconv.skipDecodeWarning = true; - } - - buf = new Buffer("" + (buf || ""), "binary"); // Ensure buffer. - } - - var decoder = iconv.getDecoder(encoding, options); - - var res = decoder.write(buf); - var trail = decoder.end(); - - return trail ? (res + trail) : res; -} - -iconv.encodingExists = function encodingExists(enc) { - try { - iconv.getCodec(enc); - return true; - } catch (e) { - return false; - } -} - -// Legacy aliases to convert functions -iconv.toEncoding = iconv.encode; -iconv.fromEncoding = iconv.decode; - -// Search for a codec in iconv.encodings. Cache codec data in iconv._codecDataCache. -iconv._codecDataCache = {}; -iconv.getCodec = function getCodec(encoding) { - if (!iconv.encodings) - iconv.encodings = __webpack_require__(171); // Lazy load all encoding definitions. - - // Canonicalize encoding name: strip all non-alphanumeric chars and appended year. - var enc = (''+encoding).toLowerCase().replace(/[^0-9a-z]|:\d{4}$/g, ""); - - // Traverse iconv.encodings to find actual codec. - var codecOptions = {}; - while (true) { - var codec = iconv._codecDataCache[enc]; - if (codec) - return codec; - - var codecDef = iconv.encodings[enc]; - - switch (typeof codecDef) { - case "string": // Direct alias to other encoding. - enc = codecDef; - break; - - case "object": // Alias with options. Can be layered. - for (var key in codecDef) - codecOptions[key] = codecDef[key]; - - if (!codecOptions.encodingName) - codecOptions.encodingName = enc; - - enc = codecDef.type; - break; - - case "function": // Codec itself. - if (!codecOptions.encodingName) - codecOptions.encodingName = enc; - - // The codec function must load all tables and return object with .encoder and .decoder methods. - // It'll be called only once (for each different options object). - codec = new codecDef(codecOptions, iconv); - - iconv._codecDataCache[codecOptions.encodingName] = codec; // Save it to be reused later. - return codec; - - default: - throw new Error("Encoding not recognized: '" + encoding + "' (searched as: '"+enc+"')"); - } - } -} - -iconv.getEncoder = function getEncoder(encoding, options) { - var codec = iconv.getCodec(encoding), - encoder = new codec.encoder(options, codec); - - if (codec.bomAware && options && options.addBOM) - encoder = new bomHandling.PrependBOM(encoder, options); - - return encoder; -} - -iconv.getDecoder = function getDecoder(encoding, options) { - var codec = iconv.getCodec(encoding), - decoder = new codec.decoder(options, codec); - - if (codec.bomAware && !(options && options.stripBOM === false)) - decoder = new bomHandling.StripBOM(decoder, options); - - return decoder; -} - - -// Load extensions in Node. All of them are omitted in Browserify build via 'browser' field in package.json. -var nodeVer = typeof process !== 'undefined' && process.versions && process.versions.node; -if (nodeVer) { - - // Load streaming support in Node v0.10+ - var nodeVerArr = nodeVer.split(".").map(Number); - if (nodeVerArr[0] > 0 || nodeVerArr[1] >= 10) { - __webpack_require__(185)(iconv); - } - - // Load Node primitive extensions. - __webpack_require__(186)(iconv); -} - -if (false) { - console.error("iconv-lite warning: javascript files use encoding different from utf-8. See https://github.com/ashtuchkin/iconv-lite/wiki/Javascript-source-file-encodings for more info."); -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(11))) - -/***/ }), -/* 53 */ -/***/ (function(module, exports) { - -module.exports = [["0","\u0000",127,"€"],["8140","丂丄丅丆丏丒丗丟丠両丣並丩丮丯丱丳丵丷丼乀乁乂乄乆乊乑乕乗乚乛乢乣乤乥乧乨乪",5,"乲乴",9,"乿",6,"亇亊"],["8180","亐亖亗亙亜亝亞亣亪亯亰亱亴亶亷亸亹亼亽亾仈仌仏仐仒仚仛仜仠仢仦仧仩仭仮仯仱仴仸仹仺仼仾伀伂",6,"伋伌伒",4,"伜伝伡伣伨伩伬伭伮伱伳伵伷伹伻伾",4,"佄佅佇",5,"佒佔佖佡佢佦佨佪佫佭佮佱佲併佷佸佹佺佽侀侁侂侅來侇侊侌侎侐侒侓侕侖侘侙侚侜侞侟価侢"],["8240","侤侫侭侰",4,"侶",8,"俀俁係俆俇俈俉俋俌俍俒",4,"俙俛俠俢俤俥俧俫俬俰俲俴俵俶俷俹俻俼俽俿",11],["8280","個倎倐們倓倕倖倗倛倝倞倠倢倣値倧倫倯",10,"倻倽倿偀偁偂偄偅偆偉偊偋偍偐",4,"偖偗偘偙偛偝",7,"偦",5,"偭",8,"偸偹偺偼偽傁傂傃傄傆傇傉傊傋傌傎",20,"傤傦傪傫傭",4,"傳",6,"傼"],["8340","傽",17,"僐",5,"僗僘僙僛",10,"僨僩僪僫僯僰僱僲僴僶",4,"僼",9,"儈"],["8380","儉儊儌",5,"儓",13,"儢",28,"兂兇兊兌兎兏児兒兓兗兘兙兛兝",4,"兣兤兦內兩兪兯兲兺兾兿冃冄円冇冊冋冎冏冐冑冓冔冘冚冝冞冟冡冣冦",4,"冭冮冴冸冹冺冾冿凁凂凃凅凈凊凍凎凐凒",5],["8440","凘凙凚凜凞凟凢凣凥",5,"凬凮凱凲凴凷凾刄刅刉刋刌刏刐刓刔刕刜刞刟刡刢刣別刦刧刪刬刯刱刲刴刵刼刾剄",5,"剋剎剏剒剓剕剗剘"],["8480","剙剚剛剝剟剠剢剣剤剦剨剫剬剭剮剰剱剳",9,"剾劀劃",4,"劉",6,"劑劒劔",6,"劜劤劥劦劧劮劯劰労",9,"勀勁勂勄勅勆勈勊勌勍勎勏勑勓勔動勗務",5,"勠勡勢勣勥",10,"勱",7,"勻勼勽匁匂匃匄匇匉匊匋匌匎"],["8540","匑匒匓匔匘匛匜匞匟匢匤匥匧匨匩匫匬匭匯",9,"匼匽區卂卄卆卋卌卍卐協単卙卛卝卥卨卪卬卭卲卶卹卻卼卽卾厀厁厃厇厈厊厎厏"],["8580","厐",4,"厖厗厙厛厜厞厠厡厤厧厪厫厬厭厯",6,"厷厸厹厺厼厽厾叀參",4,"収叏叐叒叓叕叚叜叝叞叡叢叧叴叺叾叿吀吂吅吇吋吔吘吙吚吜吢吤吥吪吰吳吶吷吺吽吿呁呂呄呅呇呉呌呍呎呏呑呚呝",4,"呣呥呧呩",7,"呴呹呺呾呿咁咃咅咇咈咉咊咍咑咓咗咘咜咞咟咠咡"],["8640","咢咥咮咰咲咵咶咷咹咺咼咾哃哅哊哋哖哘哛哠",4,"哫哬哯哰哱哴",5,"哻哾唀唂唃唄唅唈唊",4,"唒唓唕",5,"唜唝唞唟唡唥唦"],["8680","唨唩唫唭唲唴唵唶唸唹唺唻唽啀啂啅啇啈啋",4,"啑啒啓啔啗",4,"啝啞啟啠啢啣啨啩啫啯",5,"啹啺啽啿喅喆喌喍喎喐喒喓喕喖喗喚喛喞喠",6,"喨",8,"喲喴営喸喺喼喿",4,"嗆嗇嗈嗊嗋嗎嗏嗐嗕嗗",4,"嗞嗠嗢嗧嗩嗭嗮嗰嗱嗴嗶嗸",4,"嗿嘂嘃嘄嘅"],["8740","嘆嘇嘊嘋嘍嘐",7,"嘙嘚嘜嘝嘠嘡嘢嘥嘦嘨嘩嘪嘫嘮嘯嘰嘳嘵嘷嘸嘺嘼嘽嘾噀",11,"噏",4,"噕噖噚噛噝",4],["8780","噣噥噦噧噭噮噯噰噲噳噴噵噷噸噹噺噽",7,"嚇",6,"嚐嚑嚒嚔",14,"嚤",10,"嚰",6,"嚸嚹嚺嚻嚽",12,"囋",8,"囕囖囘囙囜団囥",5,"囬囮囯囲図囶囷囸囻囼圀圁圂圅圇國",6],["8840","園",9,"圝圞圠圡圢圤圥圦圧圫圱圲圴",4,"圼圽圿坁坃坄坅坆坈坉坋坒",4,"坘坙坢坣坥坧坬坮坰坱坲坴坵坸坹坺坽坾坿垀"],["8880","垁垇垈垉垊垍",4,"垔",6,"垜垝垞垟垥垨垪垬垯垰垱垳垵垶垷垹",8,"埄",6,"埌埍埐埑埓埖埗埛埜埞埡埢埣埥",7,"埮埰埱埲埳埵埶執埻埼埾埿堁堃堄堅堈堉堊堌堎堏堐堒堓堔堖堗堘堚堛堜堝堟堢堣堥",4,"堫",4,"報堲堳場堶",7],["8940","堾",5,"塅",6,"塎塏塐塒塓塕塖塗塙",4,"塟",5,"塦",4,"塭",16,"塿墂墄墆墇墈墊墋墌"],["8980","墍",4,"墔",4,"墛墜墝墠",7,"墪",17,"墽墾墿壀壂壃壄壆",10,"壒壓壔壖",13,"壥",5,"壭壯壱売壴壵壷壸壺",7,"夃夅夆夈",4,"夎夐夑夒夓夗夘夛夝夞夠夡夢夣夦夨夬夰夲夳夵夶夻"],["8a40","夽夾夿奀奃奅奆奊奌奍奐奒奓奙奛",4,"奡奣奤奦",12,"奵奷奺奻奼奾奿妀妅妉妋妌妎妏妐妑妔妕妘妚妛妜妝妟妠妡妢妦"],["8a80","妧妬妭妰妱妳",5,"妺妼妽妿",6,"姇姈姉姌姍姎姏姕姖姙姛姞",4,"姤姦姧姩姪姫姭",11,"姺姼姽姾娀娂娊娋娍娎娏娐娒娔娕娖娗娙娚娛娝娞娡娢娤娦娧娨娪",6,"娳娵娷",4,"娽娾娿婁",4,"婇婈婋",9,"婖婗婘婙婛",5],["8b40","婡婣婤婥婦婨婩婫",8,"婸婹婻婼婽婾媀",17,"媓",6,"媜",13,"媫媬"],["8b80","媭",4,"媴媶媷媹",4,"媿嫀嫃",5,"嫊嫋嫍",4,"嫓嫕嫗嫙嫚嫛嫝嫞嫟嫢嫤嫥嫧嫨嫪嫬",4,"嫲",22,"嬊",11,"嬘",25,"嬳嬵嬶嬸",7,"孁",6],["8c40","孈",7,"孒孖孞孠孡孧孨孫孭孮孯孲孴孶孷學孹孻孼孾孿宂宆宊宍宎宐宑宒宔宖実宧宨宩宬宭宮宯宱宲宷宺宻宼寀寁寃寈寉寊寋寍寎寏"],["8c80","寑寔",8,"寠寢寣實寧審",4,"寯寱",6,"寽対尀専尃尅將專尋尌對導尐尒尓尗尙尛尞尟尠尡尣尦尨尩尪尫尭尮尯尰尲尳尵尶尷屃屄屆屇屌屍屒屓屔屖屗屘屚屛屜屝屟屢層屧",6,"屰屲",6,"屻屼屽屾岀岃",4,"岉岊岋岎岏岒岓岕岝",4,"岤",4],["8d40","岪岮岯岰岲岴岶岹岺岻岼岾峀峂峃峅",5,"峌",5,"峓",5,"峚",6,"峢峣峧峩峫峬峮峯峱",9,"峼",4],["8d80","崁崄崅崈",5,"崏",4,"崕崗崘崙崚崜崝崟",4,"崥崨崪崫崬崯",4,"崵",7,"崿",7,"嵈嵉嵍",10,"嵙嵚嵜嵞",10,"嵪嵭嵮嵰嵱嵲嵳嵵",12,"嶃",21,"嶚嶛嶜嶞嶟嶠"],["8e40","嶡",21,"嶸",12,"巆",6,"巎",12,"巜巟巠巣巤巪巬巭"],["8e80","巰巵巶巸",4,"巿帀帄帇帉帊帋帍帎帒帓帗帞",7,"帨",4,"帯帰帲",4,"帹帺帾帿幀幁幃幆",5,"幍",6,"幖",4,"幜幝幟幠幣",14,"幵幷幹幾庁庂広庅庈庉庌庍庎庒庘庛庝庡庢庣庤庨",4,"庮",4,"庴庺庻庼庽庿",6],["8f40","廆廇廈廋",5,"廔廕廗廘廙廚廜",11,"廩廫",8,"廵廸廹廻廼廽弅弆弇弉弌弍弎弐弒弔弖弙弚弜弝弞弡弢弣弤"],["8f80","弨弫弬弮弰弲",6,"弻弽弾弿彁",14,"彑彔彙彚彛彜彞彟彠彣彥彧彨彫彮彯彲彴彵彶彸彺彽彾彿徃徆徍徎徏徑従徔徖徚徛徝從徟徠徢",5,"復徫徬徯",5,"徶徸徹徺徻徾",4,"忇忈忊忋忎忓忔忕忚忛応忞忟忢忣忥忦忨忩忬忯忰忲忳忴忶忷忹忺忼怇"],["9040","怈怉怋怌怐怑怓怗怘怚怞怟怢怣怤怬怭怮怰",4,"怶",4,"怽怾恀恄",6,"恌恎恏恑恓恔恖恗恘恛恜恞恟恠恡恥恦恮恱恲恴恵恷恾悀"],["9080","悁悂悅悆悇悈悊悋悎悏悐悑悓悕悗悘悙悜悞悡悢悤悥悧悩悪悮悰悳悵悶悷悹悺悽",7,"惇惈惉惌",4,"惒惓惔惖惗惙惛惞惡",4,"惪惱惲惵惷惸惻",4,"愂愃愄愅愇愊愋愌愐",4,"愖愗愘愙愛愜愝愞愡愢愥愨愩愪愬",18,"慀",6],["9140","慇慉態慍慏慐慒慓慔慖",6,"慞慟慠慡慣慤慥慦慩",6,"慱慲慳慴慶慸",18,"憌憍憏",4,"憕"],["9180","憖",6,"憞",8,"憪憫憭",9,"憸",5,"憿懀懁懃",4,"應懌",4,"懓懕",16,"懧",13,"懶",8,"戀",5,"戇戉戓戔戙戜戝戞戠戣戦戧戨戩戫戭戯戰戱戲戵戶戸",4,"扂扄扅扆扊"],["9240","扏扐払扖扗扙扚扜",6,"扤扥扨扱扲扴扵扷扸扺扻扽抁抂抃抅抆抇抈抋",5,"抔抙抜抝択抣抦抧抩抪抭抮抯抰抲抳抴抶抷抸抺抾拀拁"],["9280","拃拋拏拑拕拝拞拠拡拤拪拫拰拲拵拸拹拺拻挀挃挄挅挆挊挋挌挍挏挐挒挓挔挕挗挘挙挜挦挧挩挬挭挮挰挱挳",5,"挻挼挾挿捀捁捄捇捈捊捑捒捓捔捖",7,"捠捤捥捦捨捪捫捬捯捰捲捳捴捵捸捹捼捽捾捿掁掃掄掅掆掋掍掑掓掔掕掗掙",6,"採掤掦掫掯掱掲掵掶掹掻掽掿揀"],["9340","揁揂揃揅揇揈揊揋揌揑揓揔揕揗",6,"揟揢揤",4,"揫揬揮揯揰揱揳揵揷揹揺揻揼揾搃搄搆",4,"損搎搑搒搕",5,"搝搟搢搣搤"],["9380","搥搧搨搩搫搮",5,"搵",4,"搻搼搾摀摂摃摉摋",6,"摓摕摖摗摙",4,"摟",7,"摨摪摫摬摮",9,"摻",6,"撃撆撈",8,"撓撔撗撘撚撛撜撝撟",4,"撥撦撧撨撪撫撯撱撲撳撴撶撹撻撽撾撿擁擃擄擆",6,"擏擑擓擔擕擖擙據"],["9440","擛擜擝擟擠擡擣擥擧",24,"攁",7,"攊",7,"攓",4,"攙",8],["9480","攢攣攤攦",4,"攬攭攰攱攲攳攷攺攼攽敀",4,"敆敇敊敋敍敎敐敒敓敔敗敘敚敜敟敠敡敤敥敧敨敩敪敭敮敯敱敳敵敶數",14,"斈斉斊斍斎斏斒斔斕斖斘斚斝斞斠斢斣斦斨斪斬斮斱",7,"斺斻斾斿旀旂旇旈旉旊旍旐旑旓旔旕旘",7,"旡旣旤旪旫"],["9540","旲旳旴旵旸旹旻",4,"昁昄昅昇昈昉昋昍昐昑昒昖昗昘昚昛昜昞昡昢昣昤昦昩昪昫昬昮昰昲昳昷",4,"昽昿晀時晄",6,"晍晎晐晑晘"],["9580","晙晛晜晝晞晠晢晣晥晧晩",4,"晱晲晳晵晸晹晻晼晽晿暀暁暃暅暆暈暉暊暋暍暎暏暐暒暓暔暕暘",4,"暞",8,"暩",4,"暯",4,"暵暶暷暸暺暻暼暽暿",25,"曚曞",7,"曧曨曪",5,"曱曵曶書曺曻曽朁朂會"],["9640","朄朅朆朇朌朎朏朑朒朓朖朘朙朚朜朞朠",5,"朧朩朮朰朲朳朶朷朸朹朻朼朾朿杁杄杅杇杊杋杍杒杔杕杗",4,"杝杢杣杤杦杧杫杬杮東杴杶"],["9680","杸杹杺杻杽枀枂枃枅枆枈枊枌枍枎枏枑枒枓枔枖枙枛枟枠枡枤枦枩枬枮枱枲枴枹",7,"柂柅",9,"柕柖柗柛柟柡柣柤柦柧柨柪柫柭柮柲柵",7,"柾栁栂栃栄栆栍栐栒栔栕栘",4,"栞栟栠栢",6,"栫",6,"栴栵栶栺栻栿桇桋桍桏桒桖",5],["9740","桜桝桞桟桪桬",7,"桵桸",8,"梂梄梇",7,"梐梑梒梔梕梖梘",9,"梣梤梥梩梪梫梬梮梱梲梴梶梷梸"],["9780","梹",6,"棁棃",5,"棊棌棎棏棐棑棓棔棖棗棙棛",4,"棡棢棤",9,"棯棲棳棴棶棷棸棻棽棾棿椀椂椃椄椆",4,"椌椏椑椓",11,"椡椢椣椥",7,"椮椯椱椲椳椵椶椷椸椺椻椼椾楀楁楃",16,"楕楖楘楙楛楜楟"],["9840","楡楢楤楥楧楨楩楪楬業楯楰楲",4,"楺楻楽楾楿榁榃榅榊榋榌榎",5,"榖榗榙榚榝",9,"榩榪榬榮榯榰榲榳榵榶榸榹榺榼榽"],["9880","榾榿槀槂",7,"構槍槏槑槒槓槕",5,"槜槝槞槡",11,"槮槯槰槱槳",9,"槾樀",9,"樋",11,"標",5,"樠樢",5,"権樫樬樭樮樰樲樳樴樶",6,"樿",4,"橅橆橈",7,"橑",6,"橚"],["9940","橜",4,"橢橣橤橦",10,"橲",6,"橺橻橽橾橿檁檂檃檅",8,"檏檒",4,"檘",7,"檡",5],["9980","檧檨檪檭",114,"欥欦欨",6],["9a40","欯欰欱欳欴欵欶欸欻欼欽欿歀歁歂歄歅歈歊歋歍",11,"歚",7,"歨歩歫",13,"歺歽歾歿殀殅殈"],["9a80","殌殎殏殐殑殔殕殗殘殙殜",4,"殢",7,"殫",7,"殶殸",6,"毀毃毄毆",4,"毌毎毐毑毘毚毜",4,"毢",7,"毬毭毮毰毱毲毴毶毷毸毺毻毼毾",6,"氈",4,"氎氒気氜氝氞氠氣氥氫氬氭氱氳氶氷氹氺氻氼氾氿汃汄汅汈汋",4,"汑汒汓汖汘"],["9b40","汙汚汢汣汥汦汧汫",4,"汱汳汵汷汸決汻汼汿沀沄沇沊沋沍沎沑沒沕沖沗沘沚沜沝沞沠沢沨沬沯沰沴沵沶沷沺泀況泂泃泆泇泈泋泍泎泏泑泒泘"],["9b80","泙泚泜泝泟泤泦泧泩泬泭泲泴泹泿洀洂洃洅洆洈洉洊洍洏洐洑洓洔洕洖洘洜洝洟",5,"洦洨洩洬洭洯洰洴洶洷洸洺洿浀浂浄浉浌浐浕浖浗浘浛浝浟浡浢浤浥浧浨浫浬浭浰浱浲浳浵浶浹浺浻浽",4,"涃涄涆涇涊涋涍涏涐涒涖",4,"涜涢涥涬涭涰涱涳涴涶涷涹",5,"淁淂淃淈淉淊"],["9c40","淍淎淏淐淒淓淔淕淗淚淛淜淟淢淣淥淧淨淩淪淭淯淰淲淴淵淶淸淺淽",7,"渆渇済渉渋渏渒渓渕渘渙減渜渞渟渢渦渧渨渪測渮渰渱渳渵"],["9c80","渶渷渹渻",7,"湅",7,"湏湐湑湒湕湗湙湚湜湝湞湠",10,"湬湭湯",14,"満溁溂溄溇溈溊",4,"溑",6,"溙溚溛溝溞溠溡溣溤溦溨溩溫溬溭溮溰溳溵溸溹溼溾溿滀滃滄滅滆滈滉滊滌滍滎滐滒滖滘滙滛滜滝滣滧滪",5],["9d40","滰滱滲滳滵滶滷滸滺",7,"漃漄漅漇漈漊",4,"漐漑漒漖",9,"漡漢漣漥漦漧漨漬漮漰漲漴漵漷",6,"漿潀潁潂"],["9d80","潃潄潅潈潉潊潌潎",9,"潙潚潛潝潟潠潡潣潤潥潧",5,"潯潰潱潳潵潶潷潹潻潽",6,"澅澆澇澊澋澏",12,"澝澞澟澠澢",4,"澨",10,"澴澵澷澸澺",5,"濁濃",5,"濊",6,"濓",10,"濟濢濣濤濥"],["9e40","濦",7,"濰",32,"瀒",7,"瀜",6,"瀤",6],["9e80","瀫",9,"瀶瀷瀸瀺",17,"灍灎灐",13,"灟",11,"灮灱灲灳灴灷灹灺灻災炁炂炃炄炆炇炈炋炌炍炏炐炑炓炗炘炚炛炞",12,"炰炲炴炵炶為炾炿烄烅烆烇烉烋",12,"烚"],["9f40","烜烝烞烠烡烢烣烥烪烮烰",6,"烸烺烻烼烾",10,"焋",4,"焑焒焔焗焛",10,"焧",7,"焲焳焴"],["9f80","焵焷",13,"煆煇煈煉煋煍煏",12,"煝煟",4,"煥煩",4,"煯煰煱煴煵煶煷煹煻煼煾",5,"熅",4,"熋熌熍熎熐熑熒熓熕熖熗熚",4,"熡",6,"熩熪熫熭",5,"熴熶熷熸熺",8,"燄",9,"燏",4],["a040","燖",9,"燡燢燣燤燦燨",5,"燯",9,"燺",11,"爇",19],["a080","爛爜爞",9,"爩爫爭爮爯爲爳爴爺爼爾牀",6,"牉牊牋牎牏牐牑牓牔牕牗牘牚牜牞牠牣牤牥牨牪牫牬牭牰牱牳牴牶牷牸牻牼牽犂犃犅",4,"犌犎犐犑犓",11,"犠",11,"犮犱犲犳犵犺",6,"狅狆狇狉狊狋狌狏狑狓狔狕狖狘狚狛"],["a1a1"," 、。·ˉˇ¨〃々—~‖…‘’“”〔〕〈",7,"〖〗【】±×÷∶∧∨∑∏∪∩∈∷√⊥∥∠⌒⊙∫∮≡≌≈∽∝≠≮≯≤≥∞∵∴♂♀°′″℃$¤¢£‰§№☆★○●◎◇◆□■△▲※→←↑↓〓"],["a2a1","ⅰ",9],["a2b1","⒈",19,"⑴",19,"①",9],["a2e5","㈠",9],["a2f1","Ⅰ",11],["a3a1","!"#¥%",88," ̄"],["a4a1","ぁ",82],["a5a1","ァ",85],["a6a1","Α",16,"Σ",6],["a6c1","α",16,"σ",6],["a6e0","︵︶︹︺︿﹀︽︾﹁﹂﹃﹄"],["a6ee","︻︼︷︸︱"],["a6f4","︳︴"],["a7a1","А",5,"ЁЖ",25],["a7d1","а",5,"ёж",25],["a840","ˊˋ˙–―‥‵℅℉↖↗↘↙∕∟∣≒≦≧⊿═",35,"▁",6],["a880","█",7,"▓▔▕▼▽◢◣◤◥☉⊕〒〝〞"],["a8a1","āáǎàēéěèīíǐìōóǒòūúǔùǖǘǚǜüêɑ"],["a8bd","ńň"],["a8c0","ɡ"],["a8c5","ㄅ",36],["a940","〡",8,"㊣㎎㎏㎜㎝㎞㎡㏄㏎㏑㏒㏕︰¬¦"],["a959","℡㈱"],["a95c","‐"],["a960","ー゛゜ヽヾ〆ゝゞ﹉",9,"﹔﹕﹖﹗﹙",8],["a980","﹢",4,"﹨﹩﹪﹫"],["a996","〇"],["a9a4","─",75],["aa40","狜狝狟狢",5,"狪狫狵狶狹狽狾狿猀猂猄",5,"猋猌猍猏猐猑猒猔猘猙猚猟猠猣猤猦猧猨猭猯猰猲猳猵猶猺猻猼猽獀",8],["aa80","獉獊獋獌獎獏獑獓獔獕獖獘",7,"獡",10,"獮獰獱"],["ab40","獲",11,"獿",4,"玅玆玈玊玌玍玏玐玒玓玔玕玗玘玙玚玜玝玞玠玡玣",5,"玪玬玭玱玴玵玶玸玹玼玽玾玿珁珃",4],["ab80","珋珌珎珒",6,"珚珛珜珝珟珡珢珣珤珦珨珪珫珬珮珯珰珱珳",4],["ac40","珸",10,"琄琇琈琋琌琍琎琑",8,"琜",5,"琣琤琧琩琫琭琯琱琲琷",4,"琽琾琿瑀瑂",11],["ac80","瑎",6,"瑖瑘瑝瑠",12,"瑮瑯瑱",4,"瑸瑹瑺"],["ad40","瑻瑼瑽瑿璂璄璅璆璈璉璊璌璍璏璑",10,"璝璟",7,"璪",15,"璻",12],["ad80","瓈",9,"瓓",8,"瓝瓟瓡瓥瓧",6,"瓰瓱瓲"],["ae40","瓳瓵瓸",6,"甀甁甂甃甅",7,"甎甐甒甔甕甖甗甛甝甞甠",4,"甦甧甪甮甴甶甹甼甽甿畁畂畃畄畆畇畉畊畍畐畑畒畓畕畖畗畘"],["ae80","畝",7,"畧畨畩畫",6,"畳畵當畷畺",4,"疀疁疂疄疅疇"],["af40","疈疉疊疌疍疎疐疓疕疘疛疜疞疢疦",4,"疭疶疷疺疻疿痀痁痆痋痌痎痏痐痑痓痗痙痚痜痝痟痠痡痥痩痬痭痮痯痲痳痵痶痷痸痺痻痽痾瘂瘄瘆瘇"],["af80","瘈瘉瘋瘍瘎瘏瘑瘒瘓瘔瘖瘚瘜瘝瘞瘡瘣瘧瘨瘬瘮瘯瘱瘲瘶瘷瘹瘺瘻瘽癁療癄"],["b040","癅",6,"癎",5,"癕癗",4,"癝癟癠癡癢癤",6,"癬癭癮癰",7,"癹発發癿皀皁皃皅皉皊皌皍皏皐皒皔皕皗皘皚皛"],["b080","皜",7,"皥",8,"皯皰皳皵",9,"盀盁盃啊阿埃挨哎唉哀皑癌蔼矮艾碍爱隘鞍氨安俺按暗岸胺案肮昂盎凹敖熬翱袄傲奥懊澳芭捌扒叭吧笆八疤巴拔跋靶把耙坝霸罢爸白柏百摆佰败拜稗斑班搬扳般颁板版扮拌伴瓣半办绊邦帮梆榜膀绑棒磅蚌镑傍谤苞胞包褒剥"],["b140","盄盇盉盋盌盓盕盙盚盜盝盞盠",4,"盦",7,"盰盳盵盶盷盺盻盽盿眀眂眃眅眆眊県眎",10,"眛眜眝眞眡眣眤眥眧眪眫"],["b180","眬眮眰",4,"眹眻眽眾眿睂睄睅睆睈",7,"睒",7,"睜薄雹保堡饱宝抱报暴豹鲍爆杯碑悲卑北辈背贝钡倍狈备惫焙被奔苯本笨崩绷甭泵蹦迸逼鼻比鄙笔彼碧蓖蔽毕毙毖币庇痹闭敝弊必辟壁臂避陛鞭边编贬扁便变卞辨辩辫遍标彪膘表鳖憋别瘪彬斌濒滨宾摈兵冰柄丙秉饼炳"],["b240","睝睞睟睠睤睧睩睪睭",11,"睺睻睼瞁瞂瞃瞆",5,"瞏瞐瞓",11,"瞡瞣瞤瞦瞨瞫瞭瞮瞯瞱瞲瞴瞶",4],["b280","瞼瞾矀",12,"矎",8,"矘矙矚矝",4,"矤病并玻菠播拨钵波博勃搏铂箔伯帛舶脖膊渤泊驳捕卜哺补埠不布步簿部怖擦猜裁材才财睬踩采彩菜蔡餐参蚕残惭惨灿苍舱仓沧藏操糙槽曹草厕策侧册测层蹭插叉茬茶查碴搽察岔差诧拆柴豺搀掺蝉馋谗缠铲产阐颤昌猖"],["b340","矦矨矪矯矰矱矲矴矵矷矹矺矻矼砃",5,"砊砋砎砏砐砓砕砙砛砞砠砡砢砤砨砪砫砮砯砱砲砳砵砶砽砿硁硂硃硄硆硈硉硊硋硍硏硑硓硔硘硙硚"],["b380","硛硜硞",11,"硯",7,"硸硹硺硻硽",6,"场尝常长偿肠厂敞畅唱倡超抄钞朝嘲潮巢吵炒车扯撤掣彻澈郴臣辰尘晨忱沉陈趁衬撑称城橙成呈乘程惩澄诚承逞骋秤吃痴持匙池迟弛驰耻齿侈尺赤翅斥炽充冲虫崇宠抽酬畴踌稠愁筹仇绸瞅丑臭初出橱厨躇锄雏滁除楚"],["b440","碄碅碆碈碊碋碏碐碒碔碕碖碙碝碞碠碢碤碦碨",7,"碵碶碷碸確碻碼碽碿磀磂磃磄磆磇磈磌磍磎磏磑磒磓磖磗磘磚",9],["b480","磤磥磦磧磩磪磫磭",4,"磳磵磶磸磹磻",5,"礂礃礄礆",6,"础储矗搐触处揣川穿椽传船喘串疮窗幢床闯创吹炊捶锤垂春椿醇唇淳纯蠢戳绰疵茨磁雌辞慈瓷词此刺赐次聪葱囱匆从丛凑粗醋簇促蹿篡窜摧崔催脆瘁粹淬翠村存寸磋撮搓措挫错搭达答瘩打大呆歹傣戴带殆代贷袋待逮"],["b540","礍",5,"礔",9,"礟",4,"礥",14,"礵",4,"礽礿祂祃祄祅祇祊",8,"祔祕祘祙祡祣"],["b580","祤祦祩祪祫祬祮祰",6,"祹祻",4,"禂禃禆禇禈禉禋禌禍禎禐禑禒怠耽担丹单郸掸胆旦氮但惮淡诞弹蛋当挡党荡档刀捣蹈倒岛祷导到稻悼道盗德得的蹬灯登等瞪凳邓堤低滴迪敌笛狄涤翟嫡抵底地蒂第帝弟递缔颠掂滇碘点典靛垫电佃甸店惦奠淀殿碉叼雕凋刁掉吊钓调跌爹碟蝶迭谍叠"],["b640","禓",6,"禛",11,"禨",10,"禴",4,"禼禿秂秄秅秇秈秊秌秎秏秐秓秔秖秗秙",5,"秠秡秢秥秨秪"],["b680","秬秮秱",6,"秹秺秼秾秿稁稄稅稇稈稉稊稌稏",4,"稕稖稘稙稛稜丁盯叮钉顶鼎锭定订丢东冬董懂动栋侗恫冻洞兜抖斗陡豆逗痘都督毒犊独读堵睹赌杜镀肚度渡妒端短锻段断缎堆兑队对墩吨蹲敦顿囤钝盾遁掇哆多夺垛躲朵跺舵剁惰堕蛾峨鹅俄额讹娥恶厄扼遏鄂饿恩而儿耳尔饵洱二"],["b740","稝稟稡稢稤",14,"稴稵稶稸稺稾穀",5,"穇",9,"穒",4,"穘",16],["b780","穩",6,"穱穲穳穵穻穼穽穾窂窅窇窉窊窋窌窎窏窐窓窔窙窚窛窞窡窢贰发罚筏伐乏阀法珐藩帆番翻樊矾钒繁凡烦反返范贩犯饭泛坊芳方肪房防妨仿访纺放菲非啡飞肥匪诽吠肺废沸费芬酚吩氛分纷坟焚汾粉奋份忿愤粪丰封枫蜂峰锋风疯烽逢冯缝讽奉凤佛否夫敷肤孵扶拂辐幅氟符伏俘服"],["b840","窣窤窧窩窪窫窮",4,"窴",10,"竀",10,"竌",9,"竗竘竚竛竜竝竡竢竤竧",5,"竮竰竱竲竳"],["b880","竴",4,"竻竼竾笀笁笂笅笇笉笌笍笎笐笒笓笖笗笘笚笜笝笟笡笢笣笧笩笭浮涪福袱弗甫抚辅俯釜斧脯腑府腐赴副覆赋复傅付阜父腹负富讣附妇缚咐噶嘎该改概钙盖溉干甘杆柑竿肝赶感秆敢赣冈刚钢缸肛纲岗港杠篙皋高膏羔糕搞镐稿告哥歌搁戈鸽胳疙割革葛格蛤阁隔铬个各给根跟耕更庚羹"],["b940","笯笰笲笴笵笶笷笹笻笽笿",5,"筆筈筊筍筎筓筕筗筙筜筞筟筡筣",10,"筯筰筳筴筶筸筺筼筽筿箁箂箃箄箆",6,"箎箏"],["b980","箑箒箓箖箘箙箚箛箞箟箠箣箤箥箮箯箰箲箳箵箶箷箹",7,"篂篃範埂耿梗工攻功恭龚供躬公宫弓巩汞拱贡共钩勾沟苟狗垢构购够辜菇咕箍估沽孤姑鼓古蛊骨谷股故顾固雇刮瓜剐寡挂褂乖拐怪棺关官冠观管馆罐惯灌贯光广逛瑰规圭硅归龟闺轨鬼诡癸桂柜跪贵刽辊滚棍锅郭国果裹过哈"],["ba40","篅篈築篊篋篍篎篏篐篒篔",4,"篛篜篞篟篠篢篣篤篧篨篩篫篬篭篯篰篲",4,"篸篹篺篻篽篿",7,"簈簉簊簍簎簐",5,"簗簘簙"],["ba80","簚",4,"簠",5,"簨簩簫",12,"簹",5,"籂骸孩海氦亥害骇酣憨邯韩含涵寒函喊罕翰撼捍旱憾悍焊汗汉夯杭航壕嚎豪毫郝好耗号浩呵喝荷菏核禾和何合盒貉阂河涸赫褐鹤贺嘿黑痕很狠恨哼亨横衡恒轰哄烘虹鸿洪宏弘红喉侯猴吼厚候后呼乎忽瑚壶葫胡蝴狐糊湖"],["bb40","籃",9,"籎",36,"籵",5,"籾",9],["bb80","粈粊",6,"粓粔粖粙粚粛粠粡粣粦粧粨粩粫粬粭粯粰粴",4,"粺粻弧虎唬护互沪户花哗华猾滑画划化话槐徊怀淮坏欢环桓还缓换患唤痪豢焕涣宦幻荒慌黄磺蝗簧皇凰惶煌晃幌恍谎灰挥辉徽恢蛔回毁悔慧卉惠晦贿秽会烩汇讳诲绘荤昏婚魂浑混豁活伙火获或惑霍货祸击圾基机畸稽积箕"],["bc40","粿糀糂糃糄糆糉糋糎",6,"糘糚糛糝糞糡",6,"糩",5,"糰",7,"糹糺糼",13,"紋",5],["bc80","紑",14,"紡紣紤紥紦紨紩紪紬紭紮細",6,"肌饥迹激讥鸡姬绩缉吉极棘辑籍集及急疾汲即嫉级挤几脊己蓟技冀季伎祭剂悸济寄寂计记既忌际妓继纪嘉枷夹佳家加荚颊贾甲钾假稼价架驾嫁歼监坚尖笺间煎兼肩艰奸缄茧检柬碱硷拣捡简俭剪减荐槛鉴践贱见键箭件"],["bd40","紷",54,"絯",7],["bd80","絸",32,"健舰剑饯渐溅涧建僵姜将浆江疆蒋桨奖讲匠酱降蕉椒礁焦胶交郊浇骄娇嚼搅铰矫侥脚狡角饺缴绞剿教酵轿较叫窖揭接皆秸街阶截劫节桔杰捷睫竭洁结解姐戒藉芥界借介疥诫届巾筋斤金今津襟紧锦仅谨进靳晋禁近烬浸"],["be40","継",12,"綧",6,"綯",42],["be80","線",32,"尽劲荆兢茎睛晶鲸京惊精粳经井警景颈静境敬镜径痉靖竟竞净炯窘揪究纠玖韭久灸九酒厩救旧臼舅咎就疚鞠拘狙疽居驹菊局咀矩举沮聚拒据巨具距踞锯俱句惧炬剧捐鹃娟倦眷卷绢撅攫抉掘倔爵觉决诀绝均菌钧军君峻"],["bf40","緻",62],["bf80","縺縼",4,"繂",4,"繈",21,"俊竣浚郡骏喀咖卡咯开揩楷凯慨刊堪勘坎砍看康慷糠扛抗亢炕考拷烤靠坷苛柯棵磕颗科壳咳可渴克刻客课肯啃垦恳坑吭空恐孔控抠口扣寇枯哭窟苦酷库裤夸垮挎跨胯块筷侩快宽款匡筐狂框矿眶旷况亏盔岿窥葵奎魁傀"],["c040","繞",35,"纃",23,"纜纝纞"],["c080","纮纴纻纼绖绤绬绹缊缐缞缷缹缻",6,"罃罆",9,"罒罓馈愧溃坤昆捆困括扩廓阔垃拉喇蜡腊辣啦莱来赖蓝婪栏拦篮阑兰澜谰揽览懒缆烂滥琅榔狼廊郎朗浪捞劳牢老佬姥酪烙涝勒乐雷镭蕾磊累儡垒擂肋类泪棱楞冷厘梨犁黎篱狸离漓理李里鲤礼莉荔吏栗丽厉励砾历利傈例俐"],["c140","罖罙罛罜罝罞罠罣",4,"罫罬罭罯罰罳罵罶罷罸罺罻罼罽罿羀羂",7,"羋羍羏",4,"羕",4,"羛羜羠羢羣羥羦羨",6,"羱"],["c180","羳",4,"羺羻羾翀翂翃翄翆翇翈翉翋翍翏",4,"翖翗翙",5,"翢翣痢立粒沥隶力璃哩俩联莲连镰廉怜涟帘敛脸链恋炼练粮凉梁粱良两辆量晾亮谅撩聊僚疗燎寥辽潦了撂镣廖料列裂烈劣猎琳林磷霖临邻鳞淋凛赁吝拎玲菱零龄铃伶羚凌灵陵岭领另令溜琉榴硫馏留刘瘤流柳六龙聋咙笼窿"],["c240","翤翧翨翪翫翬翭翯翲翴",6,"翽翾翿耂耇耈耉耊耎耏耑耓耚耛耝耞耟耡耣耤耫",5,"耲耴耹耺耼耾聀聁聄聅聇聈聉聎聏聐聑聓聕聖聗"],["c280","聙聛",13,"聫",5,"聲",11,"隆垄拢陇楼娄搂篓漏陋芦卢颅庐炉掳卤虏鲁麓碌露路赂鹿潞禄录陆戮驴吕铝侣旅履屡缕虑氯律率滤绿峦挛孪滦卵乱掠略抡轮伦仑沦纶论萝螺罗逻锣箩骡裸落洛骆络妈麻玛码蚂马骂嘛吗埋买麦卖迈脉瞒馒蛮满蔓曼慢漫"],["c340","聾肁肂肅肈肊肍",5,"肔肕肗肙肞肣肦肧肨肬肰肳肵肶肸肹肻胅胇",4,"胏",6,"胘胟胠胢胣胦胮胵胷胹胻胾胿脀脁脃脄脅脇脈脋"],["c380","脌脕脗脙脛脜脝脟",12,"脭脮脰脳脴脵脷脹",4,"脿谩芒茫盲氓忙莽猫茅锚毛矛铆卯茂冒帽貌贸么玫枚梅酶霉煤没眉媒镁每美昧寐妹媚门闷们萌蒙檬盟锰猛梦孟眯醚靡糜迷谜弥米秘觅泌蜜密幂棉眠绵冕免勉娩缅面苗描瞄藐秒渺庙妙蔑灭民抿皿敏悯闽明螟鸣铭名命谬摸"],["c440","腀",5,"腇腉腍腎腏腒腖腗腘腛",4,"腡腢腣腤腦腨腪腫腬腯腲腳腵腶腷腸膁膃",4,"膉膋膌膍膎膐膒",5,"膙膚膞",4,"膤膥"],["c480","膧膩膫",7,"膴",5,"膼膽膾膿臄臅臇臈臉臋臍",6,"摹蘑模膜磨摩魔抹末莫墨默沫漠寞陌谋牟某拇牡亩姆母墓暮幕募慕木目睦牧穆拿哪呐钠那娜纳氖乃奶耐奈南男难囊挠脑恼闹淖呢馁内嫩能妮霓倪泥尼拟你匿腻逆溺蔫拈年碾撵捻念娘酿鸟尿捏聂孽啮镊镍涅您柠狞凝宁"],["c540","臔",14,"臤臥臦臨臩臫臮",4,"臵",5,"臽臿舃與",4,"舎舏舑舓舕",5,"舝舠舤舥舦舧舩舮舲舺舼舽舿"],["c580","艀艁艂艃艅艆艈艊艌艍艎艐",7,"艙艛艜艝艞艠",7,"艩拧泞牛扭钮纽脓浓农弄奴努怒女暖虐疟挪懦糯诺哦欧鸥殴藕呕偶沤啪趴爬帕怕琶拍排牌徘湃派攀潘盘磐盼畔判叛乓庞旁耪胖抛咆刨炮袍跑泡呸胚培裴赔陪配佩沛喷盆砰抨烹澎彭蓬棚硼篷膨朋鹏捧碰坯砒霹批披劈琵毗"],["c640","艪艫艬艭艱艵艶艷艸艻艼芀芁芃芅芆芇芉芌芐芓芔芕芖芚芛芞芠芢芣芧芲芵芶芺芻芼芿苀苂苃苅苆苉苐苖苙苚苝苢苧苨苩苪苬苭苮苰苲苳苵苶苸"],["c680","苺苼",4,"茊茋茍茐茒茓茖茘茙茝",9,"茩茪茮茰茲茷茻茽啤脾疲皮匹痞僻屁譬篇偏片骗飘漂瓢票撇瞥拼频贫品聘乒坪苹萍平凭瓶评屏坡泼颇婆破魄迫粕剖扑铺仆莆葡菩蒲埔朴圃普浦谱曝瀑期欺栖戚妻七凄漆柒沏其棋奇歧畦崎脐齐旗祈祁骑起岂乞企启契砌器气迄弃汽泣讫掐"],["c740","茾茿荁荂荄荅荈荊",4,"荓荕",4,"荝荢荰",6,"荹荺荾",6,"莇莈莊莋莌莍莏莐莑莔莕莖莗莙莚莝莟莡",6,"莬莭莮"],["c780","莯莵莻莾莿菂菃菄菆菈菉菋菍菎菐菑菒菓菕菗菙菚菛菞菢菣菤菦菧菨菫菬菭恰洽牵扦钎铅千迁签仟谦乾黔钱钳前潜遣浅谴堑嵌欠歉枪呛腔羌墙蔷强抢橇锹敲悄桥瞧乔侨巧鞘撬翘峭俏窍切茄且怯窃钦侵亲秦琴勤芹擒禽寝沁青轻氢倾卿清擎晴氰情顷请庆琼穷秋丘邱球求囚酋泅趋区蛆曲躯屈驱渠"],["c840","菮華菳",4,"菺菻菼菾菿萀萂萅萇萈萉萊萐萒",5,"萙萚萛萞",5,"萩",7,"萲",5,"萹萺萻萾",7,"葇葈葉"],["c880","葊",6,"葒",4,"葘葝葞葟葠葢葤",4,"葪葮葯葰葲葴葷葹葻葼取娶龋趣去圈颧权醛泉全痊拳犬券劝缺炔瘸却鹊榷确雀裙群然燃冉染瓤壤攘嚷让饶扰绕惹热壬仁人忍韧任认刃妊纫扔仍日戎茸蓉荣融熔溶容绒冗揉柔肉茹蠕儒孺如辱乳汝入褥软阮蕊瑞锐闰润若弱撒洒萨腮鳃塞赛三叁"],["c940","葽",4,"蒃蒄蒅蒆蒊蒍蒏",7,"蒘蒚蒛蒝蒞蒟蒠蒢",12,"蒰蒱蒳蒵蒶蒷蒻蒼蒾蓀蓂蓃蓅蓆蓇蓈蓋蓌蓎蓏蓒蓔蓕蓗"],["c980","蓘",4,"蓞蓡蓢蓤蓧",4,"蓭蓮蓯蓱",10,"蓽蓾蔀蔁蔂伞散桑嗓丧搔骚扫嫂瑟色涩森僧莎砂杀刹沙纱傻啥煞筛晒珊苫杉山删煽衫闪陕擅赡膳善汕扇缮墒伤商赏晌上尚裳梢捎稍烧芍勺韶少哨邵绍奢赊蛇舌舍赦摄射慑涉社设砷申呻伸身深娠绅神沈审婶甚肾慎渗声生甥牲升绳"],["ca40","蔃",8,"蔍蔎蔏蔐蔒蔔蔕蔖蔘蔙蔛蔜蔝蔞蔠蔢",8,"蔭",9,"蔾",4,"蕄蕅蕆蕇蕋",10],["ca80","蕗蕘蕚蕛蕜蕝蕟",4,"蕥蕦蕧蕩",8,"蕳蕵蕶蕷蕸蕼蕽蕿薀薁省盛剩胜圣师失狮施湿诗尸虱十石拾时什食蚀实识史矢使屎驶始式示士世柿事拭誓逝势是嗜噬适仕侍释饰氏市恃室视试收手首守寿授售受瘦兽蔬枢梳殊抒输叔舒淑疏书赎孰熟薯暑曙署蜀黍鼠属术述树束戍竖墅庶数漱"],["cb40","薂薃薆薈",6,"薐",10,"薝",6,"薥薦薧薩薫薬薭薱",5,"薸薺",6,"藂",6,"藊",4,"藑藒"],["cb80","藔藖",5,"藝",6,"藥藦藧藨藪",14,"恕刷耍摔衰甩帅栓拴霜双爽谁水睡税吮瞬顺舜说硕朔烁斯撕嘶思私司丝死肆寺嗣四伺似饲巳松耸怂颂送宋讼诵搜艘擞嗽苏酥俗素速粟僳塑溯宿诉肃酸蒜算虽隋随绥髓碎岁穗遂隧祟孙损笋蓑梭唆缩琐索锁所塌他它她塔"],["cc40","藹藺藼藽藾蘀",4,"蘆",10,"蘒蘓蘔蘕蘗",15,"蘨蘪",13,"蘹蘺蘻蘽蘾蘿虀"],["cc80","虁",11,"虒虓處",4,"虛虜虝號虠虡虣",7,"獭挞蹋踏胎苔抬台泰酞太态汰坍摊贪瘫滩坛檀痰潭谭谈坦毯袒碳探叹炭汤塘搪堂棠膛唐糖倘躺淌趟烫掏涛滔绦萄桃逃淘陶讨套特藤腾疼誊梯剔踢锑提题蹄啼体替嚏惕涕剃屉天添填田甜恬舔腆挑条迢眺跳贴铁帖厅听烃"],["cd40","虭虯虰虲",6,"蚃",6,"蚎",4,"蚔蚖",5,"蚞",4,"蚥蚦蚫蚭蚮蚲蚳蚷蚸蚹蚻",4,"蛁蛂蛃蛅蛈蛌蛍蛒蛓蛕蛖蛗蛚蛜"],["cd80","蛝蛠蛡蛢蛣蛥蛦蛧蛨蛪蛫蛬蛯蛵蛶蛷蛺蛻蛼蛽蛿蜁蜄蜅蜆蜋蜌蜎蜏蜐蜑蜔蜖汀廷停亭庭挺艇通桐酮瞳同铜彤童桶捅筒统痛偷投头透凸秃突图徒途涂屠土吐兔湍团推颓腿蜕褪退吞屯臀拖托脱鸵陀驮驼椭妥拓唾挖哇蛙洼娃瓦袜歪外豌弯湾玩顽丸烷完碗挽晚皖惋宛婉万腕汪王亡枉网往旺望忘妄威"],["ce40","蜙蜛蜝蜟蜠蜤蜦蜧蜨蜪蜫蜬蜭蜯蜰蜲蜳蜵蜶蜸蜹蜺蜼蜽蝀",6,"蝊蝋蝍蝏蝐蝑蝒蝔蝕蝖蝘蝚",5,"蝡蝢蝦",7,"蝯蝱蝲蝳蝵"],["ce80","蝷蝸蝹蝺蝿螀螁螄螆螇螉螊螌螎",4,"螔螕螖螘",6,"螠",4,"巍微危韦违桅围唯惟为潍维苇萎委伟伪尾纬未蔚味畏胃喂魏位渭谓尉慰卫瘟温蚊文闻纹吻稳紊问嗡翁瓮挝蜗涡窝我斡卧握沃巫呜钨乌污诬屋无芜梧吾吴毋武五捂午舞伍侮坞戊雾晤物勿务悟误昔熙析西硒矽晰嘻吸锡牺"],["cf40","螥螦螧螩螪螮螰螱螲螴螶螷螸螹螻螼螾螿蟁",4,"蟇蟈蟉蟌",4,"蟔",6,"蟜蟝蟞蟟蟡蟢蟣蟤蟦蟧蟨蟩蟫蟬蟭蟯",9],["cf80","蟺蟻蟼蟽蟿蠀蠁蠂蠄",5,"蠋",7,"蠔蠗蠘蠙蠚蠜",4,"蠣稀息希悉膝夕惜熄烯溪汐犀檄袭席习媳喜铣洗系隙戏细瞎虾匣霞辖暇峡侠狭下厦夏吓掀锨先仙鲜纤咸贤衔舷闲涎弦嫌显险现献县腺馅羡宪陷限线相厢镶香箱襄湘乡翔祥详想响享项巷橡像向象萧硝霄削哮嚣销消宵淆晓"],["d040","蠤",13,"蠳",5,"蠺蠻蠽蠾蠿衁衂衃衆",5,"衎",5,"衕衖衘衚",6,"衦衧衪衭衯衱衳衴衵衶衸衹衺"],["d080","衻衼袀袃袆袇袉袊袌袎袏袐袑袓袔袕袗",4,"袝",4,"袣袥",5,"小孝校肖啸笑效楔些歇蝎鞋协挟携邪斜胁谐写械卸蟹懈泄泻谢屑薪芯锌欣辛新忻心信衅星腥猩惺兴刑型形邢行醒幸杏性姓兄凶胸匈汹雄熊休修羞朽嗅锈秀袖绣墟戌需虚嘘须徐许蓄酗叙旭序畜恤絮婿绪续轩喧宣悬旋玄"],["d140","袬袮袯袰袲",4,"袸袹袺袻袽袾袿裀裃裄裇裈裊裋裌裍裏裐裑裓裖裗裚",4,"裠裡裦裧裩",6,"裲裵裶裷裺裻製裿褀褁褃",5],["d180","褉褋",4,"褑褔",4,"褜",4,"褢褣褤褦褧褨褩褬褭褮褯褱褲褳褵褷选癣眩绚靴薛学穴雪血勋熏循旬询寻驯巡殉汛训讯逊迅压押鸦鸭呀丫芽牙蚜崖衙涯雅哑亚讶焉咽阉烟淹盐严研蜒岩延言颜阎炎沿奄掩眼衍演艳堰燕厌砚雁唁彦焰宴谚验殃央鸯秧杨扬佯疡羊洋阳氧仰痒养样漾邀腰妖瑶"],["d240","褸",8,"襂襃襅",24,"襠",5,"襧",19,"襼"],["d280","襽襾覀覂覄覅覇",26,"摇尧遥窑谣姚咬舀药要耀椰噎耶爷野冶也页掖业叶曳腋夜液一壹医揖铱依伊衣颐夷遗移仪胰疑沂宜姨彝椅蚁倚已乙矣以艺抑易邑屹亿役臆逸肄疫亦裔意毅忆义益溢诣议谊译异翼翌绎茵荫因殷音阴姻吟银淫寅饮尹引隐"],["d340","覢",30,"觃觍觓觔觕觗觘觙觛觝觟觠觡觢觤觧觨觩觪觬觭觮觰觱觲觴",6],["d380","觻",4,"訁",5,"計",21,"印英樱婴鹰应缨莹萤营荧蝇迎赢盈影颖硬映哟拥佣臃痈庸雍踊蛹咏泳涌永恿勇用幽优悠忧尤由邮铀犹油游酉有友右佑釉诱又幼迂淤于盂榆虞愚舆余俞逾鱼愉渝渔隅予娱雨与屿禹宇语羽玉域芋郁吁遇喻峪御愈欲狱育誉"],["d440","訞",31,"訿",8,"詉",21],["d480","詟",25,"詺",6,"浴寓裕预豫驭鸳渊冤元垣袁原援辕园员圆猿源缘远苑愿怨院曰约越跃钥岳粤月悦阅耘云郧匀陨允运蕴酝晕韵孕匝砸杂栽哉灾宰载再在咱攒暂赞赃脏葬遭糟凿藻枣早澡蚤躁噪造皂灶燥责择则泽贼怎增憎曾赠扎喳渣札轧"],["d540","誁",7,"誋",7,"誔",46],["d580","諃",32,"铡闸眨栅榨咋乍炸诈摘斋宅窄债寨瞻毡詹粘沾盏斩辗崭展蘸栈占战站湛绽樟章彰漳张掌涨杖丈帐账仗胀瘴障招昭找沼赵照罩兆肇召遮折哲蛰辙者锗蔗这浙珍斟真甄砧臻贞针侦枕疹诊震振镇阵蒸挣睁征狰争怔整拯正政"],["d640","諤",34,"謈",27],["d680","謤謥謧",30,"帧症郑证芝枝支吱蜘知肢脂汁之织职直植殖执值侄址指止趾只旨纸志挚掷至致置帜峙制智秩稚质炙痔滞治窒中盅忠钟衷终种肿重仲众舟周州洲诌粥轴肘帚咒皱宙昼骤珠株蛛朱猪诸诛逐竹烛煮拄瞩嘱主著柱助蛀贮铸筑"],["d740","譆",31,"譧",4,"譭",25],["d780","讇",24,"讬讱讻诇诐诪谉谞住注祝驻抓爪拽专砖转撰赚篆桩庄装妆撞壮状椎锥追赘坠缀谆准捉拙卓桌琢茁酌啄着灼浊兹咨资姿滋淄孜紫仔籽滓子自渍字鬃棕踪宗综总纵邹走奏揍租足卒族祖诅阻组钻纂嘴醉最罪尊遵昨左佐柞做作坐座"],["d840","谸",8,"豂豃豄豅豈豊豋豍",7,"豖豗豘豙豛",5,"豣",6,"豬",6,"豴豵豶豷豻",6,"貃貄貆貇"],["d880","貈貋貍",6,"貕貖貗貙",20,"亍丌兀丐廿卅丕亘丞鬲孬噩丨禺丿匕乇夭爻卮氐囟胤馗毓睾鼗丶亟鼐乜乩亓芈孛啬嘏仄厍厝厣厥厮靥赝匚叵匦匮匾赜卦卣刂刈刎刭刳刿剀剌剞剡剜蒯剽劂劁劐劓冂罔亻仃仉仂仨仡仫仞伛仳伢佤仵伥伧伉伫佞佧攸佚佝"],["d940","貮",62],["d980","賭",32,"佟佗伲伽佶佴侑侉侃侏佾佻侪佼侬侔俦俨俪俅俚俣俜俑俟俸倩偌俳倬倏倮倭俾倜倌倥倨偾偃偕偈偎偬偻傥傧傩傺僖儆僭僬僦僮儇儋仝氽佘佥俎龠汆籴兮巽黉馘冁夔勹匍訇匐凫夙兕亠兖亳衮袤亵脔裒禀嬴蠃羸冫冱冽冼"],["da40","贎",14,"贠赑赒赗赟赥赨赩赪赬赮赯赱赲赸",8,"趂趃趆趇趈趉趌",4,"趒趓趕",9,"趠趡"],["da80","趢趤",12,"趲趶趷趹趻趽跀跁跂跅跇跈跉跊跍跐跒跓跔凇冖冢冥讠讦讧讪讴讵讷诂诃诋诏诎诒诓诔诖诘诙诜诟诠诤诨诩诮诰诳诶诹诼诿谀谂谄谇谌谏谑谒谔谕谖谙谛谘谝谟谠谡谥谧谪谫谮谯谲谳谵谶卩卺阝阢阡阱阪阽阼陂陉陔陟陧陬陲陴隈隍隗隰邗邛邝邙邬邡邴邳邶邺"],["db40","跕跘跙跜跠跡跢跥跦跧跩跭跮跰跱跲跴跶跼跾",6,"踆踇踈踋踍踎踐踑踒踓踕",7,"踠踡踤",4,"踫踭踰踲踳踴踶踷踸踻踼踾"],["db80","踿蹃蹅蹆蹌",4,"蹓",5,"蹚",11,"蹧蹨蹪蹫蹮蹱邸邰郏郅邾郐郄郇郓郦郢郜郗郛郫郯郾鄄鄢鄞鄣鄱鄯鄹酃酆刍奂劢劬劭劾哿勐勖勰叟燮矍廴凵凼鬯厶弁畚巯坌垩垡塾墼壅壑圩圬圪圳圹圮圯坜圻坂坩垅坫垆坼坻坨坭坶坳垭垤垌垲埏垧垴垓垠埕埘埚埙埒垸埴埯埸埤埝"],["dc40","蹳蹵蹷",4,"蹽蹾躀躂躃躄躆躈",6,"躑躒躓躕",6,"躝躟",11,"躭躮躰躱躳",6,"躻",7],["dc80","軃",10,"軏",21,"堋堍埽埭堀堞堙塄堠塥塬墁墉墚墀馨鼙懿艹艽艿芏芊芨芄芎芑芗芙芫芸芾芰苈苊苣芘芷芮苋苌苁芩芴芡芪芟苄苎芤苡茉苷苤茏茇苜苴苒苘茌苻苓茑茚茆茔茕苠苕茜荑荛荜茈莒茼茴茱莛荞茯荏荇荃荟荀茗荠茭茺茳荦荥"],["dd40","軥",62],["dd80","輤",32,"荨茛荩荬荪荭荮莰荸莳莴莠莪莓莜莅荼莶莩荽莸荻莘莞莨莺莼菁萁菥菘堇萘萋菝菽菖萜萸萑萆菔菟萏萃菸菹菪菅菀萦菰菡葜葑葚葙葳蒇蒈葺蒉葸萼葆葩葶蒌蒎萱葭蓁蓍蓐蓦蒽蓓蓊蒿蒺蓠蒡蒹蒴蒗蓥蓣蔌甍蔸蓰蔹蔟蔺"],["de40","轅",32,"轪辀辌辒辝辠辡辢辤辥辦辧辪辬辭辮辯農辳辴辵辷辸辺辻込辿迀迃迆"],["de80","迉",4,"迏迒迖迗迚迠迡迣迧迬迯迱迲迴迵迶迺迻迼迾迿逇逈逌逎逓逕逘蕖蔻蓿蓼蕙蕈蕨蕤蕞蕺瞢蕃蕲蕻薤薨薇薏蕹薮薜薅薹薷薰藓藁藜藿蘧蘅蘩蘖蘼廾弈夼奁耷奕奚奘匏尢尥尬尴扌扪抟抻拊拚拗拮挢拶挹捋捃掭揶捱捺掎掴捭掬掊捩掮掼揲揸揠揿揄揞揎摒揆掾摅摁搋搛搠搌搦搡摞撄摭撖"],["df40","這逜連逤逥逧",5,"逰",4,"逷逹逺逽逿遀遃遅遆遈",4,"過達違遖遙遚遜",5,"遤遦遧適遪遫遬遯",4,"遶",6,"遾邁"],["df80","還邅邆邇邉邊邌",4,"邒邔邖邘邚邜邞邟邠邤邥邧邨邩邫邭邲邷邼邽邿郀摺撷撸撙撺擀擐擗擤擢攉攥攮弋忒甙弑卟叱叽叩叨叻吒吖吆呋呒呓呔呖呃吡呗呙吣吲咂咔呷呱呤咚咛咄呶呦咝哐咭哂咴哒咧咦哓哔呲咣哕咻咿哌哙哚哜咩咪咤哝哏哞唛哧唠哽唔哳唢唣唏唑唧唪啧喏喵啉啭啁啕唿啐唼"],["e040","郂郃郆郈郉郋郌郍郒郔郕郖郘郙郚郞郟郠郣郤郥郩郪郬郮郰郱郲郳郵郶郷郹郺郻郼郿鄀鄁鄃鄅",19,"鄚鄛鄜"],["e080","鄝鄟鄠鄡鄤",10,"鄰鄲",6,"鄺",8,"酄唷啖啵啶啷唳唰啜喋嗒喃喱喹喈喁喟啾嗖喑啻嗟喽喾喔喙嗪嗷嗉嘟嗑嗫嗬嗔嗦嗝嗄嗯嗥嗲嗳嗌嗍嗨嗵嗤辔嘞嘈嘌嘁嘤嘣嗾嘀嘧嘭噘嘹噗嘬噍噢噙噜噌噔嚆噤噱噫噻噼嚅嚓嚯囔囗囝囡囵囫囹囿圄圊圉圜帏帙帔帑帱帻帼"],["e140","酅酇酈酑酓酔酕酖酘酙酛酜酟酠酦酧酨酫酭酳酺酻酼醀",4,"醆醈醊醎醏醓",6,"醜",5,"醤",5,"醫醬醰醱醲醳醶醷醸醹醻"],["e180","醼",10,"釈釋釐釒",9,"針",8,"帷幄幔幛幞幡岌屺岍岐岖岈岘岙岑岚岜岵岢岽岬岫岱岣峁岷峄峒峤峋峥崂崃崧崦崮崤崞崆崛嵘崾崴崽嵬嵛嵯嵝嵫嵋嵊嵩嵴嶂嶙嶝豳嶷巅彳彷徂徇徉後徕徙徜徨徭徵徼衢彡犭犰犴犷犸狃狁狎狍狒狨狯狩狲狴狷猁狳猃狺"],["e240","釦",62],["e280","鈥",32,"狻猗猓猡猊猞猝猕猢猹猥猬猸猱獐獍獗獠獬獯獾舛夥飧夤夂饣饧",5,"饴饷饽馀馄馇馊馍馐馑馓馔馕庀庑庋庖庥庠庹庵庾庳赓廒廑廛廨廪膺忄忉忖忏怃忮怄忡忤忾怅怆忪忭忸怙怵怦怛怏怍怩怫怊怿怡恸恹恻恺恂"],["e340","鉆",45,"鉵",16],["e380","銆",7,"銏",24,"恪恽悖悚悭悝悃悒悌悛惬悻悱惝惘惆惚悴愠愦愕愣惴愀愎愫慊慵憬憔憧憷懔懵忝隳闩闫闱闳闵闶闼闾阃阄阆阈阊阋阌阍阏阒阕阖阗阙阚丬爿戕氵汔汜汊沣沅沐沔沌汨汩汴汶沆沩泐泔沭泷泸泱泗沲泠泖泺泫泮沱泓泯泾"],["e440","銨",5,"銯",24,"鋉",31],["e480","鋩",32,"洹洧洌浃浈洇洄洙洎洫浍洮洵洚浏浒浔洳涑浯涞涠浞涓涔浜浠浼浣渚淇淅淞渎涿淠渑淦淝淙渖涫渌涮渫湮湎湫溲湟溆湓湔渲渥湄滟溱溘滠漭滢溥溧溽溻溷滗溴滏溏滂溟潢潆潇漤漕滹漯漶潋潴漪漉漩澉澍澌潸潲潼潺濑"],["e540","錊",51,"錿",10],["e580","鍊",31,"鍫濉澧澹澶濂濡濮濞濠濯瀚瀣瀛瀹瀵灏灞宀宄宕宓宥宸甯骞搴寤寮褰寰蹇謇辶迓迕迥迮迤迩迦迳迨逅逄逋逦逑逍逖逡逵逶逭逯遄遑遒遐遨遘遢遛暹遴遽邂邈邃邋彐彗彖彘尻咫屐屙孱屣屦羼弪弩弭艴弼鬻屮妁妃妍妩妪妣"],["e640","鍬",34,"鎐",27],["e680","鎬",29,"鏋鏌鏍妗姊妫妞妤姒妲妯姗妾娅娆姝娈姣姘姹娌娉娲娴娑娣娓婀婧婊婕娼婢婵胬媪媛婷婺媾嫫媲嫒嫔媸嫠嫣嫱嫖嫦嫘嫜嬉嬗嬖嬲嬷孀尕尜孚孥孳孑孓孢驵驷驸驺驿驽骀骁骅骈骊骐骒骓骖骘骛骜骝骟骠骢骣骥骧纟纡纣纥纨纩"],["e740","鏎",7,"鏗",54],["e780","鐎",32,"纭纰纾绀绁绂绉绋绌绐绔绗绛绠绡绨绫绮绯绱绲缍绶绺绻绾缁缂缃缇缈缋缌缏缑缒缗缙缜缛缟缡",6,"缪缫缬缭缯",4,"缵幺畿巛甾邕玎玑玮玢玟珏珂珑玷玳珀珉珈珥珙顼琊珩珧珞玺珲琏琪瑛琦琥琨琰琮琬"],["e840","鐯",14,"鐿",43,"鑬鑭鑮鑯"],["e880","鑰",20,"钑钖钘铇铏铓铔铚铦铻锜锠琛琚瑁瑜瑗瑕瑙瑷瑭瑾璜璎璀璁璇璋璞璨璩璐璧瓒璺韪韫韬杌杓杞杈杩枥枇杪杳枘枧杵枨枞枭枋杷杼柰栉柘栊柩枰栌柙枵柚枳柝栀柃枸柢栎柁柽栲栳桠桡桎桢桄桤梃栝桕桦桁桧桀栾桊桉栩梵梏桴桷梓桫棂楮棼椟椠棹"],["e940","锧锳锽镃镈镋镕镚镠镮镴镵長",7,"門",42],["e980","閫",32,"椤棰椋椁楗棣椐楱椹楠楂楝榄楫榀榘楸椴槌榇榈槎榉楦楣楹榛榧榻榫榭槔榱槁槊槟榕槠榍槿樯槭樗樘橥槲橄樾檠橐橛樵檎橹樽樨橘橼檑檐檩檗檫猷獒殁殂殇殄殒殓殍殚殛殡殪轫轭轱轲轳轵轶轸轷轹轺轼轾辁辂辄辇辋"],["ea40","闌",27,"闬闿阇阓阘阛阞阠阣",6,"阫阬阭阯阰阷阸阹阺阾陁陃陊陎陏陑陒陓陖陗"],["ea80","陘陙陚陜陝陞陠陣陥陦陫陭",4,"陳陸",12,"隇隉隊辍辎辏辘辚軎戋戗戛戟戢戡戥戤戬臧瓯瓴瓿甏甑甓攴旮旯旰昊昙杲昃昕昀炅曷昝昴昱昶昵耆晟晔晁晏晖晡晗晷暄暌暧暝暾曛曜曦曩贲贳贶贻贽赀赅赆赈赉赇赍赕赙觇觊觋觌觎觏觐觑牮犟牝牦牯牾牿犄犋犍犏犒挈挲掰"],["eb40","隌階隑隒隓隕隖隚際隝",9,"隨",7,"隱隲隴隵隷隸隺隻隿雂雃雈雊雋雐雑雓雔雖",9,"雡",6,"雫"],["eb80","雬雭雮雰雱雲雴雵雸雺電雼雽雿霂霃霅霊霋霌霐霑霒霔霕霗",4,"霝霟霠搿擘耄毪毳毽毵毹氅氇氆氍氕氘氙氚氡氩氤氪氲攵敕敫牍牒牖爰虢刖肟肜肓肼朊肽肱肫肭肴肷胧胨胩胪胛胂胄胙胍胗朐胝胫胱胴胭脍脎胲胼朕脒豚脶脞脬脘脲腈腌腓腴腙腚腱腠腩腼腽腭腧塍媵膈膂膑滕膣膪臌朦臊膻"],["ec40","霡",8,"霫霬霮霯霱霳",4,"霺霻霼霽霿",18,"靔靕靗靘靚靜靝靟靣靤靦靧靨靪",7],["ec80","靲靵靷",4,"靽",7,"鞆",4,"鞌鞎鞏鞐鞓鞕鞖鞗鞙",4,"臁膦欤欷欹歃歆歙飑飒飓飕飙飚殳彀毂觳斐齑斓於旆旄旃旌旎旒旖炀炜炖炝炻烀炷炫炱烨烊焐焓焖焯焱煳煜煨煅煲煊煸煺熘熳熵熨熠燠燔燧燹爝爨灬焘煦熹戾戽扃扈扉礻祀祆祉祛祜祓祚祢祗祠祯祧祺禅禊禚禧禳忑忐"],["ed40","鞞鞟鞡鞢鞤",6,"鞬鞮鞰鞱鞳鞵",46],["ed80","韤韥韨韮",4,"韴韷",23,"怼恝恚恧恁恙恣悫愆愍慝憩憝懋懑戆肀聿沓泶淼矶矸砀砉砗砘砑斫砭砜砝砹砺砻砟砼砥砬砣砩硎硭硖硗砦硐硇硌硪碛碓碚碇碜碡碣碲碹碥磔磙磉磬磲礅磴礓礤礞礴龛黹黻黼盱眄眍盹眇眈眚眢眙眭眦眵眸睐睑睇睃睚睨"],["ee40","頏",62],["ee80","顎",32,"睢睥睿瞍睽瞀瞌瞑瞟瞠瞰瞵瞽町畀畎畋畈畛畲畹疃罘罡罟詈罨罴罱罹羁罾盍盥蠲钅钆钇钋钊钌钍钏钐钔钗钕钚钛钜钣钤钫钪钭钬钯钰钲钴钶",4,"钼钽钿铄铈",6,"铐铑铒铕铖铗铙铘铛铞铟铠铢铤铥铧铨铪"],["ef40","顯",5,"颋颎颒颕颙颣風",37,"飏飐飔飖飗飛飜飝飠",4],["ef80","飥飦飩",30,"铩铫铮铯铳铴铵铷铹铼铽铿锃锂锆锇锉锊锍锎锏锒",4,"锘锛锝锞锟锢锪锫锩锬锱锲锴锶锷锸锼锾锿镂锵镄镅镆镉镌镎镏镒镓镔镖镗镘镙镛镞镟镝镡镢镤",8,"镯镱镲镳锺矧矬雉秕秭秣秫稆嵇稃稂稞稔"],["f040","餈",4,"餎餏餑",28,"餯",26],["f080","饊",9,"饖",12,"饤饦饳饸饹饻饾馂馃馉稹稷穑黏馥穰皈皎皓皙皤瓞瓠甬鸠鸢鸨",4,"鸲鸱鸶鸸鸷鸹鸺鸾鹁鹂鹄鹆鹇鹈鹉鹋鹌鹎鹑鹕鹗鹚鹛鹜鹞鹣鹦",6,"鹱鹭鹳疒疔疖疠疝疬疣疳疴疸痄疱疰痃痂痖痍痣痨痦痤痫痧瘃痱痼痿瘐瘀瘅瘌瘗瘊瘥瘘瘕瘙"],["f140","馌馎馚",10,"馦馧馩",47],["f180","駙",32,"瘛瘼瘢瘠癀瘭瘰瘿瘵癃瘾瘳癍癞癔癜癖癫癯翊竦穸穹窀窆窈窕窦窠窬窨窭窳衤衩衲衽衿袂袢裆袷袼裉裢裎裣裥裱褚裼裨裾裰褡褙褓褛褊褴褫褶襁襦襻疋胥皲皴矜耒耔耖耜耠耢耥耦耧耩耨耱耋耵聃聆聍聒聩聱覃顸颀颃"],["f240","駺",62],["f280","騹",32,"颉颌颍颏颔颚颛颞颟颡颢颥颦虍虔虬虮虿虺虼虻蚨蚍蚋蚬蚝蚧蚣蚪蚓蚩蚶蛄蚵蛎蚰蚺蚱蚯蛉蛏蚴蛩蛱蛲蛭蛳蛐蜓蛞蛴蛟蛘蛑蜃蜇蛸蜈蜊蜍蜉蜣蜻蜞蜥蜮蜚蜾蝈蜴蜱蜩蜷蜿螂蜢蝽蝾蝻蝠蝰蝌蝮螋蝓蝣蝼蝤蝙蝥螓螯螨蟒"],["f340","驚",17,"驲骃骉骍骎骔骕骙骦骩",6,"骲骳骴骵骹骻骽骾骿髃髄髆",4,"髍髎髏髐髒體髕髖髗髙髚髛髜"],["f380","髝髞髠髢髣髤髥髧髨髩髪髬髮髰",8,"髺髼",6,"鬄鬅鬆蟆螈螅螭螗螃螫蟥螬螵螳蟋蟓螽蟑蟀蟊蟛蟪蟠蟮蠖蠓蟾蠊蠛蠡蠹蠼缶罂罄罅舐竺竽笈笃笄笕笊笫笏筇笸笪笙笮笱笠笥笤笳笾笞筘筚筅筵筌筝筠筮筻筢筲筱箐箦箧箸箬箝箨箅箪箜箢箫箴篑篁篌篝篚篥篦篪簌篾篼簏簖簋"],["f440","鬇鬉",5,"鬐鬑鬒鬔",10,"鬠鬡鬢鬤",10,"鬰鬱鬳",7,"鬽鬾鬿魀魆魊魋魌魎魐魒魓魕",5],["f480","魛",32,"簟簪簦簸籁籀臾舁舂舄臬衄舡舢舣舭舯舨舫舸舻舳舴舾艄艉艋艏艚艟艨衾袅袈裘裟襞羝羟羧羯羰羲籼敉粑粝粜粞粢粲粼粽糁糇糌糍糈糅糗糨艮暨羿翎翕翥翡翦翩翮翳糸絷綦綮繇纛麸麴赳趄趔趑趱赧赭豇豉酊酐酎酏酤"],["f540","魼",62],["f580","鮻",32,"酢酡酰酩酯酽酾酲酴酹醌醅醐醍醑醢醣醪醭醮醯醵醴醺豕鹾趸跫踅蹙蹩趵趿趼趺跄跖跗跚跞跎跏跛跆跬跷跸跣跹跻跤踉跽踔踝踟踬踮踣踯踺蹀踹踵踽踱蹉蹁蹂蹑蹒蹊蹰蹶蹼蹯蹴躅躏躔躐躜躞豸貂貊貅貘貔斛觖觞觚觜"],["f640","鯜",62],["f680","鰛",32,"觥觫觯訾謦靓雩雳雯霆霁霈霏霎霪霭霰霾龀龃龅",5,"龌黾鼋鼍隹隼隽雎雒瞿雠銎銮鋈錾鍪鏊鎏鐾鑫鱿鲂鲅鲆鲇鲈稣鲋鲎鲐鲑鲒鲔鲕鲚鲛鲞",5,"鲥",4,"鲫鲭鲮鲰",7,"鲺鲻鲼鲽鳄鳅鳆鳇鳊鳋"],["f740","鰼",62],["f780","鱻鱽鱾鲀鲃鲄鲉鲊鲌鲏鲓鲖鲗鲘鲙鲝鲪鲬鲯鲹鲾",4,"鳈鳉鳑鳒鳚鳛鳠鳡鳌",4,"鳓鳔鳕鳗鳘鳙鳜鳝鳟鳢靼鞅鞑鞒鞔鞯鞫鞣鞲鞴骱骰骷鹘骶骺骼髁髀髅髂髋髌髑魅魃魇魉魈魍魑飨餍餮饕饔髟髡髦髯髫髻髭髹鬈鬏鬓鬟鬣麽麾縻麂麇麈麋麒鏖麝麟黛黜黝黠黟黢黩黧黥黪黯鼢鼬鼯鼹鼷鼽鼾齄"],["f840","鳣",62],["f880","鴢",32],["f940","鵃",62],["f980","鶂",32],["fa40","鶣",62],["fa80","鷢",32],["fb40","鸃",27,"鸤鸧鸮鸰鸴鸻鸼鹀鹍鹐鹒鹓鹔鹖鹙鹝鹟鹠鹡鹢鹥鹮鹯鹲鹴",9,"麀"],["fb80","麁麃麄麅麆麉麊麌",5,"麔",8,"麞麠",5,"麧麨麩麪"],["fc40","麫",8,"麵麶麷麹麺麼麿",4,"黅黆黇黈黊黋黌黐黒黓黕黖黗黙黚點黡黣黤黦黨黫黬黭黮黰",8,"黺黽黿",6],["fc80","鼆",4,"鼌鼏鼑鼒鼔鼕鼖鼘鼚",5,"鼡鼣",8,"鼭鼮鼰鼱"],["fd40","鼲",4,"鼸鼺鼼鼿",4,"齅",10,"齒",38],["fd80","齹",5,"龁龂龍",11,"龜龝龞龡",4,"郎凉秊裏隣"],["fe40","兀嗀﨎﨏﨑﨓﨔礼﨟蘒﨡﨣﨤﨧﨨﨩"]] - -/***/ }), -/* 54 */ -/***/ (function(module, exports, __webpack_require__) { - -// fallback for non-array-like ES3 and non-enumerable old V8 strings -var cof = __webpack_require__(55); -// eslint-disable-next-line no-prototype-builtins -module.exports = Object('z').propertyIsEnumerable(0) ? Object : function (it) { - return cof(it) == 'String' ? it.split('') : Object(it); -}; - - -/***/ }), -/* 55 */ -/***/ (function(module, exports) { - -var toString = {}.toString; - -module.exports = function (it) { - return toString.call(it).slice(8, -1); -}; - - -/***/ }), -/* 56 */ -/***/ (function(module, exports) { - -// 7.2.1 RequireObjectCoercible(argument) -module.exports = function (it) { - if (it == undefined) throw TypeError("Can't call method on " + it); - return it; -}; - - -/***/ }), -/* 57 */ -/***/ (function(module, exports, __webpack_require__) { - -var pIE = __webpack_require__(35); -var createDesc = __webpack_require__(27); -var toIObject = __webpack_require__(17); -var toPrimitive = __webpack_require__(58); -var has = __webpack_require__(18); -var IE8_DOM_DEFINE = __webpack_require__(95); -var gOPD = Object.getOwnPropertyDescriptor; - -exports.f = __webpack_require__(5) ? gOPD : function getOwnPropertyDescriptor(O, P) { - O = toIObject(O); - P = toPrimitive(P, true); - if (IE8_DOM_DEFINE) try { - return gOPD(O, P); - } catch (e) { /* empty */ } - if (has(O, P)) return createDesc(!pIE.f.call(O, P), O[P]); -}; - - -/***/ }), -/* 58 */ -/***/ (function(module, exports, __webpack_require__) { - -// 7.1.1 ToPrimitive(input [, PreferredType]) -var isObject = __webpack_require__(9); -// instead of the ES6 spec version, we didn't implement @@toPrimitive case -// and the second argument - flag - preferred type is a string -module.exports = function (it, S) { - if (!isObject(it)) return it; - var fn, val; - if (S && typeof (fn = it.toString) == 'function' && !isObject(val = fn.call(it))) return val; - if (typeof (fn = it.valueOf) == 'function' && !isObject(val = fn.call(it))) return val; - if (!S && typeof (fn = it.toString) == 'function' && !isObject(val = fn.call(it))) return val; - throw TypeError("Can't convert object to primitive value"); -}; - - -/***/ }), -/* 59 */ -/***/ (function(module, exports, __webpack_require__) { - -// most Object methods by ES6 should accept primitives -var $export = __webpack_require__(3); -var core = __webpack_require__(2); -var fails = __webpack_require__(19); -module.exports = function (KEY, exec) { - var fn = (core.Object || {})[KEY] || Object[KEY]; - var exp = {}; - exp[KEY] = exec(fn); - $export($export.S + $export.F * fails(function () { fn(1); }), 'Object', exp); -}; - - -/***/ }), -/* 60 */ -/***/ (function(module, exports, __webpack_require__) { - -module.exports = { "default": __webpack_require__(200), __esModule: true }; - -/***/ }), -/* 61 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var LIBRARY = __webpack_require__(62); -var $export = __webpack_require__(3); -var redefine = __webpack_require__(99); -var hide = __webpack_require__(13); -var has = __webpack_require__(18); -var Iterators = __webpack_require__(23); -var $iterCreate = __webpack_require__(203); -var setToStringTag = __webpack_require__(39); -var getPrototypeOf = __webpack_require__(206); -var ITERATOR = __webpack_require__(4)('iterator'); -var BUGGY = !([].keys && 'next' in [].keys()); // Safari has buggy iterators w/o `next` -var FF_ITERATOR = '@@iterator'; -var KEYS = 'keys'; -var VALUES = 'values'; - -var returnThis = function () { return this; }; - -module.exports = function (Base, NAME, Constructor, next, DEFAULT, IS_SET, FORCED) { - $iterCreate(Constructor, NAME, next); - var getMethod = function (kind) { - if (!BUGGY && kind in proto) return proto[kind]; - switch (kind) { - case KEYS: return function keys() { return new Constructor(this, kind); }; - case VALUES: return function values() { return new Constructor(this, kind); }; - } return function entries() { return new Constructor(this, kind); }; - }; - var TAG = NAME + ' Iterator'; - var DEF_VALUES = DEFAULT == VALUES; - var VALUES_BUG = false; - var proto = Base.prototype; - var $native = proto[ITERATOR] || proto[FF_ITERATOR] || DEFAULT && proto[DEFAULT]; - var $default = (!BUGGY && $native) || getMethod(DEFAULT); - var $entries = DEFAULT ? !DEF_VALUES ? $default : getMethod('entries') : undefined; - var $anyNative = NAME == 'Array' ? proto.entries || $native : $native; - var methods, key, IteratorPrototype; - // Fix native - if ($anyNative) { - IteratorPrototype = getPrototypeOf($anyNative.call(new Base())); - if (IteratorPrototype !== Object.prototype && IteratorPrototype.next) { - // Set @@toStringTag to native iterators - setToStringTag(IteratorPrototype, TAG, true); - // fix for some old engines - if (!LIBRARY && !has(IteratorPrototype, ITERATOR)) hide(IteratorPrototype, ITERATOR, returnThis); - } - } - // fix Array#{values, @@iterator}.name in V8 / FF - if (DEF_VALUES && $native && $native.name !== VALUES) { - VALUES_BUG = true; - $default = function values() { return $native.call(this); }; - } - // Define iterator - if ((!LIBRARY || FORCED) && (BUGGY || VALUES_BUG || !proto[ITERATOR])) { - hide(proto, ITERATOR, $default); - } - // Plug for library - Iterators[NAME] = $default; - Iterators[TAG] = returnThis; - if (DEFAULT) { - methods = { - values: DEF_VALUES ? $default : getMethod(VALUES), - keys: IS_SET ? $default : getMethod(KEYS), - entries: $entries - }; - if (FORCED) for (key in methods) { - if (!(key in proto)) redefine(proto, key, methods[key]); - } else $export($export.P + $export.F * (BUGGY || VALUES_BUG), NAME, methods); - } - return methods; -}; - - -/***/ }), -/* 62 */ -/***/ (function(module, exports) { - -module.exports = true; - - -/***/ }), -/* 63 */ -/***/ (function(module, exports) { - -// 7.1.4 ToInteger -var ceil = Math.ceil; -var floor = Math.floor; -module.exports = function (it) { - return isNaN(it = +it) ? 0 : (it > 0 ? floor : ceil)(it); -}; - - -/***/ }), -/* 64 */ -/***/ (function(module, exports, __webpack_require__) { - -var shared = __webpack_require__(65)('keys'); -var uid = __webpack_require__(38); -module.exports = function (key) { - return shared[key] || (shared[key] = uid(key)); -}; - - -/***/ }), -/* 65 */ -/***/ (function(module, exports, __webpack_require__) { - -var global = __webpack_require__(10); -var SHARED = '__core-js_shared__'; -var store = global[SHARED] || (global[SHARED] = {}); -module.exports = function (key) { - return store[key] || (store[key] = {}); -}; - - -/***/ }), -/* 66 */ -/***/ (function(module, exports) { - -// IE 8- don't enum bug keys -module.exports = ( - 'constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf' -).split(','); - - -/***/ }), -/* 67 */ -/***/ (function(module, exports, __webpack_require__) { - -var classof = __webpack_require__(68); -var ITERATOR = __webpack_require__(4)('iterator'); -var Iterators = __webpack_require__(23); -module.exports = __webpack_require__(2).getIteratorMethod = function (it) { - if (it != undefined) return it[ITERATOR] - || it['@@iterator'] - || Iterators[classof(it)]; -}; - - -/***/ }), -/* 68 */ -/***/ (function(module, exports, __webpack_require__) { - -// getting tag from 19.1.3.6 Object.prototype.toString() -var cof = __webpack_require__(55); -var TAG = __webpack_require__(4)('toStringTag'); -// ES3 wrong here -var ARG = cof(function () { return arguments; }()) == 'Arguments'; - -// fallback for IE11 Script Access Denied error -var tryGet = function (it, key) { - try { - return it[key]; - } catch (e) { /* empty */ } -}; - -module.exports = function (it) { - var O, T, B; - return it === undefined ? 'Undefined' : it === null ? 'Null' - // @@toStringTag case - : typeof (T = tryGet(O = Object(it), TAG)) == 'string' ? T - // builtinTag case - : ARG ? cof(O) - // ES3 arguments fallback - : (B = cof(O)) == 'Object' && typeof O.callee == 'function' ? 'Arguments' : B; -}; - - -/***/ }), -/* 69 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -exports.__esModule = true; - -var _iterator = __webpack_require__(103); - -var _iterator2 = _interopRequireDefault(_iterator); - -var _symbol = __webpack_require__(216); - -var _symbol2 = _interopRequireDefault(_symbol); - -var _typeof = typeof _symbol2.default === "function" && typeof _iterator2.default === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof _symbol2.default === "function" && obj.constructor === _symbol2.default && obj !== _symbol2.default.prototype ? "symbol" : typeof obj; }; - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -exports.default = typeof _symbol2.default === "function" && _typeof(_iterator2.default) === "symbol" ? function (obj) { - return typeof obj === "undefined" ? "undefined" : _typeof(obj); -} : function (obj) { - return obj && typeof _symbol2.default === "function" && obj.constructor === _symbol2.default && obj !== _symbol2.default.prototype ? "symbol" : typeof obj === "undefined" ? "undefined" : _typeof(obj); -}; - -/***/ }), -/* 70 */ -/***/ (function(module, exports, __webpack_require__) { - -exports.f = __webpack_require__(4); - - -/***/ }), -/* 71 */ -/***/ (function(module, exports, __webpack_require__) { - -var global = __webpack_require__(10); -var core = __webpack_require__(2); -var LIBRARY = __webpack_require__(62); -var wksExt = __webpack_require__(70); -var defineProperty = __webpack_require__(6).f; -module.exports = function (name) { - var $Symbol = core.Symbol || (core.Symbol = LIBRARY ? {} : global.Symbol || {}); - if (name.charAt(0) != '_' && !(name in $Symbol)) defineProperty($Symbol, name, { value: wksExt.f(name) }); -}; - - -/***/ }), -/* 72 */ -/***/ (function(module, exports) { - -exports.f = Object.getOwnPropertySymbols; - - -/***/ }), -/* 73 */ -/***/ (function(module, exports) { - - - -/***/ }), -/* 74 */ -/***/ (function(module, exports, __webpack_require__) { - -module.exports = { "default": __webpack_require__(223), __esModule: true }; - -/***/ }), -/* 75 */ -/***/ (function(module, exports, __webpack_require__) { - -var isObject = __webpack_require__(9); -module.exports = function (it, TYPE) { - if (!isObject(it) || it._t !== TYPE) throw TypeError('Incompatible receiver, ' + TYPE + ' required!'); - return it; -}; - - -/***/ }), -/* 76 */ -/***/ (function(module, exports) { - -var toString = {}.toString; - -module.exports = Array.isArray || function (arr) { - return toString.call(arr) == '[object Array]'; -}; - - -/***/ }), -/* 77 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -function TraversalTracker() { - this.events = {}; -} - -TraversalTracker.prototype.startTracking = function (event, callback) { - var callbacks = this.events[event] || (this.events[event] = []); - - if (callbacks.indexOf(callback) < 0) { - callbacks.push(callback); - } -}; - -TraversalTracker.prototype.stopTracking = function (event, callback) { - var callbacks = this.events[event]; - - if (!callbacks) { - return; - } - - var index = callbacks.indexOf(callback); - if (index >= 0) { - callbacks.splice(index, 1); - } -}; - -TraversalTracker.prototype.emit = function (event) { - var args = Array.prototype.slice.call(arguments, 1); - var callbacks = this.events[event]; - - if (!callbacks) { - return; - } - - callbacks.forEach(function (callback) { - callback.apply(this, args); - }); -}; - -TraversalTracker.prototype.auto = function (event, callback, innerFunction) { - this.startTracking(event, callback); - innerFunction(); - this.stopTracking(event, callback); -}; - -module.exports = TraversalTracker; - - -/***/ }), -/* 78 */ -/***/ (function(module, exports, __webpack_require__) { - -// Generated by CoffeeScript 1.7.1 -(function() { - var AI, AL, BA, BK, CB, CI_BRK, CJ, CP_BRK, CR, DI_BRK, ID, IN_BRK, LF, LineBreaker, NL, NS, PR_BRK, SA, SG, SP, UnicodeTrie, WJ, XX, base64, characterClasses, classTrie, data, fs, pairTable, _ref, _ref1; - - UnicodeTrie = __webpack_require__(43); - - - - base64 = __webpack_require__(131); - - _ref = __webpack_require__(132), BK = _ref.BK, CR = _ref.CR, LF = _ref.LF, NL = _ref.NL, CB = _ref.CB, BA = _ref.BA, SP = _ref.SP, WJ = _ref.WJ, SP = _ref.SP, BK = _ref.BK, LF = _ref.LF, NL = _ref.NL, AI = _ref.AI, AL = _ref.AL, SA = _ref.SA, SG = _ref.SG, XX = _ref.XX, CJ = _ref.CJ, ID = _ref.ID, NS = _ref.NS, characterClasses = _ref.characterClasses; - - _ref1 = __webpack_require__(133), DI_BRK = _ref1.DI_BRK, IN_BRK = _ref1.IN_BRK, CI_BRK = _ref1.CI_BRK, CP_BRK = _ref1.CP_BRK, PR_BRK = _ref1.PR_BRK, pairTable = _ref1.pairTable; - - data = base64.toByteArray("AA4IAAAAAAAAAhqg5VV7NJtZvz7fTC8zU5deplUlMrQoWqmqahD5So0aipYWrUhVFSVBQ10iSTtUtW6nKDVF6k7d75eQfEUbFcQ9KiFS90tQEolcP23nrLPmO+esr/+f39rr/a293t/e7/P8nmfvlz0O6RvrBJADtbBNaD88IOKTOmOrCqhu9zE770vc1pBV/xL5dxj2V7Zj4FGSomFKStCWNlV7hG1VabZfZ1LaHbFrRwzzLjzPoi1UHDnlV/lWbhgIIJvLBp/pu7AHEdRnIY+ROdXxg4fNpMdTxVnnm08OjozejAVsBqwqz8kddGRlRxsd8c55dNZoPuex6a7Dt6L0NNb03sqgTlR2/OT7eTt0Y0WnpUXxLsp5SMANc4DsmX4zJUBQvznwexm9tsMH+C9uRYMPOd96ZHB29NZjCIM2nfO7tsmQveX3l2r7ft0N4/SRJ7kO6Y8ZCaeuUQ4gMTZ67cp7TgxvlNDsPgOBdZi2YTam5Q7m3+00l+XG7PrDe6YoPmHgK+yLih7fAR16ZFCeD9WvOVt+gfNW/KT5/M6rb/9KERt+N1lad5RneVjzxXHsLofuU+TvrEsr3+26sVz5WJh6L/svoPK3qepFH9bysDljWtD1F7KrxzW1i9r+e/NLxV/acts7zuo304J9+t3Pd6Y6u8f3EAqxNRgv5DZjaI3unyvkvHPya/v3mWVYOC38qBq11+yHZ2bAyP1HbkV92vdno7r2lxz9UwCdCJVfd14NLcpO2CadHS/XPJ9doXgz5vLv/1OBVS3gX0D9n6LiNIDfpilO9RsLgZ2W/wIy8W/Rh93jfoz4qmRV2xElv6p2lRXQdO6/Cv8f5nGn3u0wLXjhnvClabL1o+7yvIpvLfT/xsKG30y/sTvq30ia9Czxp9dr9v/e7Yn/O0QJXxxBOJmceP/DBFa1q1v6oudn/e6qc/37dUoNvnYL4plQ9OoneYOh/r8fOFm7yl7FETHY9dXd5K2n/qEc53dOEe1TTJcvCfp1dpTC334l0vyaFL6mttNEbFjzO+ZV2mLk0qc3BrxJ4d9gweMmjRorxb7vic0rSq6D4wzAyFWas1TqPE0sLI8XLAryC8tPChaN3ALEZSWmtB34SyZcxXYn/E4Tg0LeMIPhgPKD9zyHGMxxhxnDDih7eI86xECTM8zodUCdgffUmRh4rQ8zyA6ow/Aei+01a8OMfziQQ+GAEkhwN/cqUFYAVzA9ex4n6jgtsiMvXf5BtXxEU4hSphvx3v8+9au8eEekEEpkrkne/zB1M+HAPuXIz3paxKlfe8aDMfGWAX6Md6PuuAdKHFVH++Ed5LEji94Z5zeiJIxbmWeN7rr1/ZcaBl5/nimdHsHgIH/ssyLUXZ4fDQ46HnBb+hQqG8yNiKRrXL/b1IPYDUsu3dFKtRMcjqlRvONd4xBvOufx2cUHuk8pmG1D7PyOQmUmluisVFS9OWS8fPIe8LiCtjwJKnEC9hrS9uKmISI3Wa5+vdXUG9dtyfr7g/oJv2wbzeZU838G6mEvntUb3SVV/fBZ6H/sL+lElzeRrHy2Xbe7UWX1q5sgOQ81rv+2baej4fP4m5Mf/GkoxfDtT3++KP7do9Jn26aa6xAhCf5L9RZVfkWKCcjI1eYbm2plvTEqkDxKC402bGzXCYaGnuALHabBT1dFLuOSB7RorOPEhZah1NjZIgR/UFGfK3p1ElYnevOMBDLURdpIjrI+qZk4sffGbRFiXuEmdFjiAODlQCJvIaB1rW61Ljg3y4eS4LAcSgDxxZQs0DYa15wA032Z+lGUfpoyOrFo3mg1sRQtN/fHHCx3TrM8eTrldMbYisDLXbUDoXMLejSq0fUNuO1muX0gEa8vgyegkqiqqbC3W0S4cC9Kmt8MuS/hFO7Xei3f8rSvIjeveMM7kxjUixOrl6gJshe4JU7PhOHpfrRYvu7yoAZKa3Buyk2J+K5W+nNTz1nhJDhRUfDJLiUXxjxXCJeeaOe/r7HlBP/uURc/5efaZEPxr55Qj39rfTLkugUGyMrwo7HAglfEjDriehF1jXtwJkPoiYkYQ5aoXSA7qbCBGKq5hwtu2VkpI9xVDop/1xrC52eiIvCoPWx4lLl40jm9upvycVPfpaH9/o2D4xKXpeNjE2HPQRS+3RFaYTc4Txw7Dvq5X6JBRwzs9mvoB49BK6b+XgsZVJYiInTlSXZ+62FT18mkFVcPKCJsoF5ahb19WheZLUYsSwdrrVM3aQ2XE6SzU2xHDS6iWkodk5AF6F8WUNmmushi8aVpMPwiIfEiQWo3CApONDRjrhDiVnkaFsaP5rjIJkmsN6V26li5LNM3JxGSyKgomknTyyrhcnwv9Qcqaq5utAh44W30SWo8Q0XHKR0glPF4fWst1FUCnk2woFq3iy9fAbzcjJ8fvSjgKVOfn14RDqyQuIgaGJZuswTywdCFSa89SakMf6fe+9KaQMYQlKxiJBczuPSho4wmBjdA+ag6QUOr2GdpcbSl51Ay6khhBt5UXdrnxc7ZGMxCvz96A4oLocxh2+px+1zkyLacCGrxnPzTRSgrLKpStFpH5ppKWm7PgMKZtwgytKLOjbGCOQLTm+KOowqa1sdut9raj1CZFkZD0jbaKNLpJUarSH5Qknx1YiOxdA5L6d5sfI/unmkSF65Ic/AvtXt98Pnrdwl5vgppQ3dYzWFwknZsy6xh2llmLxpegF8ayLwniknlXRHiF4hzzrgB8jQ4wdIqcaHCEAxyJwCeGkXPBZYSrrGa4vMwZvNN9aK0F4JBOK9mQ8g8EjEbIQVwvfS2D8GuCYsdqwqSWbQrfWdTRUJMqmpnWPax4Z7E137I6brHbvjpPlfNZpF1d7PP7HB/MPHcHVKTMhLO4f3CZcaccZEOiS2DpKiQB5KXDJ+Ospcz4qTRCRxgrKEQIgUkKLTKKwskdx2DWo3bg3PEoB5h2nA24olwfKSR+QR6TAvEDi/0czhUT59RZmO1MGeKGeEfuOSPWfL+XKmhqpZmOVR9mJVNDPKOS49Lq+Um10YsBybzDMtemlPCOJEtE8zaXhsaqEs9bngSJGhlOTTMlCXly9Qv5cRN3PVLK7zoMptutf7ihutrQ/Xj7VqeCdUwleTTKklOI8Wep9h7fCY0kVtDtIWKnubWAvbNZtsRRqOYl802vebPEkZRSZc6wXOfPtpPtN5HI63EUFfsy7U/TLr8NkIzaY3vx4A28x765XZMzRZTpMk81YIMuwJ5+/zoCuZj1wGnaHObxa5rpKZj4WhT670maRw04w0e3cZW74Z0aZe2n05hjZaxm6urenz8Ef5O6Yu1J2aqYAlqsCXs5ZB5o1JJ5l3xkTVr8rJQ09NLsBqRRDT2IIjOPmcJa6xQ1R5yGP9jAsj23xYDTezdyqG8YWZ7vJBIWK56K+iDgcHimiQOTIasNSua1fOBxsKMMEKd15jxTl+3CyvGCR+UyRwuSI2XuwRIPoNNclPihfJhaq2mKkNijwYLY6feqohktukmI3KDvOpN7ItCqHHhNuKlxMfBAEO5LjW2RKh6lE5Hd1dtAOopac/Z4FdsNsjMhXz/ug8JGmbVJTA+VOBJXdrYyJcIn5+OEeoK8kWEWF+wdG8ZtZHKSquWDtDVyhFPkRVqguKFkLkKCz46hcU1SUY9oJ2Sk+dmq0kglqk4kqKT1CV9JDELPjK1WsWGkEXF87g9P98e5ff0mIupm/w6vc3kCeq04X5bgJQlcMFRjlFWmSk+kssXCAVikfeAlMuzpUvCSdXiG+dc6KrIiLxxhbEVuKf7vW7KmDQI95bZe3H9mN3/77F6fZ2Yx/F9yClllj8gXpLWLpd5+v90iOaFa9sd7Pvx0lNa1o1+bkiZ69wCiC2x9UIb6/boBCuNMB/HYR0RC6+FD9Oe5qrgQl6JbXtkaYn0wkdNhROLqyhv6cKvyMj1Fvs2o3OOKoMYTubGENLfY5F6H9d8wX1cnINsvz+wZFQu3zhWVlwJvwBEp69Dqu/ZnkBf3nIfbx4TK7zOVJH5sGJX+IMwkn1vVBn38GbpTg9bJnMcTOb5F6Ci5gOn9Fcy6Qzcu+FL6mYJJ+f2ZZJGda1VqruZ0JRXItp8X0aTjIcJgzdaXlha7q7kV4ebrMsunfsRyRa9qYuryBHA0hc1KVsKdE+oI0ljLmSAyMze8lWmc5/lQ18slyTVC/vADTc+SNM5++gztTBLz4m0aVUKcfgOEExuKVomJ7XQDZuziMDjG6JP9tgR7JXZTeo9RGetW/Xm9/TgPJpTgHACPOGvmy2mDm9fl09WeMm9sQUAXP3Su2uApeCwJVT5iWCXDgmcuTsFgU9Nm6/PusJzSbDQIMfl6INY/OAEvZRN54BSSXUClM51im6Wn9VhVamKJmzOaFJErgJcs0etFZ40LIF3EPkjFTjGmAhsd174NnOwJW8TdJ1Dja+E6Wa6FVS22Haj1DDA474EesoMP5nbspAPJLWJ8rYcP1DwCslhnn+gTFm+sS9wY+U6SogAa9tiwpoxuaFeqm2OK+uozR6SfiLCOPz36LiDlzXr6UWd7BpY6mlrNANkTOeme5EgnnAkQRTGo9T6iYxbUKfGJcI9B+ub2PcyUOgpwXbOf3bHFWtygD7FYbRhb+vkzi87dB0JeXl/vBpBUz93VtqZi7AL7C1VowTF+tGmyurw7DBcktc+UMY0E10Jw4URojf8NdaNpN6E1q4+Oz+4YePtMLy8FPRP"); - - classTrie = new UnicodeTrie(data); - - LineBreaker = (function() { - var Break, mapClass, mapFirst; - - function LineBreaker(string) { - this.string = string; - this.pos = 0; - this.lastPos = 0; - this.curClass = null; - this.nextClass = null; - } - - LineBreaker.prototype.nextCodePoint = function() { - var code, next; - code = this.string.charCodeAt(this.pos++); - next = this.string.charCodeAt(this.pos); - if ((0xd800 <= code && code <= 0xdbff) && (0xdc00 <= next && next <= 0xdfff)) { - this.pos++; - return ((code - 0xd800) * 0x400) + (next - 0xdc00) + 0x10000; - } - return code; - }; - - mapClass = function(c) { - switch (c) { - case AI: - return AL; - case SA: - case SG: - case XX: - return AL; - case CJ: - return NS; - default: - return c; - } - }; - - mapFirst = function(c) { - switch (c) { - case LF: - case NL: - return BK; - case CB: - return BA; - case SP: - return WJ; - default: - return c; - } - }; - - LineBreaker.prototype.nextCharClass = function(first) { - if (first == null) { - first = false; - } - return mapClass(classTrie.get(this.nextCodePoint())); - }; - - Break = (function() { - function Break(position, required) { - this.position = position; - this.required = required != null ? required : false; - } - - return Break; - - })(); - - LineBreaker.prototype.nextBreak = function() { - var cur, lastClass, shouldBreak; - if (this.curClass == null) { - this.curClass = mapFirst(this.nextCharClass()); - } - while (this.pos < this.string.length) { - this.lastPos = this.pos; - lastClass = this.nextClass; - this.nextClass = this.nextCharClass(); - if (this.curClass === BK || (this.curClass === CR && this.nextClass !== LF)) { - this.curClass = mapFirst(mapClass(this.nextClass)); - return new Break(this.lastPos, true); - } - cur = (function() { - switch (this.nextClass) { - case SP: - return this.curClass; - case BK: - case LF: - case NL: - return BK; - case CR: - return CR; - case CB: - return BA; - } - }).call(this); - if (cur != null) { - this.curClass = cur; - if (this.nextClass === CB) { - return new Break(this.lastPos); - } - continue; - } - shouldBreak = false; - switch (pairTable[this.curClass][this.nextClass]) { - case DI_BRK: - shouldBreak = true; - break; - case IN_BRK: - shouldBreak = lastClass === SP; - break; - case CI_BRK: - shouldBreak = lastClass === SP; - if (!shouldBreak) { - continue; - } - break; - case CP_BRK: - if (lastClass !== SP) { - continue; - } - } - this.curClass = this.nextClass; - if (shouldBreak) { - return new Break(this.lastPos); - } - } - if (this.pos >= this.string.length) { - if (this.lastPos < this.string.length) { - this.lastPos = this.string.length; - return new Break(this.string.length); - } else { - return null; - } - } - }; - - return LineBreaker; - - })(); - - module.exports = LineBreaker; - -}).call(this); - - -/***/ }), -/* 79 */ -/***/ (function(module, exports) { - -var TINF_OK = 0; -var TINF_DATA_ERROR = -3; - -function Tree() { - this.table = new Uint16Array(16); /* table of code length counts */ - this.trans = new Uint16Array(288); /* code -> symbol translation table */ -} - -function Data(source, dest) { - this.source = source; - this.sourceIndex = 0; - this.tag = 0; - this.bitcount = 0; - - this.dest = dest; - this.destLen = 0; - - this.ltree = new Tree(); /* dynamic length/symbol tree */ - this.dtree = new Tree(); /* dynamic distance tree */ -} - -/* --------------------------------------------------- * - * -- uninitialized global data (static structures) -- * - * --------------------------------------------------- */ - -var sltree = new Tree(); -var sdtree = new Tree(); - -/* extra bits and base tables for length codes */ -var length_bits = new Uint8Array(30); -var length_base = new Uint16Array(30); - -/* extra bits and base tables for distance codes */ -var dist_bits = new Uint8Array(30); -var dist_base = new Uint16Array(30); - -/* special ordering of code length codes */ -var clcidx = new Uint8Array([ - 16, 17, 18, 0, 8, 7, 9, 6, - 10, 5, 11, 4, 12, 3, 13, 2, - 14, 1, 15 -]); - -/* used by tinf_decode_trees, avoids allocations every call */ -var code_tree = new Tree(); -var lengths = new Uint8Array(288 + 32); - -/* ----------------------- * - * -- utility functions -- * - * ----------------------- */ - -/* build extra bits and base tables */ -function tinf_build_bits_base(bits, base, delta, first) { - var i, sum; - - /* build bits table */ - for (i = 0; i < delta; ++i) bits[i] = 0; - for (i = 0; i < 30 - delta; ++i) bits[i + delta] = i / delta | 0; - - /* build base table */ - for (sum = first, i = 0; i < 30; ++i) { - base[i] = sum; - sum += 1 << bits[i]; - } -} - -/* build the fixed huffman trees */ -function tinf_build_fixed_trees(lt, dt) { - var i; - - /* build fixed length tree */ - for (i = 0; i < 7; ++i) lt.table[i] = 0; - - lt.table[7] = 24; - lt.table[8] = 152; - lt.table[9] = 112; - - for (i = 0; i < 24; ++i) lt.trans[i] = 256 + i; - for (i = 0; i < 144; ++i) lt.trans[24 + i] = i; - for (i = 0; i < 8; ++i) lt.trans[24 + 144 + i] = 280 + i; - for (i = 0; i < 112; ++i) lt.trans[24 + 144 + 8 + i] = 144 + i; - - /* build fixed distance tree */ - for (i = 0; i < 5; ++i) dt.table[i] = 0; - - dt.table[5] = 32; - - for (i = 0; i < 32; ++i) dt.trans[i] = i; -} - -/* given an array of code lengths, build a tree */ -var offs = new Uint16Array(16); - -function tinf_build_tree(t, lengths, off, num) { - var i, sum; - - /* clear code length count table */ - for (i = 0; i < 16; ++i) t.table[i] = 0; - - /* scan symbol lengths, and sum code length counts */ - for (i = 0; i < num; ++i) t.table[lengths[off + i]]++; - - t.table[0] = 0; - - /* compute offset table for distribution sort */ - for (sum = 0, i = 0; i < 16; ++i) { - offs[i] = sum; - sum += t.table[i]; - } - - /* create code->symbol translation table (symbols sorted by code) */ - for (i = 0; i < num; ++i) { - if (lengths[off + i]) t.trans[offs[lengths[off + i]]++] = i; - } -} - -/* ---------------------- * - * -- decode functions -- * - * ---------------------- */ - -/* get one bit from source stream */ -function tinf_getbit(d) { - /* check if tag is empty */ - if (!d.bitcount--) { - /* load next tag */ - d.tag = d.source[d.sourceIndex++]; - d.bitcount = 7; - } - - /* shift bit out of tag */ - var bit = d.tag & 1; - d.tag >>>= 1; - - return bit; -} - -/* read a num bit value from a stream and add base */ -function tinf_read_bits(d, num, base) { - if (!num) - return base; - - while (d.bitcount < 24) { - d.tag |= d.source[d.sourceIndex++] << d.bitcount; - d.bitcount += 8; - } - - var val = d.tag & (0xffff >>> (16 - num)); - d.tag >>>= num; - d.bitcount -= num; - return val + base; -} - -/* given a data stream and a tree, decode a symbol */ -function tinf_decode_symbol(d, t) { - while (d.bitcount < 24) { - d.tag |= d.source[d.sourceIndex++] << d.bitcount; - d.bitcount += 8; - } - - var sum = 0, cur = 0, len = 0; - var tag = d.tag; - - /* get more bits while code value is above sum */ - do { - cur = 2 * cur + (tag & 1); - tag >>>= 1; - ++len; - - sum += t.table[len]; - cur -= t.table[len]; - } while (cur >= 0); - - d.tag = tag; - d.bitcount -= len; - - return t.trans[sum + cur]; -} - -/* given a data stream, decode dynamic trees from it */ -function tinf_decode_trees(d, lt, dt) { - var hlit, hdist, hclen; - var i, num, length; - - /* get 5 bits HLIT (257-286) */ - hlit = tinf_read_bits(d, 5, 257); - - /* get 5 bits HDIST (1-32) */ - hdist = tinf_read_bits(d, 5, 1); - - /* get 4 bits HCLEN (4-19) */ - hclen = tinf_read_bits(d, 4, 4); - - for (i = 0; i < 19; ++i) lengths[i] = 0; - - /* read code lengths for code length alphabet */ - for (i = 0; i < hclen; ++i) { - /* get 3 bits code length (0-7) */ - var clen = tinf_read_bits(d, 3, 0); - lengths[clcidx[i]] = clen; - } - - /* build code length tree */ - tinf_build_tree(code_tree, lengths, 0, 19); - - /* decode code lengths for the dynamic trees */ - for (num = 0; num < hlit + hdist;) { - var sym = tinf_decode_symbol(d, code_tree); - - switch (sym) { - case 16: - /* copy previous code length 3-6 times (read 2 bits) */ - var prev = lengths[num - 1]; - for (length = tinf_read_bits(d, 2, 3); length; --length) { - lengths[num++] = prev; - } - break; - case 17: - /* repeat code length 0 for 3-10 times (read 3 bits) */ - for (length = tinf_read_bits(d, 3, 3); length; --length) { - lengths[num++] = 0; - } - break; - case 18: - /* repeat code length 0 for 11-138 times (read 7 bits) */ - for (length = tinf_read_bits(d, 7, 11); length; --length) { - lengths[num++] = 0; - } - break; - default: - /* values 0-15 represent the actual code lengths */ - lengths[num++] = sym; - break; - } - } - - /* build dynamic trees */ - tinf_build_tree(lt, lengths, 0, hlit); - tinf_build_tree(dt, lengths, hlit, hdist); -} - -/* ----------------------------- * - * -- block inflate functions -- * - * ----------------------------- */ - -/* given a stream and two trees, inflate a block of data */ -function tinf_inflate_block_data(d, lt, dt) { - while (1) { - var sym = tinf_decode_symbol(d, lt); - - /* check for end of block */ - if (sym === 256) { - return TINF_OK; - } - - if (sym < 256) { - d.dest[d.destLen++] = sym; - } else { - var length, dist, offs; - var i; - - sym -= 257; - - /* possibly get more bits from length code */ - length = tinf_read_bits(d, length_bits[sym], length_base[sym]); - - dist = tinf_decode_symbol(d, dt); - - /* possibly get more bits from distance code */ - offs = d.destLen - tinf_read_bits(d, dist_bits[dist], dist_base[dist]); - - /* copy match */ - for (i = offs; i < offs + length; ++i) { - d.dest[d.destLen++] = d.dest[i]; - } - } - } -} - -/* inflate an uncompressed block of data */ -function tinf_inflate_uncompressed_block(d) { - var length, invlength; - var i; - - /* unread from bitbuffer */ - while (d.bitcount > 8) { - d.sourceIndex--; - d.bitcount -= 8; - } - - /* get length */ - length = d.source[d.sourceIndex + 1]; - length = 256 * length + d.source[d.sourceIndex]; - - /* get one's complement of length */ - invlength = d.source[d.sourceIndex + 3]; - invlength = 256 * invlength + d.source[d.sourceIndex + 2]; - - /* check length */ - if (length !== (~invlength & 0x0000ffff)) - return TINF_DATA_ERROR; - - d.sourceIndex += 4; - - /* copy block */ - for (i = length; i; --i) - d.dest[d.destLen++] = d.source[d.sourceIndex++]; - - /* make sure we start next block on a byte boundary */ - d.bitcount = 0; - - return TINF_OK; -} - -/* inflate stream from source to dest */ -function tinf_uncompress(source, dest) { - var d = new Data(source, dest); - var bfinal, btype, res; - - do { - /* read final block flag */ - bfinal = tinf_getbit(d); - - /* read block type (2 bits) */ - btype = tinf_read_bits(d, 2, 0); - - /* decompress block */ - switch (btype) { - case 0: - /* decompress uncompressed block */ - res = tinf_inflate_uncompressed_block(d); - break; - case 1: - /* decompress block with fixed huffman trees */ - res = tinf_inflate_block_data(d, sltree, sdtree); - break; - case 2: - /* decompress block with dynamic huffman trees */ - tinf_decode_trees(d, d.ltree, d.dtree); - res = tinf_inflate_block_data(d, d.ltree, d.dtree); - break; - default: - res = TINF_DATA_ERROR; - } - - if (res !== TINF_OK) - throw new Error('Data error'); - - } while (!bfinal); - - if (d.destLen < d.dest.length) { - if (typeof d.dest.slice === 'function') - return d.dest.slice(0, d.destLen); - else - return d.dest.subarray(0, d.destLen); - } - - return d.dest; -} - -/* -------------------- * - * -- initialization -- * - * -------------------- */ - -/* build fixed huffman trees */ -tinf_build_fixed_trees(sltree, sdtree); - -/* build extra bits and base tables */ -tinf_build_bits_base(length_bits, length_base, 4, 3); -tinf_build_bits_base(dist_bits, dist_base, 2, 1); - -/* fix a special case */ -length_bits[28] = 0; -length_base[28] = 258; - -module.exports = tinf_uncompress; - - -/***/ }), -/* 80 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var isString = __webpack_require__(0).isString; -var isArray = __webpack_require__(0).isArray; -var isUndefined = __webpack_require__(0).isUndefined; -var isNull = __webpack_require__(0).isNull; - -/** - * Creates an instance of StyleContextStack used for style inheritance and style overrides - * - * @constructor - * @this {StyleContextStack} - * @param {Object} named styles dictionary - * @param {Object} optional default style definition - */ -function StyleContextStack(styleDictionary, defaultStyle) { - this.defaultStyle = defaultStyle || {}; - this.styleDictionary = styleDictionary; - this.styleOverrides = []; -} - -/** - * Creates cloned version of current stack - * @return {StyleContextStack} current stack snapshot - */ -StyleContextStack.prototype.clone = function () { - var stack = new StyleContextStack(this.styleDictionary, this.defaultStyle); - - this.styleOverrides.forEach(function (item) { - stack.styleOverrides.push(item); - }); - - return stack; -}; - -/** - * Pushes style-name or style-overrides-object onto the stack for future evaluation - * - * @param {String|Object} styleNameOrOverride style-name (referring to styleDictionary) or - * a new dictionary defining overriding properties - */ -StyleContextStack.prototype.push = function (styleNameOrOverride) { - this.styleOverrides.push(styleNameOrOverride); -}; - -/** - * Removes last style-name or style-overrides-object from the stack - * - * @param {Number} howMany - optional number of elements to be popped (if not specified, - * one element will be removed from the stack) - */ -StyleContextStack.prototype.pop = function (howMany) { - howMany = howMany || 1; - - while (howMany-- > 0) { - this.styleOverrides.pop(); - } -}; - -/** - * Creates a set of named styles or/and a style-overrides-object based on the item, - * pushes those elements onto the stack for future evaluation and returns the number - * of elements pushed, so they can be easily poped then. - * - * @param {Object} item - an object with optional style property and/or style overrides - * @return the number of items pushed onto the stack - */ -StyleContextStack.prototype.autopush = function (item) { - if (isString(item)) { - return 0; - } - - var styleNames = []; - - if (item.style) { - if (isArray(item.style)) { - styleNames = item.style; - } else { - styleNames = [item.style]; - } - } - - for (var i = 0, l = styleNames.length; i < l; i++) { - this.push(styleNames[i]); - } - - var styleProperties = [ - 'font', - 'fontSize', - 'fontFeatures', - 'bold', - 'italics', - 'alignment', - 'color', - 'columnGap', - 'fillColor', - 'decoration', - 'decorationStyle', - 'decorationColor', - 'background', - 'lineHeight', - 'characterSpacing', - 'noWrap', - 'markerColor', - 'leadingIndent' - //'tableCellPadding' - // 'cellBorder', - // 'headerCellBorder', - // 'oddRowCellBorder', - // 'evenRowCellBorder', - // 'tableBorder' - ]; - var styleOverrideObject = {}; - var pushStyleOverrideObject = false; - - styleProperties.forEach(function (key) { - if (!isUndefined(item[key]) && !isNull(item[key])) { - styleOverrideObject[key] = item[key]; - pushStyleOverrideObject = true; - } - }); - - if (pushStyleOverrideObject) { - this.push(styleOverrideObject); - } - - return styleNames.length + (pushStyleOverrideObject ? 1 : 0); -}; - -/** - * Automatically pushes elements onto the stack, using autopush based on item, - * executes callback and then pops elements back. Returns value returned by callback - * - * @param {Object} item - an object with optional style property and/or style overrides - * @param {Function} function to be called between autopush and pop - * @return {Object} value returned by callback - */ -StyleContextStack.prototype.auto = function (item, callback) { - var pushedItems = this.autopush(item); - var result = callback(); - - if (pushedItems > 0) { - this.pop(pushedItems); - } - - return result; -}; - -/** - * Evaluates stack and returns value of a named property - * - * @param {String} property - property name - * @return property value or null if not found - */ -StyleContextStack.prototype.getProperty = function (property) { - if (this.styleOverrides) { - for (var i = this.styleOverrides.length - 1; i >= 0; i--) { - var item = this.styleOverrides[i]; - - if (isString(item)) { - // named-style-override - var style = this.styleDictionary[item]; - if (style && !isUndefined(style[property]) && !isNull(style[property])) { - return style[property]; - } - } else if (!isUndefined(item[property]) && !isNull(item[property])) { - // style-overrides-object - return item[property]; - } - } - } - - return this.defaultStyle && this.defaultStyle[property]; -}; - -module.exports = StyleContextStack; - - -/***/ }), -/* 81 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var TraversalTracker = __webpack_require__(77); -var isString = __webpack_require__(0).isString; - -/** - * Creates an instance of DocumentContext - a store for current x, y positions and available width/height. - * It facilitates column divisions and vertical sync - */ -function DocumentContext(pageSize, pageMargins) { - this.pages = []; - - this.pageMargins = pageMargins; - - this.x = pageMargins.left; - this.availableWidth = pageSize.width - pageMargins.left - pageMargins.right; - this.availableHeight = 0; - this.page = -1; - - this.snapshots = []; - - this.endingCell = null; - - this.tracker = new TraversalTracker(); - - this.addPage(pageSize); - - this.hasBackground = false; -} - -DocumentContext.prototype.beginColumnGroup = function () { - this.snapshots.push({ - x: this.x, - y: this.y, - availableHeight: this.availableHeight, - availableWidth: this.availableWidth, - page: this.page, - bottomMost: { - x: this.x, - y: this.y, - availableHeight: this.availableHeight, - availableWidth: this.availableWidth, - page: this.page - }, - endingCell: this.endingCell, - lastColumnWidth: this.lastColumnWidth - }); - - this.lastColumnWidth = 0; -}; - -DocumentContext.prototype.beginColumn = function (width, offset, endingCell) { - var saved = this.snapshots[this.snapshots.length - 1]; - - this.calculateBottomMost(saved); - - this.endingCell = endingCell; - this.page = saved.page; - this.x = this.x + this.lastColumnWidth + (offset || 0); - this.y = saved.y; - this.availableWidth = width; //saved.availableWidth - offset; - this.availableHeight = saved.availableHeight; - - this.lastColumnWidth = width; -}; - -DocumentContext.prototype.calculateBottomMost = function (destContext) { - if (this.endingCell) { - this.saveContextInEndingCell(this.endingCell); - this.endingCell = null; - } else { - destContext.bottomMost = bottomMostContext(this, destContext.bottomMost); - } -}; - -DocumentContext.prototype.markEnding = function (endingCell) { - this.page = endingCell._columnEndingContext.page; - this.x = endingCell._columnEndingContext.x; - this.y = endingCell._columnEndingContext.y; - this.availableWidth = endingCell._columnEndingContext.availableWidth; - this.availableHeight = endingCell._columnEndingContext.availableHeight; - this.lastColumnWidth = endingCell._columnEndingContext.lastColumnWidth; -}; - -DocumentContext.prototype.saveContextInEndingCell = function (endingCell) { - endingCell._columnEndingContext = { - page: this.page, - x: this.x, - y: this.y, - availableHeight: this.availableHeight, - availableWidth: this.availableWidth, - lastColumnWidth: this.lastColumnWidth - }; -}; - -DocumentContext.prototype.completeColumnGroup = function (height) { - var saved = this.snapshots.pop(); - - this.calculateBottomMost(saved); - - this.endingCell = null; - this.x = saved.x; - - var y = saved.bottomMost.y; - if (height) { - if (saved.page === saved.bottomMost.page) { - if ((saved.y + height) > y) { - y = saved.y + height; - } - } else { - y += height; - } - } - - this.y = y; - this.page = saved.bottomMost.page; - this.availableWidth = saved.availableWidth; - this.availableHeight = saved.bottomMost.availableHeight; - if (height) { - this.availableHeight -= (y - saved.bottomMost.y); - } - this.lastColumnWidth = saved.lastColumnWidth; -}; - -DocumentContext.prototype.addMargin = function (left, right) { - this.x += left; - this.availableWidth -= left + (right || 0); -}; - -DocumentContext.prototype.moveDown = function (offset) { - this.y += offset; - this.availableHeight -= offset; - - return this.availableHeight > 0; -}; - -DocumentContext.prototype.initializePage = function () { - this.y = this.pageMargins.top; - this.availableHeight = this.getCurrentPage().pageSize.height - this.pageMargins.top - this.pageMargins.bottom; - this.pageSnapshot().availableWidth = this.getCurrentPage().pageSize.width - this.pageMargins.left - this.pageMargins.right; -}; - -DocumentContext.prototype.pageSnapshot = function () { - if (this.snapshots[0]) { - return this.snapshots[0]; - } else { - return this; - } -}; - -DocumentContext.prototype.moveTo = function (x, y) { - if (x !== undefined && x !== null) { - this.x = x; - this.availableWidth = this.getCurrentPage().pageSize.width - this.x - this.pageMargins.right; - } - if (y !== undefined && y !== null) { - this.y = y; - this.availableHeight = this.getCurrentPage().pageSize.height - this.y - this.pageMargins.bottom; - } -}; - -DocumentContext.prototype.beginDetachedBlock = function () { - this.snapshots.push({ - x: this.x, - y: this.y, - availableHeight: this.availableHeight, - availableWidth: this.availableWidth, - page: this.page, - endingCell: this.endingCell, - lastColumnWidth: this.lastColumnWidth - }); -}; - -DocumentContext.prototype.endDetachedBlock = function () { - var saved = this.snapshots.pop(); - - this.x = saved.x; - this.y = saved.y; - this.availableWidth = saved.availableWidth; - this.availableHeight = saved.availableHeight; - this.page = saved.page; - this.endingCell = saved.endingCell; - this.lastColumnWidth = saved.lastColumnWidth; -}; - -function pageOrientation(pageOrientationString, currentPageOrientation) { - if (pageOrientationString === undefined) { - return currentPageOrientation; - } else if (isString(pageOrientationString) && (pageOrientationString.toLowerCase() === 'landscape')) { - return 'landscape'; - } else { - return 'portrait'; - } -} - -var getPageSize = function (currentPage, newPageOrientation) { - - newPageOrientation = pageOrientation(newPageOrientation, currentPage.pageSize.orientation); - - if (newPageOrientation !== currentPage.pageSize.orientation) { - return { - orientation: newPageOrientation, - width: currentPage.pageSize.height, - height: currentPage.pageSize.width - }; - } else { - return { - orientation: currentPage.pageSize.orientation, - width: currentPage.pageSize.width, - height: currentPage.pageSize.height - }; - } - -}; - - -DocumentContext.prototype.moveToNextPage = function (pageOrientation) { - var nextPageIndex = this.page + 1; - - var prevPage = this.page; - var prevY = this.y; - - var createNewPage = nextPageIndex >= this.pages.length; - if (createNewPage) { - var currentAvailableWidth = this.availableWidth; - var currentPageOrientation = this.getCurrentPage().pageSize.orientation; - - var pageSize = getPageSize(this.getCurrentPage(), pageOrientation); - this.addPage(pageSize); - - if (currentPageOrientation === pageSize.orientation) { - this.availableWidth = currentAvailableWidth; - } - } else { - this.page = nextPageIndex; - this.initializePage(); - } - - return { - newPageCreated: createNewPage, - prevPage: prevPage, - prevY: prevY, - y: this.y - }; -}; - - -DocumentContext.prototype.addPage = function (pageSize) { - var page = {items: [], pageSize: pageSize}; - this.pages.push(page); - this.page = this.pages.length - 1; - this.initializePage(); - - this.tracker.emit('pageAdded'); - - return page; -}; - -DocumentContext.prototype.getCurrentPage = function () { - if (this.page < 0 || this.page >= this.pages.length) { - return null; - } - - return this.pages[this.page]; -}; - -DocumentContext.prototype.getCurrentPosition = function () { - var pageSize = this.getCurrentPage().pageSize; - var innerHeight = pageSize.height - this.pageMargins.top - this.pageMargins.bottom; - var innerWidth = pageSize.width - this.pageMargins.left - this.pageMargins.right; - - return { - pageNumber: this.page + 1, - pageOrientation: pageSize.orientation, - pageInnerHeight: innerHeight, - pageInnerWidth: innerWidth, - left: this.x, - top: this.y, - verticalRatio: ((this.y - this.pageMargins.top) / innerHeight), - horizontalRatio: ((this.x - this.pageMargins.left) / innerWidth) - }; -}; - -function bottomMostContext(c1, c2) { - var r; - - if (c1.page > c2.page) { - r = c1; - } else if (c2.page > c1.page) { - r = c2; - } else { - r = (c1.y > c2.y) ? c1 : c2; - } - - return { - page: r.page, - x: r.x, - y: r.y, - availableHeight: r.availableHeight, - availableWidth: r.availableWidth - }; -} - -module.exports = DocumentContext; - - -/***/ }), -/* 82 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/** - * Creates an instance of Line - * - * @constructor - * @this {Line} - * @param {Number} Maximum width this line can have - */ -function Line(maxWidth) { - this.maxWidth = maxWidth; - this.leadingCut = 0; - this.trailingCut = 0; - this.inlineWidths = 0; - this.inlines = []; -} - -Line.prototype.getAscenderHeight = function () { - var y = 0; - - this.inlines.forEach(function (inline) { - y = Math.max(y, inline.font.ascender / 1000 * inline.fontSize); - }); - return y; -}; - -Line.prototype.hasEnoughSpaceForInline = function (inline) { - if (this.inlines.length === 0) { - return true; - } - if (this.newLineForced) { - return false; - } - - return this.inlineWidths + inline.width - this.leadingCut - (inline.trailingCut || 0) <= this.maxWidth; -}; - -Line.prototype.addInline = function (inline) { - if (this.inlines.length === 0) { - this.leadingCut = inline.leadingCut || 0; - } - this.trailingCut = inline.trailingCut || 0; - - inline.x = this.inlineWidths - this.leadingCut; - - this.inlines.push(inline); - this.inlineWidths += inline.width; - - if (inline.lineEnd) { - this.newLineForced = true; - } -}; - -Line.prototype.getWidth = function () { - return this.inlineWidths - this.leadingCut - this.trailingCut; -}; - -/** - * Returns line height - * @return {Number} - */ -Line.prototype.getHeight = function () { - var max = 0; - - this.inlines.forEach(function (item) { - max = Math.max(max, item.height || 0); - }); - - return max; -}; - -module.exports = Line; - - -/***/ }), -/* 83 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/* WEBPACK VAR INJECTION */(function(global, process) {// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - - - -/**/ - -var processNextTick = __webpack_require__(32).nextTick; -/**/ - -module.exports = Readable; - -/**/ -var isArray = __webpack_require__(76); -/**/ - -/**/ -var Duplex; -/**/ - -Readable.ReadableState = ReadableState; - -/**/ -var EE = __webpack_require__(31).EventEmitter; - -var EElistenerCount = function (emitter, type) { - return emitter.listeners(type).length; -}; -/**/ - -/**/ -var Stream = __webpack_require__(84); -/**/ - -/**/ - -var Buffer = __webpack_require__(33).Buffer; -var OurUint8Array = global.Uint8Array || function () {}; -function _uint8ArrayToBuffer(chunk) { - return Buffer.from(chunk); -} -function _isUint8Array(obj) { - return Buffer.isBuffer(obj) || obj instanceof OurUint8Array; -} - -/**/ - -/**/ -var util = __webpack_require__(25); -util.inherits = __webpack_require__(21); -/**/ - -/**/ -var debugUtil = __webpack_require__(139); -var debug = void 0; -if (debugUtil && debugUtil.debuglog) { - debug = debugUtil.debuglog('stream'); -} else { - debug = function () {}; -} -/**/ - -var BufferList = __webpack_require__(140); -var destroyImpl = __webpack_require__(85); -var StringDecoder; - -util.inherits(Readable, Stream); - -var kProxyEvents = ['error', 'close', 'destroy', 'pause', 'resume']; - -function prependListener(emitter, event, fn) { - // Sadly this is not cacheable as some libraries bundle their own - // event emitter implementation with them. - if (typeof emitter.prependListener === 'function') return emitter.prependListener(event, fn); - - // This is a hack to make sure that our error handler is attached before any - // userland ones. NEVER DO THIS. This is here only because this code needs - // to continue to work with older versions of Node.js that do not include - // the prependListener() method. The goal is to eventually remove this hack. - if (!emitter._events || !emitter._events[event]) emitter.on(event, fn);else if (isArray(emitter._events[event])) emitter._events[event].unshift(fn);else emitter._events[event] = [fn, emitter._events[event]]; -} - -function ReadableState(options, stream) { - Duplex = Duplex || __webpack_require__(16); - - options = options || {}; - - // Duplex streams are both readable and writable, but share - // the same options object. - // However, some cases require setting options to different - // values for the readable and the writable sides of the duplex stream. - // These options can be provided separately as readableXXX and writableXXX. - var isDuplex = stream instanceof Duplex; - - // object stream flag. Used to make read(n) ignore n and to - // make all the buffer merging and length checks go away - this.objectMode = !!options.objectMode; - - if (isDuplex) this.objectMode = this.objectMode || !!options.readableObjectMode; - - // the point at which it stops calling _read() to fill the buffer - // Note: 0 is a valid value, means "don't call _read preemptively ever" - var hwm = options.highWaterMark; - var readableHwm = options.readableHighWaterMark; - var defaultHwm = this.objectMode ? 16 : 16 * 1024; - - if (hwm || hwm === 0) this.highWaterMark = hwm;else if (isDuplex && (readableHwm || readableHwm === 0)) this.highWaterMark = readableHwm;else this.highWaterMark = defaultHwm; - - // cast to ints. - this.highWaterMark = Math.floor(this.highWaterMark); - - // A linked list is used to store data chunks instead of an array because the - // linked list can remove elements from the beginning faster than - // array.shift() - this.buffer = new BufferList(); - this.length = 0; - this.pipes = null; - this.pipesCount = 0; - this.flowing = null; - this.ended = false; - this.endEmitted = false; - this.reading = false; - - // a flag to be able to tell if the event 'readable'/'data' is emitted - // immediately, or on a later tick. We set this to true at first, because - // any actions that shouldn't happen until "later" should generally also - // not happen before the first read call. - this.sync = true; - - // whenever we return null, then we set a flag to say - // that we're awaiting a 'readable' event emission. - this.needReadable = false; - this.emittedReadable = false; - this.readableListening = false; - this.resumeScheduled = false; - - // has it been destroyed - this.destroyed = false; - - // Crypto is kind of old and crusty. Historically, its default string - // encoding is 'binary' so we have to make this configurable. - // Everything else in the universe uses 'utf8', though. - this.defaultEncoding = options.defaultEncoding || 'utf8'; - - // the number of writers that are awaiting a drain event in .pipe()s - this.awaitDrain = 0; - - // if true, a maybeReadMore has been scheduled - this.readingMore = false; - - this.decoder = null; - this.encoding = null; - if (options.encoding) { - if (!StringDecoder) StringDecoder = __webpack_require__(47).StringDecoder; - this.decoder = new StringDecoder(options.encoding); - this.encoding = options.encoding; - } -} - -function Readable(options) { - Duplex = Duplex || __webpack_require__(16); - - if (!(this instanceof Readable)) return new Readable(options); - - this._readableState = new ReadableState(options, this); - - // legacy - this.readable = true; - - if (options) { - if (typeof options.read === 'function') this._read = options.read; - - if (typeof options.destroy === 'function') this._destroy = options.destroy; - } - - Stream.call(this); -} - -Object.defineProperty(Readable.prototype, 'destroyed', { - get: function () { - if (this._readableState === undefined) { - return false; - } - return this._readableState.destroyed; - }, - set: function (value) { - // we ignore the value if the stream - // has not been initialized yet - if (!this._readableState) { - return; - } - - // backward compatibility, the user is explicitly - // managing destroyed - this._readableState.destroyed = value; - } -}); - -Readable.prototype.destroy = destroyImpl.destroy; -Readable.prototype._undestroy = destroyImpl.undestroy; -Readable.prototype._destroy = function (err, cb) { - this.push(null); - cb(err); -}; - -// Manually shove something into the read() buffer. -// This returns true if the highWaterMark has not been hit yet, -// similar to how Writable.write() returns true if you should -// write() some more. -Readable.prototype.push = function (chunk, encoding) { - var state = this._readableState; - var skipChunkCheck; - - if (!state.objectMode) { - if (typeof chunk === 'string') { - encoding = encoding || state.defaultEncoding; - if (encoding !== state.encoding) { - chunk = Buffer.from(chunk, encoding); - encoding = ''; - } - skipChunkCheck = true; - } - } else { - skipChunkCheck = true; - } - - return readableAddChunk(this, chunk, encoding, false, skipChunkCheck); -}; - -// Unshift should *always* be something directly out of read() -Readable.prototype.unshift = function (chunk) { - return readableAddChunk(this, chunk, null, true, false); -}; - -function readableAddChunk(stream, chunk, encoding, addToFront, skipChunkCheck) { - var state = stream._readableState; - if (chunk === null) { - state.reading = false; - onEofChunk(stream, state); - } else { - var er; - if (!skipChunkCheck) er = chunkInvalid(state, chunk); - if (er) { - stream.emit('error', er); - } else if (state.objectMode || chunk && chunk.length > 0) { - if (typeof chunk !== 'string' && !state.objectMode && Object.getPrototypeOf(chunk) !== Buffer.prototype) { - chunk = _uint8ArrayToBuffer(chunk); - } - - if (addToFront) { - if (state.endEmitted) stream.emit('error', new Error('stream.unshift() after end event'));else addChunk(stream, state, chunk, true); - } else if (state.ended) { - stream.emit('error', new Error('stream.push() after EOF')); - } else { - state.reading = false; - if (state.decoder && !encoding) { - chunk = state.decoder.write(chunk); - if (state.objectMode || chunk.length !== 0) addChunk(stream, state, chunk, false);else maybeReadMore(stream, state); - } else { - addChunk(stream, state, chunk, false); - } - } - } else if (!addToFront) { - state.reading = false; - } - } - - return needMoreData(state); -} - -function addChunk(stream, state, chunk, addToFront) { - if (state.flowing && state.length === 0 && !state.sync) { - stream.emit('data', chunk); - stream.read(0); - } else { - // update the buffer info. - state.length += state.objectMode ? 1 : chunk.length; - if (addToFront) state.buffer.unshift(chunk);else state.buffer.push(chunk); - - if (state.needReadable) emitReadable(stream); - } - maybeReadMore(stream, state); -} - -function chunkInvalid(state, chunk) { - var er; - if (!_isUint8Array(chunk) && typeof chunk !== 'string' && chunk !== undefined && !state.objectMode) { - er = new TypeError('Invalid non-string/buffer chunk'); - } - return er; -} - -// if it's past the high water mark, we can push in some more. -// Also, if we have no data yet, we can stand some -// more bytes. This is to work around cases where hwm=0, -// such as the repl. Also, if the push() triggered a -// readable event, and the user called read(largeNumber) such that -// needReadable was set, then we ought to push more, so that another -// 'readable' event will be triggered. -function needMoreData(state) { - return !state.ended && (state.needReadable || state.length < state.highWaterMark || state.length === 0); -} - -Readable.prototype.isPaused = function () { - return this._readableState.flowing === false; -}; - -// backwards compatibility. -Readable.prototype.setEncoding = function (enc) { - if (!StringDecoder) StringDecoder = __webpack_require__(47).StringDecoder; - this._readableState.decoder = new StringDecoder(enc); - this._readableState.encoding = enc; - return this; -}; - -// Don't raise the hwm > 8MB -var MAX_HWM = 0x800000; -function computeNewHighWaterMark(n) { - if (n >= MAX_HWM) { - n = MAX_HWM; - } else { - // Get the next highest power of 2 to prevent increasing hwm excessively in - // tiny amounts - n--; - n |= n >>> 1; - n |= n >>> 2; - n |= n >>> 4; - n |= n >>> 8; - n |= n >>> 16; - n++; - } - return n; -} - -// This function is designed to be inlinable, so please take care when making -// changes to the function body. -function howMuchToRead(n, state) { - if (n <= 0 || state.length === 0 && state.ended) return 0; - if (state.objectMode) return 1; - if (n !== n) { - // Only flow one buffer at a time - if (state.flowing && state.length) return state.buffer.head.data.length;else return state.length; - } - // If we're asking for more than the current hwm, then raise the hwm. - if (n > state.highWaterMark) state.highWaterMark = computeNewHighWaterMark(n); - if (n <= state.length) return n; - // Don't have enough - if (!state.ended) { - state.needReadable = true; - return 0; - } - return state.length; -} - -// you can override either this method, or the async _read(n) below. -Readable.prototype.read = function (n) { - debug('read', n); - n = parseInt(n, 10); - var state = this._readableState; - var nOrig = n; - - if (n !== 0) state.emittedReadable = false; - - // if we're doing read(0) to trigger a readable event, but we - // already have a bunch of data in the buffer, then just trigger - // the 'readable' event and move on. - if (n === 0 && state.needReadable && (state.length >= state.highWaterMark || state.ended)) { - debug('read: emitReadable', state.length, state.ended); - if (state.length === 0 && state.ended) endReadable(this);else emitReadable(this); - return null; - } - - n = howMuchToRead(n, state); - - // if we've ended, and we're now clear, then finish it up. - if (n === 0 && state.ended) { - if (state.length === 0) endReadable(this); - return null; - } - - // All the actual chunk generation logic needs to be - // *below* the call to _read. The reason is that in certain - // synthetic stream cases, such as passthrough streams, _read - // may be a completely synchronous operation which may change - // the state of the read buffer, providing enough data when - // before there was *not* enough. - // - // So, the steps are: - // 1. Figure out what the state of things will be after we do - // a read from the buffer. - // - // 2. If that resulting state will trigger a _read, then call _read. - // Note that this may be asynchronous, or synchronous. Yes, it is - // deeply ugly to write APIs this way, but that still doesn't mean - // that the Readable class should behave improperly, as streams are - // designed to be sync/async agnostic. - // Take note if the _read call is sync or async (ie, if the read call - // has returned yet), so that we know whether or not it's safe to emit - // 'readable' etc. - // - // 3. Actually pull the requested chunks out of the buffer and return. - - // if we need a readable event, then we need to do some reading. - var doRead = state.needReadable; - debug('need readable', doRead); - - // if we currently have less than the highWaterMark, then also read some - if (state.length === 0 || state.length - n < state.highWaterMark) { - doRead = true; - debug('length less than watermark', doRead); - } - - // however, if we've ended, then there's no point, and if we're already - // reading, then it's unnecessary. - if (state.ended || state.reading) { - doRead = false; - debug('reading or ended', doRead); - } else if (doRead) { - debug('do read'); - state.reading = true; - state.sync = true; - // if the length is currently zero, then we *need* a readable event. - if (state.length === 0) state.needReadable = true; - // call internal read method - this._read(state.highWaterMark); - state.sync = false; - // If _read pushed data synchronously, then `reading` will be false, - // and we need to re-evaluate how much data we can return to the user. - if (!state.reading) n = howMuchToRead(nOrig, state); - } - - var ret; - if (n > 0) ret = fromList(n, state);else ret = null; - - if (ret === null) { - state.needReadable = true; - n = 0; - } else { - state.length -= n; - } - - if (state.length === 0) { - // If we have nothing in the buffer, then we want to know - // as soon as we *do* get something into the buffer. - if (!state.ended) state.needReadable = true; - - // If we tried to read() past the EOF, then emit end on the next tick. - if (nOrig !== n && state.ended) endReadable(this); - } - - if (ret !== null) this.emit('data', ret); - - return ret; -}; - -function onEofChunk(stream, state) { - if (state.ended) return; - if (state.decoder) { - var chunk = state.decoder.end(); - if (chunk && chunk.length) { - state.buffer.push(chunk); - state.length += state.objectMode ? 1 : chunk.length; - } - } - state.ended = true; - - // emit 'readable' now to make sure it gets picked up. - emitReadable(stream); -} - -// Don't emit readable right away in sync mode, because this can trigger -// another read() call => stack overflow. This way, it might trigger -// a nextTick recursion warning, but that's not so bad. -function emitReadable(stream) { - var state = stream._readableState; - state.needReadable = false; - if (!state.emittedReadable) { - debug('emitReadable', state.flowing); - state.emittedReadable = true; - if (state.sync) processNextTick(emitReadable_, stream);else emitReadable_(stream); - } -} - -function emitReadable_(stream) { - debug('emit readable'); - stream.emit('readable'); - flow(stream); -} - -// at this point, the user has presumably seen the 'readable' event, -// and called read() to consume some data. that may have triggered -// in turn another _read(n) call, in which case reading = true if -// it's in progress. -// However, if we're not ended, or reading, and the length < hwm, -// then go ahead and try to read some more preemptively. -function maybeReadMore(stream, state) { - if (!state.readingMore) { - state.readingMore = true; - processNextTick(maybeReadMore_, stream, state); - } -} - -function maybeReadMore_(stream, state) { - var len = state.length; - while (!state.reading && !state.flowing && !state.ended && state.length < state.highWaterMark) { - debug('maybeReadMore read 0'); - stream.read(0); - if (len === state.length) - // didn't get any data, stop spinning. - break;else len = state.length; - } - state.readingMore = false; -} - -// abstract method. to be overridden in specific implementation classes. -// call cb(er, data) where data is <= n in length. -// for virtual (non-string, non-buffer) streams, "length" is somewhat -// arbitrary, and perhaps not very meaningful. -Readable.prototype._read = function (n) { - this.emit('error', new Error('_read() is not implemented')); -}; - -Readable.prototype.pipe = function (dest, pipeOpts) { - var src = this; - var state = this._readableState; - - switch (state.pipesCount) { - case 0: - state.pipes = dest; - break; - case 1: - state.pipes = [state.pipes, dest]; - break; - default: - state.pipes.push(dest); - break; - } - state.pipesCount += 1; - debug('pipe count=%d opts=%j', state.pipesCount, pipeOpts); - - var doEnd = (!pipeOpts || pipeOpts.end !== false) && dest !== process.stdout && dest !== process.stderr; - - var endFn = doEnd ? onend : unpipe; - if (state.endEmitted) processNextTick(endFn);else src.once('end', endFn); - - dest.on('unpipe', onunpipe); - function onunpipe(readable, unpipeInfo) { - debug('onunpipe'); - if (readable === src) { - if (unpipeInfo && unpipeInfo.hasUnpiped === false) { - unpipeInfo.hasUnpiped = true; - cleanup(); - } - } - } - - function onend() { - debug('onend'); - dest.end(); - } - - // when the dest drains, it reduces the awaitDrain counter - // on the source. This would be more elegant with a .once() - // handler in flow(), but adding and removing repeatedly is - // too slow. - var ondrain = pipeOnDrain(src); - dest.on('drain', ondrain); - - var cleanedUp = false; - function cleanup() { - debug('cleanup'); - // cleanup event handlers once the pipe is broken - dest.removeListener('close', onclose); - dest.removeListener('finish', onfinish); - dest.removeListener('drain', ondrain); - dest.removeListener('error', onerror); - dest.removeListener('unpipe', onunpipe); - src.removeListener('end', onend); - src.removeListener('end', unpipe); - src.removeListener('data', ondata); - - cleanedUp = true; - - // if the reader is waiting for a drain event from this - // specific writer, then it would cause it to never start - // flowing again. - // So, if this is awaiting a drain, then we just call it now. - // If we don't know, then assume that we are waiting for one. - if (state.awaitDrain && (!dest._writableState || dest._writableState.needDrain)) ondrain(); - } - - // If the user pushes more data while we're writing to dest then we'll end up - // in ondata again. However, we only want to increase awaitDrain once because - // dest will only emit one 'drain' event for the multiple writes. - // => Introduce a guard on increasing awaitDrain. - var increasedAwaitDrain = false; - src.on('data', ondata); - function ondata(chunk) { - debug('ondata'); - increasedAwaitDrain = false; - var ret = dest.write(chunk); - if (false === ret && !increasedAwaitDrain) { - // If the user unpiped during `dest.write()`, it is possible - // to get stuck in a permanently paused state if that write - // also returned false. - // => Check whether `dest` is still a piping destination. - if ((state.pipesCount === 1 && state.pipes === dest || state.pipesCount > 1 && indexOf(state.pipes, dest) !== -1) && !cleanedUp) { - debug('false write response, pause', src._readableState.awaitDrain); - src._readableState.awaitDrain++; - increasedAwaitDrain = true; - } - src.pause(); - } - } - - // if the dest has an error, then stop piping into it. - // however, don't suppress the throwing behavior for this. - function onerror(er) { - debug('onerror', er); - unpipe(); - dest.removeListener('error', onerror); - if (EElistenerCount(dest, 'error') === 0) dest.emit('error', er); - } - - // Make sure our error handler is attached before userland ones. - prependListener(dest, 'error', onerror); - - // Both close and finish should trigger unpipe, but only once. - function onclose() { - dest.removeListener('finish', onfinish); - unpipe(); - } - dest.once('close', onclose); - function onfinish() { - debug('onfinish'); - dest.removeListener('close', onclose); - unpipe(); - } - dest.once('finish', onfinish); - - function unpipe() { - debug('unpipe'); - src.unpipe(dest); - } - - // tell the dest that it's being piped to - dest.emit('pipe', src); - - // start the flow if it hasn't been started already. - if (!state.flowing) { - debug('pipe resume'); - src.resume(); - } - - return dest; -}; - -function pipeOnDrain(src) { - return function () { - var state = src._readableState; - debug('pipeOnDrain', state.awaitDrain); - if (state.awaitDrain) state.awaitDrain--; - if (state.awaitDrain === 0 && EElistenerCount(src, 'data')) { - state.flowing = true; - flow(src); - } - }; -} - -Readable.prototype.unpipe = function (dest) { - var state = this._readableState; - var unpipeInfo = { hasUnpiped: false }; - - // if we're not piping anywhere, then do nothing. - if (state.pipesCount === 0) return this; - - // just one destination. most common case. - if (state.pipesCount === 1) { - // passed in one, but it's not the right one. - if (dest && dest !== state.pipes) return this; - - if (!dest) dest = state.pipes; - - // got a match. - state.pipes = null; - state.pipesCount = 0; - state.flowing = false; - if (dest) dest.emit('unpipe', this, unpipeInfo); - return this; - } - - // slow case. multiple pipe destinations. - - if (!dest) { - // remove all. - var dests = state.pipes; - var len = state.pipesCount; - state.pipes = null; - state.pipesCount = 0; - state.flowing = false; - - for (var i = 0; i < len; i++) { - dests[i].emit('unpipe', this, unpipeInfo); - }return this; - } - - // try to find the right one. - var index = indexOf(state.pipes, dest); - if (index === -1) return this; - - state.pipes.splice(index, 1); - state.pipesCount -= 1; - if (state.pipesCount === 1) state.pipes = state.pipes[0]; - - dest.emit('unpipe', this, unpipeInfo); - - return this; -}; - -// set up data events if they are asked for -// Ensure readable listeners eventually get something -Readable.prototype.on = function (ev, fn) { - var res = Stream.prototype.on.call(this, ev, fn); - - if (ev === 'data') { - // Start flowing on next tick if stream isn't explicitly paused - if (this._readableState.flowing !== false) this.resume(); - } else if (ev === 'readable') { - var state = this._readableState; - if (!state.endEmitted && !state.readableListening) { - state.readableListening = state.needReadable = true; - state.emittedReadable = false; - if (!state.reading) { - processNextTick(nReadingNextTick, this); - } else if (state.length) { - emitReadable(this); - } - } - } - - return res; -}; -Readable.prototype.addListener = Readable.prototype.on; - -function nReadingNextTick(self) { - debug('readable nexttick read 0'); - self.read(0); -} - -// pause() and resume() are remnants of the legacy readable stream API -// If the user uses them, then switch into old mode. -Readable.prototype.resume = function () { - var state = this._readableState; - if (!state.flowing) { - debug('resume'); - state.flowing = true; - resume(this, state); - } - return this; -}; - -function resume(stream, state) { - if (!state.resumeScheduled) { - state.resumeScheduled = true; - processNextTick(resume_, stream, state); - } -} - -function resume_(stream, state) { - if (!state.reading) { - debug('resume read 0'); - stream.read(0); - } - - state.resumeScheduled = false; - state.awaitDrain = 0; - stream.emit('resume'); - flow(stream); - if (state.flowing && !state.reading) stream.read(0); -} - -Readable.prototype.pause = function () { - debug('call pause flowing=%j', this._readableState.flowing); - if (false !== this._readableState.flowing) { - debug('pause'); - this._readableState.flowing = false; - this.emit('pause'); - } - return this; -}; - -function flow(stream) { - var state = stream._readableState; - debug('flow', state.flowing); - while (state.flowing && stream.read() !== null) {} -} - -// wrap an old-style stream as the async data source. -// This is *not* part of the readable stream interface. -// It is an ugly unfortunate mess of history. -Readable.prototype.wrap = function (stream) { - var _this = this; - - var state = this._readableState; - var paused = false; - - stream.on('end', function () { - debug('wrapped end'); - if (state.decoder && !state.ended) { - var chunk = state.decoder.end(); - if (chunk && chunk.length) _this.push(chunk); - } - - _this.push(null); - }); - - stream.on('data', function (chunk) { - debug('wrapped data'); - if (state.decoder) chunk = state.decoder.write(chunk); - - // don't skip over falsy values in objectMode - if (state.objectMode && (chunk === null || chunk === undefined)) return;else if (!state.objectMode && (!chunk || !chunk.length)) return; - - var ret = _this.push(chunk); - if (!ret) { - paused = true; - stream.pause(); - } - }); - - // proxy all the other methods. - // important when wrapping filters and duplexes. - for (var i in stream) { - if (this[i] === undefined && typeof stream[i] === 'function') { - this[i] = function (method) { - return function () { - return stream[method].apply(stream, arguments); - }; - }(i); - } - } - - // proxy certain important events. - for (var n = 0; n < kProxyEvents.length; n++) { - stream.on(kProxyEvents[n], this.emit.bind(this, kProxyEvents[n])); - } - - // when we try to consume some more bytes, simply unpause the - // underlying stream. - this._read = function (n) { - debug('wrapped _read', n); - if (paused) { - paused = false; - stream.resume(); - } - }; - - return this; -}; - -// exposed for testing purposes only. -Readable._fromList = fromList; - -// Pluck off n bytes from an array of buffers. -// Length is the combined lengths of all the buffers in the list. -// This function is designed to be inlinable, so please take care when making -// changes to the function body. -function fromList(n, state) { - // nothing buffered - if (state.length === 0) return null; - - var ret; - if (state.objectMode) ret = state.buffer.shift();else if (!n || n >= state.length) { - // read it all, truncate the list - if (state.decoder) ret = state.buffer.join('');else if (state.buffer.length === 1) ret = state.buffer.head.data;else ret = state.buffer.concat(state.length); - state.buffer.clear(); - } else { - // read part of list - ret = fromListPartial(n, state.buffer, state.decoder); - } - - return ret; -} - -// Extracts only enough buffered data to satisfy the amount requested. -// This function is designed to be inlinable, so please take care when making -// changes to the function body. -function fromListPartial(n, list, hasStrings) { - var ret; - if (n < list.head.data.length) { - // slice is the same for buffers and strings - ret = list.head.data.slice(0, n); - list.head.data = list.head.data.slice(n); - } else if (n === list.head.data.length) { - // first chunk is a perfect match - ret = list.shift(); - } else { - // result spans more than one buffer - ret = hasStrings ? copyFromBufferString(n, list) : copyFromBuffer(n, list); - } - return ret; -} - -// Copies a specified amount of characters from the list of buffered data -// chunks. -// This function is designed to be inlinable, so please take care when making -// changes to the function body. -function copyFromBufferString(n, list) { - var p = list.head; - var c = 1; - var ret = p.data; - n -= ret.length; - while (p = p.next) { - var str = p.data; - var nb = n > str.length ? str.length : n; - if (nb === str.length) ret += str;else ret += str.slice(0, n); - n -= nb; - if (n === 0) { - if (nb === str.length) { - ++c; - if (p.next) list.head = p.next;else list.head = list.tail = null; - } else { - list.head = p; - p.data = str.slice(nb); - } - break; - } - ++c; - } - list.length -= c; - return ret; -} - -// Copies a specified amount of bytes from the list of buffered data chunks. -// This function is designed to be inlinable, so please take care when making -// changes to the function body. -function copyFromBuffer(n, list) { - var ret = Buffer.allocUnsafe(n); - var p = list.head; - var c = 1; - p.data.copy(ret); - n -= p.data.length; - while (p = p.next) { - var buf = p.data; - var nb = n > buf.length ? buf.length : n; - buf.copy(ret, ret.length - n, 0, nb); - n -= nb; - if (n === 0) { - if (nb === buf.length) { - ++c; - if (p.next) list.head = p.next;else list.head = list.tail = null; - } else { - list.head = p; - p.data = buf.slice(nb); - } - break; - } - ++c; - } - list.length -= c; - return ret; -} - -function endReadable(stream) { - var state = stream._readableState; - - // If we get here before consuming all the bytes, then that is a - // bug in node. Should never happen. - if (state.length > 0) throw new Error('"endReadable()" called on non-empty stream'); - - if (!state.endEmitted) { - state.ended = true; - processNextTick(endReadableNT, state, stream); - } -} - -function endReadableNT(state, stream) { - // Check that we didn't get one last unshift. - if (!state.endEmitted && state.length === 0) { - state.endEmitted = true; - stream.readable = false; - stream.emit('end'); - } -} - -function forEach(xs, f) { - for (var i = 0, l = xs.length; i < l; i++) { - f(xs[i], i); - } -} - -function indexOf(xs, x) { - for (var i = 0, l = xs.length; i < l; i++) { - if (xs[i] === x) return i; - } - return -1; -} -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(7), __webpack_require__(11))) - -/***/ }), -/* 84 */ -/***/ (function(module, exports, __webpack_require__) { - -module.exports = __webpack_require__(31).EventEmitter; - - -/***/ }), -/* 85 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/**/ - -var processNextTick = __webpack_require__(32).nextTick; -/**/ - -// undocumented cb() API, needed for core, not for public API -function destroy(err, cb) { - var _this = this; - - var readableDestroyed = this._readableState && this._readableState.destroyed; - var writableDestroyed = this._writableState && this._writableState.destroyed; - - if (readableDestroyed || writableDestroyed) { - if (cb) { - cb(err); - } else if (err && (!this._writableState || !this._writableState.errorEmitted)) { - processNextTick(emitErrorNT, this, err); - } - return this; - } - - // we set destroyed to true before firing error callbacks in order - // to make it re-entrance safe in case destroy() is called within callbacks - - if (this._readableState) { - this._readableState.destroyed = true; - } - - // if this is a duplex stream mark the writable part as destroyed as well - if (this._writableState) { - this._writableState.destroyed = true; - } - - this._destroy(err || null, function (err) { - if (!cb && err) { - processNextTick(emitErrorNT, _this, err); - if (_this._writableState) { - _this._writableState.errorEmitted = true; - } - } else if (cb) { - cb(err); - } - }); - - return this; -} - -function undestroy() { - if (this._readableState) { - this._readableState.destroyed = false; - this._readableState.reading = false; - this._readableState.ended = false; - this._readableState.endEmitted = false; - } - - if (this._writableState) { - this._writableState.destroyed = false; - this._writableState.ended = false; - this._writableState.ending = false; - this._writableState.finished = false; - this._writableState.errorEmitted = false; - } -} - -function emitErrorNT(self, err) { - self.emit('error', err); -} - -module.exports = { - destroy: destroy, - undestroy: undestroy -}; - -/***/ }), -/* 86 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -// a transform stream is a readable/writable stream where you do -// something with the data. Sometimes it's called a "filter", -// but that's not a great name for it, since that implies a thing where -// some bits pass through, and others are simply ignored. (That would -// be a valid example of a transform, of course.) -// -// While the output is causally related to the input, it's not a -// necessarily symmetric or synchronous transformation. For example, -// a zlib stream might take multiple plain-text writes(), and then -// emit a single compressed chunk some time in the future. -// -// Here's how this works: -// -// The Transform stream has all the aspects of the readable and writable -// stream classes. When you write(chunk), that calls _write(chunk,cb) -// internally, and returns false if there's a lot of pending writes -// buffered up. When you call read(), that calls _read(n) until -// there's enough pending readable data buffered up. -// -// In a transform stream, the written data is placed in a buffer. When -// _read(n) is called, it transforms the queued up data, calling the -// buffered _write cb's as it consumes chunks. If consuming a single -// written chunk would result in multiple output chunks, then the first -// outputted bit calls the readcb, and subsequent chunks just go into -// the read buffer, and will cause it to emit 'readable' if necessary. -// -// This way, back-pressure is actually determined by the reading side, -// since _read has to be called to start processing a new chunk. However, -// a pathological inflate type of transform can cause excessive buffering -// here. For example, imagine a stream where every byte of input is -// interpreted as an integer from 0-255, and then results in that many -// bytes of output. Writing the 4 bytes {ff,ff,ff,ff} would result in -// 1kb of data being output. In this case, you could write a very small -// amount of input, and end up with a very large amount of output. In -// such a pathological inflating mechanism, there'd be no way to tell -// the system to stop doing the transform. A single 4MB write could -// cause the system to run out of memory. -// -// However, even in such a pathological case, only a single written chunk -// would be consumed, and then the rest would wait (un-transformed) until -// the results of the previous transformed chunk were consumed. - - - -module.exports = Transform; - -var Duplex = __webpack_require__(16); - -/**/ -var util = __webpack_require__(25); -util.inherits = __webpack_require__(21); -/**/ - -util.inherits(Transform, Duplex); - -function afterTransform(er, data) { - var ts = this._transformState; - ts.transforming = false; - - var cb = ts.writecb; - - if (!cb) { - return this.emit('error', new Error('write callback called multiple times')); - } - - ts.writechunk = null; - ts.writecb = null; - - if (data != null) // single equals check for both `null` and `undefined` - this.push(data); - - cb(er); - - var rs = this._readableState; - rs.reading = false; - if (rs.needReadable || rs.length < rs.highWaterMark) { - this._read(rs.highWaterMark); - } -} - -function Transform(options) { - if (!(this instanceof Transform)) return new Transform(options); - - Duplex.call(this, options); - - this._transformState = { - afterTransform: afterTransform.bind(this), - needTransform: false, - transforming: false, - writecb: null, - writechunk: null, - writeencoding: null - }; - - // start out asking for a readable event once data is transformed. - this._readableState.needReadable = true; - - // we have implemented the _read method, and done the other things - // that Readable wants before the first _read call, so unset the - // sync guard flag. - this._readableState.sync = false; - - if (options) { - if (typeof options.transform === 'function') this._transform = options.transform; - - if (typeof options.flush === 'function') this._flush = options.flush; - } - - // When the writable side finishes, then flush out anything remaining. - this.on('prefinish', prefinish); -} - -function prefinish() { - var _this = this; - - if (typeof this._flush === 'function') { - this._flush(function (er, data) { - done(_this, er, data); - }); - } else { - done(this, null, null); - } -} - -Transform.prototype.push = function (chunk, encoding) { - this._transformState.needTransform = false; - return Duplex.prototype.push.call(this, chunk, encoding); -}; - -// This is the part where you do stuff! -// override this function in implementation classes. -// 'chunk' is an input chunk. -// -// Call `push(newChunk)` to pass along transformed output -// to the readable side. You may call 'push' zero or more times. -// -// Call `cb(err)` when you are done with this chunk. If you pass -// an error, then that'll put the hurt on the whole operation. If you -// never call cb(), then you'll never get another chunk. -Transform.prototype._transform = function (chunk, encoding, cb) { - throw new Error('_transform() is not implemented'); -}; - -Transform.prototype._write = function (chunk, encoding, cb) { - var ts = this._transformState; - ts.writecb = cb; - ts.writechunk = chunk; - ts.writeencoding = encoding; - if (!ts.transforming) { - var rs = this._readableState; - if (ts.needTransform || rs.needReadable || rs.length < rs.highWaterMark) this._read(rs.highWaterMark); - } -}; - -// Doesn't matter what the args are here. -// _transform does all the work. -// That we got here means that the readable side wants more data. -Transform.prototype._read = function (n) { - var ts = this._transformState; - - if (ts.writechunk !== null && ts.writecb && !ts.transforming) { - ts.transforming = true; - this._transform(ts.writechunk, ts.writeencoding, ts.afterTransform); - } else { - // mark that we need a transform, so that any data that comes in - // will get processed, now that we've asked for it. - ts.needTransform = true; - } -}; - -Transform.prototype._destroy = function (err, cb) { - var _this2 = this; - - Duplex.prototype._destroy.call(this, err, function (err2) { - cb(err2); - _this2.emit('close'); - }); -}; - -function done(stream, er, data) { - if (er) return stream.emit('error', er); - - if (data != null) // single equals check for both `null` and `undefined` - stream.push(data); - - // if there's nothing in the write buffer, then that means - // that nothing more will ever be provided - if (stream._writableState.length) throw new Error('Calling transform done when ws.length != 0'); - - if (stream._transformState.transforming) throw new Error('Calling transform done when still transforming'); - - return stream.push(null); -} - -/***/ }), -/* 87 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(Buffer) {// Generated by CoffeeScript 1.12.6 - -/* -PDFReference - represents a reference to another object in the PDF object heirarchy -By Devon Govett - */ - -(function() { - var PDFObject, PDFReference, stream, zlib, - bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, - extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, - hasProp = {}.hasOwnProperty; - - zlib = __webpack_require__(48); - - stream = __webpack_require__(15); - - PDFReference = (function(superClass) { - extend(PDFReference, superClass); - - function PDFReference(document, id, data) { - this.document = document; - this.id = id; - this.data = data != null ? data : {}; - this.finalize = bind(this.finalize, this); - PDFReference.__super__.constructor.call(this, { - decodeStrings: false - }); - this.gen = 0; - this.deflate = null; - this.compress = this.document.compress && !this.data.Filter; - this.uncompressedLength = 0; - this.chunks = []; - } - - PDFReference.prototype.initDeflate = function() { - this.data.Filter = 'FlateDecode'; - this.deflate = zlib.createDeflate(); - this.deflate.on('data', (function(_this) { - return function(chunk) { - _this.chunks.push(chunk); - return _this.data.Length += chunk.length; - }; - })(this)); - return this.deflate.on('end', this.finalize); - }; - - PDFReference.prototype._write = function(chunk, encoding, callback) { - var base; - if (!Buffer.isBuffer(chunk)) { - chunk = new Buffer(chunk + '\n', 'binary'); - } - this.uncompressedLength += chunk.length; - if ((base = this.data).Length == null) { - base.Length = 0; - } - if (this.compress) { - if (!this.deflate) { - this.initDeflate(); - } - this.deflate.write(chunk); - } else { - this.chunks.push(chunk); - this.data.Length += chunk.length; - } - return callback(); - }; - - PDFReference.prototype.end = function(chunk) { - PDFReference.__super__.end.apply(this, arguments); - if (this.deflate) { - return this.deflate.end(); - } else { - return this.finalize(); - } - }; - - PDFReference.prototype.finalize = function() { - var chunk, i, len, ref; - this.offset = this.document._offset; - this.document._write(this.id + " " + this.gen + " obj"); - this.document._write(PDFObject.convert(this.data)); - if (this.chunks.length) { - this.document._write('stream'); - ref = this.chunks; - for (i = 0, len = ref.length; i < len; i++) { - chunk = ref[i]; - this.document._write(chunk); - } - this.chunks.length = 0; - this.document._write('\nendstream'); - } - this.document._write('endobj'); - return this.document._refEnd(this); - }; - - PDFReference.prototype.toString = function() { - return this.id + " " + this.gen + " R"; - }; - - return PDFReference; - - })(stream.Writable); - - module.exports = PDFReference; - - PDFObject = __webpack_require__(26); - -}).call(this); - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1).Buffer)) - -/***/ }), -/* 88 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/* WEBPACK VAR INJECTION */(function(global) { - -// compare and isBuffer taken from https://github.com/feross/buffer/blob/680e9e5e488f22aac27599a57dc844a6315928dd/index.js -// original notice: - -/*! - * The buffer module from node.js, for the browser. - * - * @author Feross Aboukhadijeh - * @license MIT - */ -function compare(a, b) { - if (a === b) { - return 0; - } - - var x = a.length; - var y = b.length; - - for (var i = 0, len = Math.min(x, y); i < len; ++i) { - if (a[i] !== b[i]) { - x = a[i]; - y = b[i]; - break; - } - } - - if (x < y) { - return -1; - } - if (y < x) { - return 1; - } - return 0; -} -function isBuffer(b) { - if (global.Buffer && typeof global.Buffer.isBuffer === 'function') { - return global.Buffer.isBuffer(b); - } - return !!(b != null && b._isBuffer); -} - -// based on node assert, original notice: - -// http://wiki.commonjs.org/wiki/Unit_Testing/1.0 -// -// THIS IS NOT TESTED NOR LIKELY TO WORK OUTSIDE V8! -// -// Originally from narwhal.js (http://narwhaljs.org) -// Copyright (c) 2009 Thomas Robinson <280north.com> -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the 'Software'), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -var util = __webpack_require__(49); -var hasOwn = Object.prototype.hasOwnProperty; -var pSlice = Array.prototype.slice; -var functionsHaveNames = (function () { - return function foo() {}.name === 'foo'; -}()); -function pToString (obj) { - return Object.prototype.toString.call(obj); -} -function isView(arrbuf) { - if (isBuffer(arrbuf)) { - return false; - } - if (typeof global.ArrayBuffer !== 'function') { - return false; - } - if (typeof ArrayBuffer.isView === 'function') { - return ArrayBuffer.isView(arrbuf); - } - if (!arrbuf) { - return false; - } - if (arrbuf instanceof DataView) { - return true; - } - if (arrbuf.buffer && arrbuf.buffer instanceof ArrayBuffer) { - return true; - } - return false; -} -// 1. The assert module provides functions that throw -// AssertionError's when particular conditions are not met. The -// assert module must conform to the following interface. - -var assert = module.exports = ok; - -// 2. The AssertionError is defined in assert. -// new assert.AssertionError({ message: message, -// actual: actual, -// expected: expected }) - -var regex = /\s*function\s+([^\(\s]*)\s*/; -// based on https://github.com/ljharb/function.prototype.name/blob/adeeeec8bfcc6068b187d7d9fb3d5bb1d3a30899/implementation.js -function getName(func) { - if (!util.isFunction(func)) { - return; - } - if (functionsHaveNames) { - return func.name; - } - var str = func.toString(); - var match = str.match(regex); - return match && match[1]; -} -assert.AssertionError = function AssertionError(options) { - this.name = 'AssertionError'; - this.actual = options.actual; - this.expected = options.expected; - this.operator = options.operator; - if (options.message) { - this.message = options.message; - this.generatedMessage = false; - } else { - this.message = getMessage(this); - this.generatedMessage = true; - } - var stackStartFunction = options.stackStartFunction || fail; - if (Error.captureStackTrace) { - Error.captureStackTrace(this, stackStartFunction); - } else { - // non v8 browsers so we can have a stacktrace - var err = new Error(); - if (err.stack) { - var out = err.stack; - - // try to strip useless frames - var fn_name = getName(stackStartFunction); - var idx = out.indexOf('\n' + fn_name); - if (idx >= 0) { - // once we have located the function frame - // we need to strip out everything before it (and its line) - var next_line = out.indexOf('\n', idx + 1); - out = out.substring(next_line + 1); - } - - this.stack = out; - } - } -}; - -// assert.AssertionError instanceof Error -util.inherits(assert.AssertionError, Error); - -function truncate(s, n) { - if (typeof s === 'string') { - return s.length < n ? s : s.slice(0, n); - } else { - return s; - } -} -function inspect(something) { - if (functionsHaveNames || !util.isFunction(something)) { - return util.inspect(something); - } - var rawname = getName(something); - var name = rawname ? ': ' + rawname : ''; - return '[Function' + name + ']'; -} -function getMessage(self) { - return truncate(inspect(self.actual), 128) + ' ' + - self.operator + ' ' + - truncate(inspect(self.expected), 128); -} - -// At present only the three keys mentioned above are used and -// understood by the spec. Implementations or sub modules can pass -// other keys to the AssertionError's constructor - they will be -// ignored. - -// 3. All of the following functions must throw an AssertionError -// when a corresponding condition is not met, with a message that -// may be undefined if not provided. All assertion methods provide -// both the actual and expected values to the assertion error for -// display purposes. - -function fail(actual, expected, message, operator, stackStartFunction) { - throw new assert.AssertionError({ - message: message, - actual: actual, - expected: expected, - operator: operator, - stackStartFunction: stackStartFunction - }); -} - -// EXTENSION! allows for well behaved errors defined elsewhere. -assert.fail = fail; - -// 4. Pure assertion tests whether a value is truthy, as determined -// by !!guard. -// assert.ok(guard, message_opt); -// This statement is equivalent to assert.equal(true, !!guard, -// message_opt);. To test strictly for the value true, use -// assert.strictEqual(true, guard, message_opt);. - -function ok(value, message) { - if (!value) fail(value, true, message, '==', assert.ok); -} -assert.ok = ok; - -// 5. The equality assertion tests shallow, coercive equality with -// ==. -// assert.equal(actual, expected, message_opt); - -assert.equal = function equal(actual, expected, message) { - if (actual != expected) fail(actual, expected, message, '==', assert.equal); -}; - -// 6. The non-equality assertion tests for whether two objects are not equal -// with != assert.notEqual(actual, expected, message_opt); - -assert.notEqual = function notEqual(actual, expected, message) { - if (actual == expected) { - fail(actual, expected, message, '!=', assert.notEqual); - } -}; - -// 7. The equivalence assertion tests a deep equality relation. -// assert.deepEqual(actual, expected, message_opt); - -assert.deepEqual = function deepEqual(actual, expected, message) { - if (!_deepEqual(actual, expected, false)) { - fail(actual, expected, message, 'deepEqual', assert.deepEqual); - } -}; - -assert.deepStrictEqual = function deepStrictEqual(actual, expected, message) { - if (!_deepEqual(actual, expected, true)) { - fail(actual, expected, message, 'deepStrictEqual', assert.deepStrictEqual); - } -}; - -function _deepEqual(actual, expected, strict, memos) { - // 7.1. All identical values are equivalent, as determined by ===. - if (actual === expected) { - return true; - } else if (isBuffer(actual) && isBuffer(expected)) { - return compare(actual, expected) === 0; - - // 7.2. If the expected value is a Date object, the actual value is - // equivalent if it is also a Date object that refers to the same time. - } else if (util.isDate(actual) && util.isDate(expected)) { - return actual.getTime() === expected.getTime(); - - // 7.3 If the expected value is a RegExp object, the actual value is - // equivalent if it is also a RegExp object with the same source and - // properties (`global`, `multiline`, `lastIndex`, `ignoreCase`). - } else if (util.isRegExp(actual) && util.isRegExp(expected)) { - return actual.source === expected.source && - actual.global === expected.global && - actual.multiline === expected.multiline && - actual.lastIndex === expected.lastIndex && - actual.ignoreCase === expected.ignoreCase; - - // 7.4. Other pairs that do not both pass typeof value == 'object', - // equivalence is determined by ==. - } else if ((actual === null || typeof actual !== 'object') && - (expected === null || typeof expected !== 'object')) { - return strict ? actual === expected : actual == expected; - - // If both values are instances of typed arrays, wrap their underlying - // ArrayBuffers in a Buffer each to increase performance - // This optimization requires the arrays to have the same type as checked by - // Object.prototype.toString (aka pToString). Never perform binary - // comparisons for Float*Arrays, though, since e.g. +0 === -0 but their - // bit patterns are not identical. - } else if (isView(actual) && isView(expected) && - pToString(actual) === pToString(expected) && - !(actual instanceof Float32Array || - actual instanceof Float64Array)) { - return compare(new Uint8Array(actual.buffer), - new Uint8Array(expected.buffer)) === 0; - - // 7.5 For all other Object pairs, including Array objects, equivalence is - // determined by having the same number of owned properties (as verified - // with Object.prototype.hasOwnProperty.call), the same set of keys - // (although not necessarily the same order), equivalent values for every - // corresponding key, and an identical 'prototype' property. Note: this - // accounts for both named and indexed properties on Arrays. - } else if (isBuffer(actual) !== isBuffer(expected)) { - return false; - } else { - memos = memos || {actual: [], expected: []}; - - var actualIndex = memos.actual.indexOf(actual); - if (actualIndex !== -1) { - if (actualIndex === memos.expected.indexOf(expected)) { - return true; - } - } - - memos.actual.push(actual); - memos.expected.push(expected); - - return objEquiv(actual, expected, strict, memos); - } -} - -function isArguments(object) { - return Object.prototype.toString.call(object) == '[object Arguments]'; -} - -function objEquiv(a, b, strict, actualVisitedObjects) { - if (a === null || a === undefined || b === null || b === undefined) - return false; - // if one is a primitive, the other must be same - if (util.isPrimitive(a) || util.isPrimitive(b)) - return a === b; - if (strict && Object.getPrototypeOf(a) !== Object.getPrototypeOf(b)) - return false; - var aIsArgs = isArguments(a); - var bIsArgs = isArguments(b); - if ((aIsArgs && !bIsArgs) || (!aIsArgs && bIsArgs)) - return false; - if (aIsArgs) { - a = pSlice.call(a); - b = pSlice.call(b); - return _deepEqual(a, b, strict); - } - var ka = objectKeys(a); - var kb = objectKeys(b); - var key, i; - // having the same number of owned properties (keys incorporates - // hasOwnProperty) - if (ka.length !== kb.length) - return false; - //the same set of keys (although not necessarily the same order), - ka.sort(); - kb.sort(); - //~~~cheap key test - for (i = ka.length - 1; i >= 0; i--) { - if (ka[i] !== kb[i]) - return false; - } - //equivalent values for every corresponding key, and - //~~~possibly expensive deep test - for (i = ka.length - 1; i >= 0; i--) { - key = ka[i]; - if (!_deepEqual(a[key], b[key], strict, actualVisitedObjects)) - return false; - } - return true; -} - -// 8. The non-equivalence assertion tests for any deep inequality. -// assert.notDeepEqual(actual, expected, message_opt); - -assert.notDeepEqual = function notDeepEqual(actual, expected, message) { - if (_deepEqual(actual, expected, false)) { - fail(actual, expected, message, 'notDeepEqual', assert.notDeepEqual); - } -}; - -assert.notDeepStrictEqual = notDeepStrictEqual; -function notDeepStrictEqual(actual, expected, message) { - if (_deepEqual(actual, expected, true)) { - fail(actual, expected, message, 'notDeepStrictEqual', notDeepStrictEqual); - } -} - - -// 9. The strict equality assertion tests strict equality, as determined by ===. -// assert.strictEqual(actual, expected, message_opt); - -assert.strictEqual = function strictEqual(actual, expected, message) { - if (actual !== expected) { - fail(actual, expected, message, '===', assert.strictEqual); - } -}; - -// 10. The strict non-equality assertion tests for strict inequality, as -// determined by !==. assert.notStrictEqual(actual, expected, message_opt); - -assert.notStrictEqual = function notStrictEqual(actual, expected, message) { - if (actual === expected) { - fail(actual, expected, message, '!==', assert.notStrictEqual); - } -}; - -function expectedException(actual, expected) { - if (!actual || !expected) { - return false; - } - - if (Object.prototype.toString.call(expected) == '[object RegExp]') { - return expected.test(actual); - } - - try { - if (actual instanceof expected) { - return true; - } - } catch (e) { - // Ignore. The instanceof check doesn't work for arrow functions. - } - - if (Error.isPrototypeOf(expected)) { - return false; - } - - return expected.call({}, actual) === true; -} - -function _tryBlock(block) { - var error; - try { - block(); - } catch (e) { - error = e; - } - return error; -} - -function _throws(shouldThrow, block, expected, message) { - var actual; - - if (typeof block !== 'function') { - throw new TypeError('"block" argument must be a function'); - } - - if (typeof expected === 'string') { - message = expected; - expected = null; - } - - actual = _tryBlock(block); - - message = (expected && expected.name ? ' (' + expected.name + ').' : '.') + - (message ? ' ' + message : '.'); - - if (shouldThrow && !actual) { - fail(actual, expected, 'Missing expected exception' + message); - } - - var userProvidedMessage = typeof message === 'string'; - var isUnwantedException = !shouldThrow && util.isError(actual); - var isUnexpectedException = !shouldThrow && actual && !expected; - - if ((isUnwantedException && - userProvidedMessage && - expectedException(actual, expected)) || - isUnexpectedException) { - fail(actual, expected, 'Got unwanted exception' + message); - } - - if ((shouldThrow && actual && expected && - !expectedException(actual, expected)) || (!shouldThrow && actual)) { - throw actual; - } -} - -// 11. Expected to throw an error: -// assert.throws(block, Error_opt, message_opt); - -assert.throws = function(block, /*optional*/error, /*optional*/message) { - _throws(true, block, error, message); -}; - -// EXTENSION! This is annoying to write outside this module. -assert.doesNotThrow = function(block, /*optional*/error, /*optional*/message) { - _throws(false, block, error, message); -}; - -assert.ifError = function(err) { if (err) throw err; }; - -var objectKeys = Object.keys || function (obj) { - var keys = []; - for (var key in obj) { - if (hasOwn.call(obj, key)) keys.push(key); - } - return keys; -}; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(7))) - -/***/ }), -/* 89 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -// Note: adler32 takes 12% for level 0 and 2% for level 6. -// It isn't worth it to make additional optimizations as in original. -// Small size is preferable. - -// (C) 1995-2013 Jean-loup Gailly and Mark Adler -// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any damages -// arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must not -// claim that you wrote the original software. If you use this software -// in a product, an acknowledgment in the product documentation would be -// appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must not be -// misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source distribution. - -function adler32(adler, buf, len, pos) { - var s1 = (adler & 0xffff) |0, - s2 = ((adler >>> 16) & 0xffff) |0, - n = 0; - - while (len !== 0) { - // Set limit ~ twice less than 5552, to keep - // s2 in 31-bits, because we force signed ints. - // in other case %= will fail. - n = len > 2000 ? 2000 : len; - len -= n; - - do { - s1 = (s1 + buf[pos++]) |0; - s2 = (s2 + s1) |0; - } while (--n); - - s1 %= 65521; - s2 %= 65521; - } - - return (s1 | (s2 << 16)) |0; -} - - -module.exports = adler32; - - -/***/ }), -/* 90 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -// Note: we can't get significant speed boost here. -// So write code to minimize size - no pregenerated tables -// and array tools dependencies. - -// (C) 1995-2013 Jean-loup Gailly and Mark Adler -// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any damages -// arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must not -// claim that you wrote the original software. If you use this software -// in a product, an acknowledgment in the product documentation would be -// appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must not be -// misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source distribution. - -// Use ordinary array, since untyped makes no boost here -function makeTable() { - var c, table = []; - - for (var n = 0; n < 256; n++) { - c = n; - for (var k = 0; k < 8; k++) { - c = ((c & 1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1)); - } - table[n] = c; - } - - return table; -} - -// Create table on load. Just 255 signed longs. Not a problem. -var crcTable = makeTable(); - - -function crc32(crc, buf, len, pos) { - var t = crcTable, - end = pos + len; - - crc ^= -1; - - for (var i = pos; i < end; i++) { - crc = (crc >>> 8) ^ t[(crc ^ buf[i]) & 0xFF]; - } - - return (crc ^ (-1)); // >>> 0; -} - - -module.exports = crc32; - - -/***/ }), -/* 91 */ -/***/ (function(module, exports) { - -module.exports = [["a140","",62],["a180","",32],["a240","",62],["a280","",32],["a2ab","",5],["a2e3","€"],["a2ef",""],["a2fd",""],["a340","",62],["a380","",31," "],["a440","",62],["a480","",32],["a4f4","",10],["a540","",62],["a580","",32],["a5f7","",7],["a640","",62],["a680","",32],["a6b9","",7],["a6d9","",6],["a6ec",""],["a6f3",""],["a6f6","",8],["a740","",62],["a780","",32],["a7c2","",14],["a7f2","",12],["a896","",10],["a8bc",""],["a8bf","ǹ"],["a8c1",""],["a8ea","",20],["a958",""],["a95b",""],["a95d",""],["a989","〾⿰",11],["a997","",12],["a9f0","",14],["aaa1","",93],["aba1","",93],["aca1","",93],["ada1","",93],["aea1","",93],["afa1","",93],["d7fa","",4],["f8a1","",93],["f9a1","",93],["faa1","",93],["fba1","",93],["fca1","",93],["fda1","",93],["fe50","⺁⺄㑳㑇⺈⺋㖞㘚㘎⺌⺗㥮㤘㧏㧟㩳㧐㭎㱮㳠⺧⺪䁖䅟⺮䌷⺳⺶⺷䎱䎬⺻䏝䓖䙡䙌"],["fe80","䜣䜩䝼䞍⻊䥇䥺䥽䦂䦃䦅䦆䦟䦛䦷䦶䲣䲟䲠䲡䱷䲢䴓",6,"䶮",93]] - -/***/ }), -/* 92 */ -/***/ (function(module, exports) { - -module.exports = [["0","\u0000",127],["a140"," ,、。.‧;:?!︰…‥﹐﹑﹒·﹔﹕﹖﹗|–︱—︳╴︴﹏()︵︶{}︷︸〔〕︹︺【】︻︼《》︽︾〈〉︿﹀「」﹁﹂『』﹃﹄﹙﹚"],["a1a1","﹛﹜﹝﹞‘’“”〝〞‵′#&*※§〃○●△▲◎☆★◇◆□■▽▼㊣℅¯ ̄_ˍ﹉﹊﹍﹎﹋﹌﹟﹠﹡+-×÷±√<>=≦≧≠∞≒≡﹢",4,"~∩∪⊥∠∟⊿㏒㏑∫∮∵∴♀♂⊕⊙↑↓←→↖↗↙↘∥∣/"],["a240","\∕﹨$¥〒¢£%@℃℉﹩﹪﹫㏕㎜㎝㎞㏎㎡㎎㎏㏄°兙兛兞兝兡兣嗧瓩糎▁",7,"▏▎▍▌▋▊▉┼┴┬┤├▔─│▕┌┐└┘╭"],["a2a1","╮╰╯═╞╪╡◢◣◥◤╱╲╳0",9,"Ⅰ",9,"〡",8,"十卄卅A",25,"a",21],["a340","wxyzΑ",16,"Σ",6,"α",16,"σ",6,"ㄅ",10],["a3a1","ㄐ",25,"˙ˉˊˇˋ"],["a3e1","€"],["a440","一乙丁七乃九了二人儿入八几刀刁力匕十卜又三下丈上丫丸凡久么也乞于亡兀刃勺千叉口土士夕大女子孑孓寸小尢尸山川工己已巳巾干廾弋弓才"],["a4a1","丑丐不中丰丹之尹予云井互五亢仁什仃仆仇仍今介仄元允內六兮公冗凶分切刈勻勾勿化匹午升卅卞厄友及反壬天夫太夭孔少尤尺屯巴幻廿弔引心戈戶手扎支文斗斤方日曰月木欠止歹毋比毛氏水火爪父爻片牙牛犬王丙"],["a540","世丕且丘主乍乏乎以付仔仕他仗代令仙仞充兄冉冊冬凹出凸刊加功包匆北匝仟半卉卡占卯卮去可古右召叮叩叨叼司叵叫另只史叱台句叭叻四囚外"],["a5a1","央失奴奶孕它尼巨巧左市布平幼弁弘弗必戊打扔扒扑斥旦朮本未末札正母民氐永汁汀氾犯玄玉瓜瓦甘生用甩田由甲申疋白皮皿目矛矢石示禾穴立丞丟乒乓乩亙交亦亥仿伉伙伊伕伍伐休伏仲件任仰仳份企伋光兇兆先全"],["a640","共再冰列刑划刎刖劣匈匡匠印危吉吏同吊吐吁吋各向名合吃后吆吒因回囝圳地在圭圬圯圩夙多夷夸妄奸妃好她如妁字存宇守宅安寺尖屹州帆并年"],["a6a1","式弛忙忖戎戌戍成扣扛托收早旨旬旭曲曳有朽朴朱朵次此死氖汝汗汙江池汐汕污汛汍汎灰牟牝百竹米糸缶羊羽老考而耒耳聿肉肋肌臣自至臼舌舛舟艮色艾虫血行衣西阡串亨位住佇佗佞伴佛何估佐佑伽伺伸佃佔似但佣"],["a740","作你伯低伶余佝佈佚兌克免兵冶冷別判利刪刨劫助努劬匣即卵吝吭吞吾否呎吧呆呃吳呈呂君吩告吹吻吸吮吵吶吠吼呀吱含吟听囪困囤囫坊坑址坍"],["a7a1","均坎圾坐坏圻壯夾妝妒妨妞妣妙妖妍妤妓妊妥孝孜孚孛完宋宏尬局屁尿尾岐岑岔岌巫希序庇床廷弄弟彤形彷役忘忌志忍忱快忸忪戒我抄抗抖技扶抉扭把扼找批扳抒扯折扮投抓抑抆改攻攸旱更束李杏材村杜杖杞杉杆杠"],["a840","杓杗步每求汞沙沁沈沉沅沛汪決沐汰沌汨沖沒汽沃汲汾汴沆汶沍沔沘沂灶灼災灸牢牡牠狄狂玖甬甫男甸皂盯矣私秀禿究系罕肖肓肝肘肛肚育良芒"],["a8a1","芋芍見角言谷豆豕貝赤走足身車辛辰迂迆迅迄巡邑邢邪邦那酉釆里防阮阱阪阬並乖乳事些亞享京佯依侍佳使佬供例來侃佰併侈佩佻侖佾侏侑佺兔兒兕兩具其典冽函刻券刷刺到刮制剁劾劻卒協卓卑卦卷卸卹取叔受味呵"],["a940","咖呸咕咀呻呷咄咒咆呼咐呱呶和咚呢周咋命咎固垃坷坪坩坡坦坤坼夜奉奇奈奄奔妾妻委妹妮姑姆姐姍始姓姊妯妳姒姅孟孤季宗定官宜宙宛尚屈居"],["a9a1","屆岷岡岸岩岫岱岳帘帚帖帕帛帑幸庚店府底庖延弦弧弩往征彿彼忝忠忽念忿怏怔怯怵怖怪怕怡性怩怫怛或戕房戾所承拉拌拄抿拂抹拒招披拓拔拋拈抨抽押拐拙拇拍抵拚抱拘拖拗拆抬拎放斧於旺昔易昌昆昂明昀昏昕昊"],["aa40","昇服朋杭枋枕東果杳杷枇枝林杯杰板枉松析杵枚枓杼杪杲欣武歧歿氓氛泣注泳沱泌泥河沽沾沼波沫法泓沸泄油況沮泗泅泱沿治泡泛泊沬泯泜泖泠"],["aaa1","炕炎炒炊炙爬爭爸版牧物狀狎狙狗狐玩玨玟玫玥甽疝疙疚的盂盲直知矽社祀祁秉秈空穹竺糾罔羌羋者肺肥肢肱股肫肩肴肪肯臥臾舍芳芝芙芭芽芟芹花芬芥芯芸芣芰芾芷虎虱初表軋迎返近邵邸邱邶采金長門阜陀阿阻附"],["ab40","陂隹雨青非亟亭亮信侵侯便俠俑俏保促侶俘俟俊俗侮俐俄係俚俎俞侷兗冒冑冠剎剃削前剌剋則勇勉勃勁匍南卻厚叛咬哀咨哎哉咸咦咳哇哂咽咪品"],["aba1","哄哈咯咫咱咻咩咧咿囿垂型垠垣垢城垮垓奕契奏奎奐姜姘姿姣姨娃姥姪姚姦威姻孩宣宦室客宥封屎屏屍屋峙峒巷帝帥帟幽庠度建弈弭彥很待徊律徇後徉怒思怠急怎怨恍恰恨恢恆恃恬恫恪恤扁拜挖按拼拭持拮拽指拱拷"],["ac40","拯括拾拴挑挂政故斫施既春昭映昧是星昨昱昤曷柿染柱柔某柬架枯柵柩柯柄柑枴柚查枸柏柞柳枰柙柢柝柒歪殃殆段毒毗氟泉洋洲洪流津洌洱洞洗"],["aca1","活洽派洶洛泵洹洧洸洩洮洵洎洫炫為炳炬炯炭炸炮炤爰牲牯牴狩狠狡玷珊玻玲珍珀玳甚甭畏界畎畋疫疤疥疢疣癸皆皇皈盈盆盃盅省盹相眉看盾盼眇矜砂研砌砍祆祉祈祇禹禺科秒秋穿突竿竽籽紂紅紀紉紇約紆缸美羿耄"],["ad40","耐耍耑耶胖胥胚胃胄背胡胛胎胞胤胝致舢苧范茅苣苛苦茄若茂茉苒苗英茁苜苔苑苞苓苟苯茆虐虹虻虺衍衫要觔計訂訃貞負赴赳趴軍軌述迦迢迪迥"],["ada1","迭迫迤迨郊郎郁郃酋酊重閂限陋陌降面革韋韭音頁風飛食首香乘亳倌倍倣俯倦倥俸倩倖倆值借倚倒們俺倀倔倨俱倡個候倘俳修倭倪俾倫倉兼冤冥冢凍凌准凋剖剜剔剛剝匪卿原厝叟哨唐唁唷哼哥哲唆哺唔哩哭員唉哮哪"],["ae40","哦唧唇哽唏圃圄埂埔埋埃堉夏套奘奚娑娘娜娟娛娓姬娠娣娩娥娌娉孫屘宰害家宴宮宵容宸射屑展屐峭峽峻峪峨峰島崁峴差席師庫庭座弱徒徑徐恙"],["aea1","恣恥恐恕恭恩息悄悟悚悍悔悌悅悖扇拳挈拿捎挾振捕捂捆捏捉挺捐挽挪挫挨捍捌效敉料旁旅時晉晏晃晒晌晅晁書朔朕朗校核案框桓根桂桔栩梳栗桌桑栽柴桐桀格桃株桅栓栘桁殊殉殷氣氧氨氦氤泰浪涕消涇浦浸海浙涓"],["af40","浬涉浮浚浴浩涌涊浹涅浥涔烊烘烤烙烈烏爹特狼狹狽狸狷玆班琉珮珠珪珞畔畝畜畚留疾病症疲疳疽疼疹痂疸皋皰益盍盎眩真眠眨矩砰砧砸砝破砷"],["afa1","砥砭砠砟砲祕祐祠祟祖神祝祗祚秤秣秧租秦秩秘窄窈站笆笑粉紡紗紋紊素索純紐紕級紜納紙紛缺罟羔翅翁耆耘耕耙耗耽耿胱脂胰脅胭胴脆胸胳脈能脊胼胯臭臬舀舐航舫舨般芻茫荒荔荊茸荐草茵茴荏茲茹茶茗荀茱茨荃"],["b040","虔蚊蚪蚓蚤蚩蚌蚣蚜衰衷袁袂衽衹記訐討訌訕訊託訓訖訏訑豈豺豹財貢起躬軒軔軏辱送逆迷退迺迴逃追逅迸邕郡郝郢酒配酌釘針釗釜釙閃院陣陡"],["b0a1","陛陝除陘陞隻飢馬骨高鬥鬲鬼乾偺偽停假偃偌做偉健偶偎偕偵側偷偏倏偯偭兜冕凰剪副勒務勘動匐匏匙匿區匾參曼商啪啦啄啞啡啃啊唱啖問啕唯啤唸售啜唬啣唳啁啗圈國圉域堅堊堆埠埤基堂堵執培夠奢娶婁婉婦婪婀"],["b140","娼婢婚婆婊孰寇寅寄寂宿密尉專將屠屜屝崇崆崎崛崖崢崑崩崔崙崤崧崗巢常帶帳帷康庸庶庵庾張強彗彬彩彫得徙從徘御徠徜恿患悉悠您惋悴惦悽"],["b1a1","情悻悵惜悼惘惕惆惟悸惚惇戚戛扈掠控捲掖探接捷捧掘措捱掩掉掃掛捫推掄授掙採掬排掏掀捻捩捨捺敝敖救教敗啟敏敘敕敔斜斛斬族旋旌旎晝晚晤晨晦晞曹勗望梁梯梢梓梵桿桶梱梧梗械梃棄梭梆梅梔條梨梟梡梂欲殺"],["b240","毫毬氫涎涼淳淙液淡淌淤添淺清淇淋涯淑涮淞淹涸混淵淅淒渚涵淚淫淘淪深淮淨淆淄涪淬涿淦烹焉焊烽烯爽牽犁猜猛猖猓猙率琅琊球理現琍瓠瓶"],["b2a1","瓷甜產略畦畢異疏痔痕疵痊痍皎盔盒盛眷眾眼眶眸眺硫硃硎祥票祭移窒窕笠笨笛第符笙笞笮粒粗粕絆絃統紮紹紼絀細紳組累終紲紱缽羞羚翌翎習耜聊聆脯脖脣脫脩脰脤舂舵舷舶船莎莞莘荸莢莖莽莫莒莊莓莉莠荷荻荼"],["b340","莆莧處彪蛇蛀蚶蛄蚵蛆蛋蚱蚯蛉術袞袈被袒袖袍袋覓規訪訝訣訥許設訟訛訢豉豚販責貫貨貪貧赧赦趾趺軛軟這逍通逗連速逝逐逕逞造透逢逖逛途"],["b3a1","部郭都酗野釵釦釣釧釭釩閉陪陵陳陸陰陴陶陷陬雀雪雩章竟頂頃魚鳥鹵鹿麥麻傢傍傅備傑傀傖傘傚最凱割剴創剩勞勝勛博厥啻喀喧啼喊喝喘喂喜喪喔喇喋喃喳單喟唾喲喚喻喬喱啾喉喫喙圍堯堪場堤堰報堡堝堠壹壺奠"],["b440","婷媚婿媒媛媧孳孱寒富寓寐尊尋就嵌嵐崴嵇巽幅帽幀幃幾廊廁廂廄弼彭復循徨惑惡悲悶惠愜愣惺愕惰惻惴慨惱愎惶愉愀愒戟扉掣掌描揀揩揉揆揍"],["b4a1","插揣提握揖揭揮捶援揪換摒揚揹敞敦敢散斑斐斯普晰晴晶景暑智晾晷曾替期朝棺棕棠棘棗椅棟棵森棧棹棒棲棣棋棍植椒椎棉棚楮棻款欺欽殘殖殼毯氮氯氬港游湔渡渲湧湊渠渥渣減湛湘渤湖湮渭渦湯渴湍渺測湃渝渾滋"],["b540","溉渙湎湣湄湲湩湟焙焚焦焰無然煮焜牌犄犀猶猥猴猩琺琪琳琢琥琵琶琴琯琛琦琨甥甦畫番痢痛痣痙痘痞痠登發皖皓皴盜睏短硝硬硯稍稈程稅稀窘"],["b5a1","窗窖童竣等策筆筐筒答筍筋筏筑粟粥絞結絨絕紫絮絲絡給絢絰絳善翔翕耋聒肅腕腔腋腑腎脹腆脾腌腓腴舒舜菩萃菸萍菠菅萋菁華菱菴著萊菰萌菌菽菲菊萸萎萄菜萇菔菟虛蛟蛙蛭蛔蛛蛤蛐蛞街裁裂袱覃視註詠評詞証詁"],["b640","詔詛詐詆訴診訶詖象貂貯貼貳貽賁費賀貴買貶貿貸越超趁跎距跋跚跑跌跛跆軻軸軼辜逮逵週逸進逶鄂郵鄉郾酣酥量鈔鈕鈣鈉鈞鈍鈐鈇鈑閔閏開閑"],["b6a1","間閒閎隊階隋陽隅隆隍陲隄雁雅雄集雇雯雲韌項順須飧飪飯飩飲飭馮馭黃黍黑亂傭債傲傳僅傾催傷傻傯僇剿剷剽募勦勤勢勣匯嗟嗨嗓嗦嗎嗜嗇嗑嗣嗤嗯嗚嗡嗅嗆嗥嗉園圓塞塑塘塗塚塔填塌塭塊塢塒塋奧嫁嫉嫌媾媽媼"],["b740","媳嫂媲嵩嵯幌幹廉廈弒彙徬微愚意慈感想愛惹愁愈慎慌慄慍愾愴愧愍愆愷戡戢搓搾搞搪搭搽搬搏搜搔損搶搖搗搆敬斟新暗暉暇暈暖暄暘暍會榔業"],["b7a1","楚楷楠楔極椰概楊楨楫楞楓楹榆楝楣楛歇歲毀殿毓毽溢溯滓溶滂源溝滇滅溥溘溼溺溫滑準溜滄滔溪溧溴煎煙煩煤煉照煜煬煦煌煥煞煆煨煖爺牒猷獅猿猾瑯瑚瑕瑟瑞瑁琿瑙瑛瑜當畸瘀痰瘁痲痱痺痿痴痳盞盟睛睫睦睞督"],["b840","睹睪睬睜睥睨睢矮碎碰碗碘碌碉硼碑碓硿祺祿禁萬禽稜稚稠稔稟稞窟窠筷節筠筮筧粱粳粵經絹綑綁綏絛置罩罪署義羨群聖聘肆肄腱腰腸腥腮腳腫"],["b8a1","腹腺腦舅艇蒂葷落萱葵葦葫葉葬葛萼萵葡董葩葭葆虞虜號蛹蜓蜈蜇蜀蛾蛻蜂蜃蜆蜊衙裟裔裙補裘裝裡裊裕裒覜解詫該詳試詩詰誇詼詣誠話誅詭詢詮詬詹詻訾詨豢貊貉賊資賈賄貲賃賂賅跡跟跨路跳跺跪跤跦躲較載軾輊"],["b940","辟農運遊道遂達逼違遐遇遏過遍遑逾遁鄒鄗酬酪酩釉鈷鉗鈸鈽鉀鈾鉛鉋鉤鉑鈴鉉鉍鉅鈹鈿鉚閘隘隔隕雍雋雉雊雷電雹零靖靴靶預頑頓頊頒頌飼飴"],["b9a1","飽飾馳馱馴髡鳩麂鼎鼓鼠僧僮僥僖僭僚僕像僑僱僎僩兢凳劃劂匱厭嗾嘀嘛嘗嗽嘔嘆嘉嘍嘎嗷嘖嘟嘈嘐嗶團圖塵塾境墓墊塹墅塽壽夥夢夤奪奩嫡嫦嫩嫗嫖嫘嫣孵寞寧寡寥實寨寢寤察對屢嶄嶇幛幣幕幗幔廓廖弊彆彰徹慇"],["ba40","愿態慷慢慣慟慚慘慵截撇摘摔撤摸摟摺摑摧搴摭摻敲斡旗旖暢暨暝榜榨榕槁榮槓構榛榷榻榫榴槐槍榭槌榦槃榣歉歌氳漳演滾漓滴漩漾漠漬漏漂漢"],["baa1","滿滯漆漱漸漲漣漕漫漯澈漪滬漁滲滌滷熔熙煽熊熄熒爾犒犖獄獐瑤瑣瑪瑰瑭甄疑瘧瘍瘋瘉瘓盡監瞄睽睿睡磁碟碧碳碩碣禎福禍種稱窪窩竭端管箕箋筵算箝箔箏箸箇箄粹粽精綻綰綜綽綾綠緊綴網綱綺綢綿綵綸維緒緇綬"],["bb40","罰翠翡翟聞聚肇腐膀膏膈膊腿膂臧臺與舔舞艋蓉蒿蓆蓄蒙蒞蒲蒜蓋蒸蓀蓓蒐蒼蓑蓊蜿蜜蜻蜢蜥蜴蜘蝕蜷蜩裳褂裴裹裸製裨褚裯誦誌語誣認誡誓誤"],["bba1","說誥誨誘誑誚誧豪貍貌賓賑賒赫趙趕跼輔輒輕輓辣遠遘遜遣遙遞遢遝遛鄙鄘鄞酵酸酷酴鉸銀銅銘銖鉻銓銜銨鉼銑閡閨閩閣閥閤隙障際雌雒需靼鞅韶頗領颯颱餃餅餌餉駁骯骰髦魁魂鳴鳶鳳麼鼻齊億儀僻僵價儂儈儉儅凜"],["bc40","劇劈劉劍劊勰厲嘮嘻嘹嘲嘿嘴嘩噓噎噗噴嘶嘯嘰墀墟增墳墜墮墩墦奭嬉嫻嬋嫵嬌嬈寮寬審寫層履嶝嶔幢幟幡廢廚廟廝廣廠彈影德徵慶慧慮慝慕憂"],["bca1","慼慰慫慾憧憐憫憎憬憚憤憔憮戮摩摯摹撞撲撈撐撰撥撓撕撩撒撮播撫撚撬撙撢撳敵敷數暮暫暴暱樣樟槨樁樞標槽模樓樊槳樂樅槭樑歐歎殤毅毆漿潼澄潑潦潔澆潭潛潸潮澎潺潰潤澗潘滕潯潠潟熟熬熱熨牖犛獎獗瑩璋璃"],["bd40","瑾璀畿瘠瘩瘟瘤瘦瘡瘢皚皺盤瞎瞇瞌瞑瞋磋磅確磊碾磕碼磐稿稼穀稽稷稻窯窮箭箱範箴篆篇篁箠篌糊締練緯緻緘緬緝編緣線緞緩綞緙緲緹罵罷羯"],["bda1","翩耦膛膜膝膠膚膘蔗蔽蔚蓮蔬蔭蔓蔑蔣蔡蔔蓬蔥蓿蔆螂蝴蝶蝠蝦蝸蝨蝙蝗蝌蝓衛衝褐複褒褓褕褊誼諒談諄誕請諸課諉諂調誰論諍誶誹諛豌豎豬賠賞賦賤賬賭賢賣賜質賡赭趟趣踫踐踝踢踏踩踟踡踞躺輝輛輟輩輦輪輜輞"],["be40","輥適遮遨遭遷鄰鄭鄧鄱醇醉醋醃鋅銻銷鋪銬鋤鋁銳銼鋒鋇鋰銲閭閱霄霆震霉靠鞍鞋鞏頡頫頜颳養餓餒餘駝駐駟駛駑駕駒駙骷髮髯鬧魅魄魷魯鴆鴉"],["bea1","鴃麩麾黎墨齒儒儘儔儐儕冀冪凝劑劓勳噙噫噹噩噤噸噪器噥噱噯噬噢噶壁墾壇壅奮嬝嬴學寰導彊憲憑憩憊懍憶憾懊懈戰擅擁擋撻撼據擄擇擂操撿擒擔撾整曆曉暹曄曇暸樽樸樺橙橫橘樹橄橢橡橋橇樵機橈歙歷氅濂澱澡"],["bf40","濃澤濁澧澳激澹澶澦澠澴熾燉燐燒燈燕熹燎燙燜燃燄獨璜璣璘璟璞瓢甌甍瘴瘸瘺盧盥瞠瞞瞟瞥磨磚磬磧禦積穎穆穌穋窺篙簑築篤篛篡篩篦糕糖縊"],["bfa1","縑縈縛縣縞縝縉縐罹羲翰翱翮耨膳膩膨臻興艘艙蕊蕙蕈蕨蕩蕃蕉蕭蕪蕞螃螟螞螢融衡褪褲褥褫褡親覦諦諺諫諱謀諜諧諮諾謁謂諷諭諳諶諼豫豭貓賴蹄踱踴蹂踹踵輻輯輸輳辨辦遵遴選遲遼遺鄴醒錠錶鋸錳錯錢鋼錫錄錚"],["c040","錐錦錡錕錮錙閻隧隨險雕霎霑霖霍霓霏靛靜靦鞘頰頸頻頷頭頹頤餐館餞餛餡餚駭駢駱骸骼髻髭鬨鮑鴕鴣鴦鴨鴒鴛默黔龍龜優償儡儲勵嚎嚀嚐嚅嚇"],["c0a1","嚏壕壓壑壎嬰嬪嬤孺尷屨嶼嶺嶽嶸幫彌徽應懂懇懦懋戲戴擎擊擘擠擰擦擬擱擢擭斂斃曙曖檀檔檄檢檜櫛檣橾檗檐檠歜殮毚氈濘濱濟濠濛濤濫濯澀濬濡濩濕濮濰燧營燮燦燥燭燬燴燠爵牆獰獲璩環璦璨癆療癌盪瞳瞪瞰瞬"],["c140","瞧瞭矯磷磺磴磯礁禧禪穗窿簇簍篾篷簌篠糠糜糞糢糟糙糝縮績繆縷縲繃縫總縱繅繁縴縹繈縵縿縯罄翳翼聱聲聰聯聳臆臃膺臂臀膿膽臉膾臨舉艱薪"],["c1a1","薄蕾薜薑薔薯薛薇薨薊虧蟀蟑螳蟒蟆螫螻螺蟈蟋褻褶襄褸褽覬謎謗謙講謊謠謝謄謐豁谿豳賺賽購賸賻趨蹉蹋蹈蹊轄輾轂轅輿避遽還邁邂邀鄹醣醞醜鍍鎂錨鍵鍊鍥鍋錘鍾鍬鍛鍰鍚鍔闊闋闌闈闆隱隸雖霜霞鞠韓顆颶餵騁"],["c240","駿鮮鮫鮪鮭鴻鴿麋黏點黜黝黛鼾齋叢嚕嚮壙壘嬸彝懣戳擴擲擾攆擺擻擷斷曜朦檳檬櫃檻檸櫂檮檯歟歸殯瀉瀋濾瀆濺瀑瀏燻燼燾燸獷獵璧璿甕癖癘"],["c2a1","癒瞽瞿瞻瞼礎禮穡穢穠竄竅簫簧簪簞簣簡糧織繕繞繚繡繒繙罈翹翻職聶臍臏舊藏薩藍藐藉薰薺薹薦蟯蟬蟲蟠覆覲觴謨謹謬謫豐贅蹙蹣蹦蹤蹟蹕軀轉轍邇邃邈醫醬釐鎔鎊鎖鎢鎳鎮鎬鎰鎘鎚鎗闔闖闐闕離雜雙雛雞霤鞣鞦"],["c340","鞭韹額顏題顎顓颺餾餿餽餮馥騎髁鬃鬆魏魎魍鯊鯉鯽鯈鯀鵑鵝鵠黠鼕鼬儳嚥壞壟壢寵龐廬懲懷懶懵攀攏曠曝櫥櫝櫚櫓瀛瀟瀨瀚瀝瀕瀘爆爍牘犢獸"],["c3a1","獺璽瓊瓣疇疆癟癡矇礙禱穫穩簾簿簸簽簷籀繫繭繹繩繪羅繳羶羹羸臘藩藝藪藕藤藥藷蟻蠅蠍蟹蟾襠襟襖襞譁譜識證譚譎譏譆譙贈贊蹼蹲躇蹶蹬蹺蹴轔轎辭邊邋醱醮鏡鏑鏟鏃鏈鏜鏝鏖鏢鏍鏘鏤鏗鏨關隴難霪霧靡韜韻類"],["c440","願顛颼饅饉騖騙鬍鯨鯧鯖鯛鶉鵡鵲鵪鵬麒麗麓麴勸嚨嚷嚶嚴嚼壤孀孃孽寶巉懸懺攘攔攙曦朧櫬瀾瀰瀲爐獻瓏癢癥礦礪礬礫竇競籌籃籍糯糰辮繽繼"],["c4a1","纂罌耀臚艦藻藹蘑藺蘆蘋蘇蘊蠔蠕襤覺觸議譬警譯譟譫贏贍躉躁躅躂醴釋鐘鐃鏽闡霰飄饒饑馨騫騰騷騵鰓鰍鹹麵黨鼯齟齣齡儷儸囁囀囂夔屬巍懼懾攝攜斕曩櫻欄櫺殲灌爛犧瓖瓔癩矓籐纏續羼蘗蘭蘚蠣蠢蠡蠟襪襬覽譴"],["c540","護譽贓躊躍躋轟辯醺鐮鐳鐵鐺鐸鐲鐫闢霸霹露響顧顥饗驅驃驀騾髏魔魑鰭鰥鶯鶴鷂鶸麝黯鼙齜齦齧儼儻囈囊囉孿巔巒彎懿攤權歡灑灘玀瓤疊癮癬"],["c5a1","禳籠籟聾聽臟襲襯觼讀贖贗躑躓轡酈鑄鑑鑒霽霾韃韁顫饕驕驍髒鬚鱉鰱鰾鰻鷓鷗鼴齬齪龔囌巖戀攣攫攪曬欐瓚竊籤籣籥纓纖纔臢蘸蘿蠱變邐邏鑣鑠鑤靨顯饜驚驛驗髓體髑鱔鱗鱖鷥麟黴囑壩攬灞癱癲矗罐羈蠶蠹衢讓讒"],["c640","讖艷贛釀鑪靂靈靄韆顰驟鬢魘鱟鷹鷺鹼鹽鼇齷齲廳欖灣籬籮蠻觀躡釁鑲鑰顱饞髖鬣黌灤矚讚鑷韉驢驥纜讜躪釅鑽鑾鑼鱷鱸黷豔鑿鸚爨驪鬱鸛鸞籲"],["c940","乂乜凵匚厂万丌乇亍囗兀屮彳丏冇与丮亓仂仉仈冘勼卬厹圠夃夬尐巿旡殳毌气爿丱丼仨仜仩仡仝仚刌匜卌圢圣夗夯宁宄尒尻屴屳帄庀庂忉戉扐氕"],["c9a1","氶汃氿氻犮犰玊禸肊阞伎优伬仵伔仱伀价伈伝伂伅伢伓伄仴伒冱刓刉刐劦匢匟卍厊吇囡囟圮圪圴夼妀奼妅奻奾奷奿孖尕尥屼屺屻屾巟幵庄异弚彴忕忔忏扜扞扤扡扦扢扙扠扚扥旯旮朾朹朸朻机朿朼朳氘汆汒汜汏汊汔汋"],["ca40","汌灱牞犴犵玎甪癿穵网艸艼芀艽艿虍襾邙邗邘邛邔阢阤阠阣佖伻佢佉体佤伾佧佒佟佁佘伭伳伿佡冏冹刜刞刡劭劮匉卣卲厎厏吰吷吪呔呅吙吜吥吘"],["caa1","吽呏呁吨吤呇囮囧囥坁坅坌坉坋坒夆奀妦妘妠妗妎妢妐妏妧妡宎宒尨尪岍岏岈岋岉岒岊岆岓岕巠帊帎庋庉庌庈庍弅弝彸彶忒忑忐忭忨忮忳忡忤忣忺忯忷忻怀忴戺抃抌抎抏抔抇扱扻扺扰抁抈扷扽扲扴攷旰旴旳旲旵杅杇"],["cb40","杙杕杌杈杝杍杚杋毐氙氚汸汧汫沄沋沏汱汯汩沚汭沇沕沜汦汳汥汻沎灴灺牣犿犽狃狆狁犺狅玕玗玓玔玒町甹疔疕皁礽耴肕肙肐肒肜芐芏芅芎芑芓"],["cba1","芊芃芄豸迉辿邟邡邥邞邧邠阰阨阯阭丳侘佼侅佽侀侇佶佴侉侄佷佌侗佪侚佹侁佸侐侜侔侞侒侂侕佫佮冞冼冾刵刲刳剆刱劼匊匋匼厒厔咇呿咁咑咂咈呫呺呾呥呬呴呦咍呯呡呠咘呣呧呤囷囹坯坲坭坫坱坰坶垀坵坻坳坴坢"],["cc40","坨坽夌奅妵妺姏姎妲姌姁妶妼姃姖妱妽姀姈妴姇孢孥宓宕屄屇岮岤岠岵岯岨岬岟岣岭岢岪岧岝岥岶岰岦帗帔帙弨弢弣弤彔徂彾彽忞忥怭怦怙怲怋"],["cca1","怴怊怗怳怚怞怬怢怍怐怮怓怑怌怉怜戔戽抭抴拑抾抪抶拊抮抳抯抻抩抰抸攽斨斻昉旼昄昒昈旻昃昋昍昅旽昑昐曶朊枅杬枎枒杶杻枘枆构杴枍枌杺枟枑枙枃杽极杸杹枔欥殀歾毞氝沓泬泫泮泙沶泔沭泧沷泐泂沺泃泆泭泲"],["cd40","泒泝沴沊沝沀泞泀洰泍泇沰泹泏泩泑炔炘炅炓炆炄炑炖炂炚炃牪狖狋狘狉狜狒狔狚狌狑玤玡玭玦玢玠玬玝瓝瓨甿畀甾疌疘皯盳盱盰盵矸矼矹矻矺"],["cda1","矷祂礿秅穸穻竻籵糽耵肏肮肣肸肵肭舠芠苀芫芚芘芛芵芧芮芼芞芺芴芨芡芩苂芤苃芶芢虰虯虭虮豖迒迋迓迍迖迕迗邲邴邯邳邰阹阽阼阺陃俍俅俓侲俉俋俁俔俜俙侻侳俛俇俖侺俀侹俬剄剉勀勂匽卼厗厖厙厘咺咡咭咥哏"],["ce40","哃茍咷咮哖咶哅哆咠呰咼咢咾呲哞咰垵垞垟垤垌垗垝垛垔垘垏垙垥垚垕壴复奓姡姞姮娀姱姝姺姽姼姶姤姲姷姛姩姳姵姠姾姴姭宨屌峐峘峌峗峋峛"],["cea1","峞峚峉峇峊峖峓峔峏峈峆峎峟峸巹帡帢帣帠帤庰庤庢庛庣庥弇弮彖徆怷怹恔恲恞恅恓恇恉恛恌恀恂恟怤恄恘恦恮扂扃拏挍挋拵挎挃拫拹挏挌拸拶挀挓挔拺挕拻拰敁敃斪斿昶昡昲昵昜昦昢昳昫昺昝昴昹昮朏朐柁柲柈枺"],["cf40","柜枻柸柘柀枷柅柫柤柟枵柍枳柷柶柮柣柂枹柎柧柰枲柼柆柭柌枮柦柛柺柉柊柃柪柋欨殂殄殶毖毘毠氠氡洨洴洭洟洼洿洒洊泚洳洄洙洺洚洑洀洝浂"],["cfa1","洁洘洷洃洏浀洇洠洬洈洢洉洐炷炟炾炱炰炡炴炵炩牁牉牊牬牰牳牮狊狤狨狫狟狪狦狣玅珌珂珈珅玹玶玵玴珫玿珇玾珃珆玸珋瓬瓮甮畇畈疧疪癹盄眈眃眄眅眊盷盻盺矧矨砆砑砒砅砐砏砎砉砃砓祊祌祋祅祄秕种秏秖秎窀"],["d040","穾竑笀笁籺籸籹籿粀粁紃紈紁罘羑羍羾耇耎耏耔耷胘胇胠胑胈胂胐胅胣胙胜胊胕胉胏胗胦胍臿舡芔苙苾苹茇苨茀苕茺苫苖苴苬苡苲苵茌苻苶苰苪"],["d0a1","苤苠苺苳苭虷虴虼虳衁衎衧衪衩觓訄訇赲迣迡迮迠郱邽邿郕郅邾郇郋郈釔釓陔陏陑陓陊陎倞倅倇倓倢倰倛俵俴倳倷倬俶俷倗倜倠倧倵倯倱倎党冔冓凊凄凅凈凎剡剚剒剞剟剕剢勍匎厞唦哢唗唒哧哳哤唚哿唄唈哫唑唅哱"],["d140","唊哻哷哸哠唎唃唋圁圂埌堲埕埒垺埆垽垼垸垶垿埇埐垹埁夎奊娙娖娭娮娕娏娗娊娞娳孬宧宭宬尃屖屔峬峿峮峱峷崀峹帩帨庨庮庪庬弳弰彧恝恚恧"],["d1a1","恁悢悈悀悒悁悝悃悕悛悗悇悜悎戙扆拲挐捖挬捄捅挶捃揤挹捋捊挼挩捁挴捘捔捙挭捇挳捚捑挸捗捀捈敊敆旆旃旄旂晊晟晇晑朒朓栟栚桉栲栳栻桋桏栖栱栜栵栫栭栯桎桄栴栝栒栔栦栨栮桍栺栥栠欬欯欭欱欴歭肂殈毦毤"],["d240","毨毣毢毧氥浺浣浤浶洍浡涒浘浢浭浯涑涍淯浿涆浞浧浠涗浰浼浟涂涘洯浨涋浾涀涄洖涃浻浽浵涐烜烓烑烝烋缹烢烗烒烞烠烔烍烅烆烇烚烎烡牂牸"],["d2a1","牷牶猀狺狴狾狶狳狻猁珓珙珥珖玼珧珣珩珜珒珛珔珝珚珗珘珨瓞瓟瓴瓵甡畛畟疰痁疻痄痀疿疶疺皊盉眝眛眐眓眒眣眑眕眙眚眢眧砣砬砢砵砯砨砮砫砡砩砳砪砱祔祛祏祜祓祒祑秫秬秠秮秭秪秜秞秝窆窉窅窋窌窊窇竘笐"],["d340","笄笓笅笏笈笊笎笉笒粄粑粊粌粈粍粅紞紝紑紎紘紖紓紟紒紏紌罜罡罞罠罝罛羖羒翃翂翀耖耾耹胺胲胹胵脁胻脀舁舯舥茳茭荄茙荑茥荖茿荁茦茜茢"],["d3a1","荂荎茛茪茈茼荍茖茤茠茷茯茩荇荅荌荓茞茬荋茧荈虓虒蚢蚨蚖蚍蚑蚞蚇蚗蚆蚋蚚蚅蚥蚙蚡蚧蚕蚘蚎蚝蚐蚔衃衄衭衵衶衲袀衱衿衯袃衾衴衼訒豇豗豻貤貣赶赸趵趷趶軑軓迾迵适迿迻逄迼迶郖郠郙郚郣郟郥郘郛郗郜郤酐"],["d440","酎酏釕釢釚陜陟隼飣髟鬯乿偰偪偡偞偠偓偋偝偲偈偍偁偛偊偢倕偅偟偩偫偣偤偆偀偮偳偗偑凐剫剭剬剮勖勓匭厜啵啶唼啍啐唴唪啑啢唶唵唰啒啅"],["d4a1","唌唲啥啎唹啈唭唻啀啋圊圇埻堔埢埶埜埴堀埭埽堈埸堋埳埏堇埮埣埲埥埬埡堎埼堐埧堁堌埱埩埰堍堄奜婠婘婕婧婞娸娵婭婐婟婥婬婓婤婗婃婝婒婄婛婈媎娾婍娹婌婰婩婇婑婖婂婜孲孮寁寀屙崞崋崝崚崠崌崨崍崦崥崏"],["d540","崰崒崣崟崮帾帴庱庴庹庲庳弶弸徛徖徟悊悐悆悾悰悺惓惔惏惤惙惝惈悱惛悷惊悿惃惍惀挲捥掊掂捽掽掞掭掝掗掫掎捯掇掐据掯捵掜捭掮捼掤挻掟"],["d5a1","捸掅掁掑掍捰敓旍晥晡晛晙晜晢朘桹梇梐梜桭桮梮梫楖桯梣梬梩桵桴梲梏桷梒桼桫桲梪梀桱桾梛梖梋梠梉梤桸桻梑梌梊桽欶欳欷欸殑殏殍殎殌氪淀涫涴涳湴涬淩淢涷淶淔渀淈淠淟淖涾淥淜淝淛淴淊涽淭淰涺淕淂淏淉"],["d640","淐淲淓淽淗淍淣涻烺焍烷焗烴焌烰焄烳焐烼烿焆焓焀烸烶焋焂焎牾牻牼牿猝猗猇猑猘猊猈狿猏猞玈珶珸珵琄琁珽琇琀珺珼珿琌琋珴琈畤畣痎痒痏"],["d6a1","痋痌痑痐皏皉盓眹眯眭眱眲眴眳眽眥眻眵硈硒硉硍硊硌砦硅硐祤祧祩祪祣祫祡离秺秸秶秷窏窔窐笵筇笴笥笰笢笤笳笘笪笝笱笫笭笯笲笸笚笣粔粘粖粣紵紽紸紶紺絅紬紩絁絇紾紿絊紻紨罣羕羜羝羛翊翋翍翐翑翇翏翉耟"],["d740","耞耛聇聃聈脘脥脙脛脭脟脬脞脡脕脧脝脢舑舸舳舺舴舲艴莐莣莨莍荺荳莤荴莏莁莕莙荵莔莩荽莃莌莝莛莪莋荾莥莯莈莗莰荿莦莇莮荶莚虙虖蚿蚷"],["d7a1","蛂蛁蛅蚺蚰蛈蚹蚳蚸蛌蚴蚻蚼蛃蚽蚾衒袉袕袨袢袪袚袑袡袟袘袧袙袛袗袤袬袌袓袎覂觖觙觕訰訧訬訞谹谻豜豝豽貥赽赻赹趼跂趹趿跁軘軞軝軜軗軠軡逤逋逑逜逌逡郯郪郰郴郲郳郔郫郬郩酖酘酚酓酕釬釴釱釳釸釤釹釪"],["d840","釫釷釨釮镺閆閈陼陭陫陱陯隿靪頄飥馗傛傕傔傞傋傣傃傌傎傝偨傜傒傂傇兟凔匒匑厤厧喑喨喥喭啷噅喢喓喈喏喵喁喣喒喤啽喌喦啿喕喡喎圌堩堷"],["d8a1","堙堞堧堣堨埵塈堥堜堛堳堿堶堮堹堸堭堬堻奡媯媔媟婺媢媞婸媦婼媥媬媕媮娷媄媊媗媃媋媩婻婽媌媜媏媓媝寪寍寋寔寑寊寎尌尰崷嵃嵫嵁嵋崿崵嵑嵎嵕崳崺嵒崽崱嵙嵂崹嵉崸崼崲崶嵀嵅幄幁彘徦徥徫惉悹惌惢惎惄愔"],["d940","惲愊愖愅惵愓惸惼惾惁愃愘愝愐惿愄愋扊掔掱掰揎揥揨揯揃撝揳揊揠揶揕揲揵摡揟掾揝揜揄揘揓揂揇揌揋揈揰揗揙攲敧敪敤敜敨敥斌斝斞斮旐旒"],["d9a1","晼晬晻暀晱晹晪晲朁椌棓椄棜椪棬棪棱椏棖棷棫棤棶椓椐棳棡椇棌椈楰梴椑棯棆椔棸棐棽棼棨椋椊椗棎棈棝棞棦棴棑椆棔棩椕椥棇欹欻欿欼殔殗殙殕殽毰毲毳氰淼湆湇渟湉溈渼渽湅湢渫渿湁湝湳渜渳湋湀湑渻渃渮湞"],["da40","湨湜湡渱渨湠湱湫渹渢渰湓湥渧湸湤湷湕湹湒湦渵渶湚焠焞焯烻焮焱焣焥焢焲焟焨焺焛牋牚犈犉犆犅犋猒猋猰猢猱猳猧猲猭猦猣猵猌琮琬琰琫琖"],["daa1","琚琡琭琱琤琣琝琩琠琲瓻甯畯畬痧痚痡痦痝痟痤痗皕皒盚睆睇睄睍睅睊睎睋睌矞矬硠硤硥硜硭硱硪确硰硩硨硞硢祴祳祲祰稂稊稃稌稄窙竦竤筊笻筄筈筌筎筀筘筅粢粞粨粡絘絯絣絓絖絧絪絏絭絜絫絒絔絩絑絟絎缾缿罥"],["db40","罦羢羠羡翗聑聏聐胾胔腃腊腒腏腇脽腍脺臦臮臷臸臹舄舼舽舿艵茻菏菹萣菀菨萒菧菤菼菶萐菆菈菫菣莿萁菝菥菘菿菡菋菎菖菵菉萉萏菞萑萆菂菳"],["dba1","菕菺菇菑菪萓菃菬菮菄菻菗菢萛菛菾蛘蛢蛦蛓蛣蛚蛪蛝蛫蛜蛬蛩蛗蛨蛑衈衖衕袺裗袹袸裀袾袶袼袷袽袲褁裉覕覘覗觝觚觛詎詍訹詙詀詗詘詄詅詒詈詑詊詌詏豟貁貀貺貾貰貹貵趄趀趉跘跓跍跇跖跜跏跕跙跈跗跅軯軷軺"],["dc40","軹軦軮軥軵軧軨軶軫軱軬軴軩逭逴逯鄆鄬鄄郿郼鄈郹郻鄁鄀鄇鄅鄃酡酤酟酢酠鈁鈊鈥鈃鈚鈦鈏鈌鈀鈒釿釽鈆鈄鈧鈂鈜鈤鈙鈗鈅鈖镻閍閌閐隇陾隈"],["dca1","隉隃隀雂雈雃雱雰靬靰靮頇颩飫鳦黹亃亄亶傽傿僆傮僄僊傴僈僂傰僁傺傱僋僉傶傸凗剺剸剻剼嗃嗛嗌嗐嗋嗊嗝嗀嗔嗄嗩喿嗒喍嗏嗕嗢嗖嗈嗲嗍嗙嗂圔塓塨塤塏塍塉塯塕塎塝塙塥塛堽塣塱壼嫇嫄嫋媺媸媱媵媰媿嫈媻嫆"],["dd40","媷嫀嫊媴媶嫍媹媐寖寘寙尟尳嵱嵣嵊嵥嵲嵬嵞嵨嵧嵢巰幏幎幊幍幋廅廌廆廋廇彀徯徭惷慉慊愫慅愶愲愮慆愯慏愩慀戠酨戣戥戤揅揱揫搐搒搉搠搤"],["dda1","搳摃搟搕搘搹搷搢搣搌搦搰搨摁搵搯搊搚摀搥搧搋揧搛搮搡搎敯斒旓暆暌暕暐暋暊暙暔晸朠楦楟椸楎楢楱椿楅楪椹楂楗楙楺楈楉椵楬椳椽楥棰楸椴楩楀楯楄楶楘楁楴楌椻楋椷楜楏楑椲楒椯楻椼歆歅歃歂歈歁殛嗀毻毼"],["de40","毹毷毸溛滖滈溏滀溟溓溔溠溱溹滆滒溽滁溞滉溷溰滍溦滏溲溾滃滜滘溙溒溎溍溤溡溿溳滐滊溗溮溣煇煔煒煣煠煁煝煢煲煸煪煡煂煘煃煋煰煟煐煓"],["dea1","煄煍煚牏犍犌犑犐犎猼獂猻猺獀獊獉瑄瑊瑋瑒瑑瑗瑀瑏瑐瑎瑂瑆瑍瑔瓡瓿瓾瓽甝畹畷榃痯瘏瘃痷痾痼痹痸瘐痻痶痭痵痽皙皵盝睕睟睠睒睖睚睩睧睔睙睭矠碇碚碔碏碄碕碅碆碡碃硹碙碀碖硻祼禂祽祹稑稘稙稒稗稕稢稓"],["df40","稛稐窣窢窞竫筦筤筭筴筩筲筥筳筱筰筡筸筶筣粲粴粯綈綆綀綍絿綅絺綎絻綃絼綌綔綄絽綒罭罫罧罨罬羦羥羧翛翜耡腤腠腷腜腩腛腢腲朡腞腶腧腯"],["dfa1","腄腡舝艉艄艀艂艅蓱萿葖葶葹蒏蒍葥葑葀蒆葧萰葍葽葚葙葴葳葝蔇葞萷萺萴葺葃葸萲葅萩菙葋萯葂萭葟葰萹葎葌葒葯蓅蒎萻葇萶萳葨葾葄萫葠葔葮葐蜋蜄蛷蜌蛺蛖蛵蝍蛸蜎蜉蜁蛶蜍蜅裖裋裍裎裞裛裚裌裐覅覛觟觥觤"],["e040","觡觠觢觜触詶誆詿詡訿詷誂誄詵誃誁詴詺谼豋豊豥豤豦貆貄貅賌赨赩趑趌趎趏趍趓趔趐趒跰跠跬跱跮跐跩跣跢跧跲跫跴輆軿輁輀輅輇輈輂輋遒逿"],["e0a1","遄遉逽鄐鄍鄏鄑鄖鄔鄋鄎酮酯鉈鉒鈰鈺鉦鈳鉥鉞銃鈮鉊鉆鉭鉬鉏鉠鉧鉯鈶鉡鉰鈱鉔鉣鉐鉲鉎鉓鉌鉖鈲閟閜閞閛隒隓隑隗雎雺雽雸雵靳靷靸靲頏頍頎颬飶飹馯馲馰馵骭骫魛鳪鳭鳧麀黽僦僔僗僨僳僛僪僝僤僓僬僰僯僣僠"],["e140","凘劀劁勩勫匰厬嘧嘕嘌嘒嗼嘏嘜嘁嘓嘂嗺嘝嘄嗿嗹墉塼墐墘墆墁塿塴墋塺墇墑墎塶墂墈塻墔墏壾奫嫜嫮嫥嫕嫪嫚嫭嫫嫳嫢嫠嫛嫬嫞嫝嫙嫨嫟孷寠"],["e1a1","寣屣嶂嶀嵽嶆嵺嶁嵷嶊嶉嶈嵾嵼嶍嵹嵿幘幙幓廘廑廗廎廜廕廙廒廔彄彃彯徶愬愨慁慞慱慳慒慓慲慬憀慴慔慺慛慥愻慪慡慖戩戧戫搫摍摛摝摴摶摲摳摽摵摦撦摎撂摞摜摋摓摠摐摿搿摬摫摙摥摷敳斠暡暠暟朅朄朢榱榶槉"],["e240","榠槎榖榰榬榼榑榙榎榧榍榩榾榯榿槄榽榤槔榹槊榚槏榳榓榪榡榞槙榗榐槂榵榥槆歊歍歋殞殟殠毃毄毾滎滵滱漃漥滸漷滻漮漉潎漙漚漧漘漻漒滭漊"],["e2a1","漶潳滹滮漭潀漰漼漵滫漇漎潃漅滽滶漹漜滼漺漟漍漞漈漡熇熐熉熀熅熂熏煻熆熁熗牄牓犗犕犓獃獍獑獌瑢瑳瑱瑵瑲瑧瑮甀甂甃畽疐瘖瘈瘌瘕瘑瘊瘔皸瞁睼瞅瞂睮瞀睯睾瞃碲碪碴碭碨硾碫碞碥碠碬碢碤禘禊禋禖禕禔禓"],["e340","禗禈禒禐稫穊稰稯稨稦窨窫窬竮箈箜箊箑箐箖箍箌箛箎箅箘劄箙箤箂粻粿粼粺綧綷緂綣綪緁緀緅綝緎緄緆緋緌綯綹綖綼綟綦綮綩綡緉罳翢翣翥翞"],["e3a1","耤聝聜膉膆膃膇膍膌膋舕蒗蒤蒡蒟蒺蓎蓂蒬蒮蒫蒹蒴蓁蓍蒪蒚蒱蓐蒝蒧蒻蒢蒔蓇蓌蒛蒩蒯蒨蓖蒘蒶蓏蒠蓗蓔蓒蓛蒰蒑虡蜳蜣蜨蝫蝀蜮蜞蜡蜙蜛蝃蜬蝁蜾蝆蜠蜲蜪蜭蜼蜒蜺蜱蜵蝂蜦蜧蜸蜤蜚蜰蜑裷裧裱裲裺裾裮裼裶裻"],["e440","裰裬裫覝覡覟覞觩觫觨誫誙誋誒誏誖谽豨豩賕賏賗趖踉踂跿踍跽踊踃踇踆踅跾踀踄輐輑輎輍鄣鄜鄠鄢鄟鄝鄚鄤鄡鄛酺酲酹酳銥銤鉶銛鉺銠銔銪銍"],["e4a1","銦銚銫鉹銗鉿銣鋮銎銂銕銢鉽銈銡銊銆銌銙銧鉾銇銩銝銋鈭隞隡雿靘靽靺靾鞃鞀鞂靻鞄鞁靿韎韍頖颭颮餂餀餇馝馜駃馹馻馺駂馽駇骱髣髧鬾鬿魠魡魟鳱鳲鳵麧僿儃儰僸儆儇僶僾儋儌僽儊劋劌勱勯噈噂噌嘵噁噊噉噆噘"],["e540","噚噀嘳嘽嘬嘾嘸嘪嘺圚墫墝墱墠墣墯墬墥墡壿嫿嫴嫽嫷嫶嬃嫸嬂嫹嬁嬇嬅嬏屧嶙嶗嶟嶒嶢嶓嶕嶠嶜嶡嶚嶞幩幝幠幜緳廛廞廡彉徲憋憃慹憱憰憢憉"],["e5a1","憛憓憯憭憟憒憪憡憍慦憳戭摮摰撖撠撅撗撜撏撋撊撌撣撟摨撱撘敶敺敹敻斲斳暵暰暩暲暷暪暯樀樆樗槥槸樕槱槤樠槿槬槢樛樝槾樧槲槮樔槷槧橀樈槦槻樍槼槫樉樄樘樥樏槶樦樇槴樖歑殥殣殢殦氁氀毿氂潁漦潾澇濆澒"],["e640","澍澉澌潢潏澅潚澖潶潬澂潕潲潒潐潗澔澓潝漀潡潫潽潧澐潓澋潩潿澕潣潷潪潻熲熯熛熰熠熚熩熵熝熥熞熤熡熪熜熧熳犘犚獘獒獞獟獠獝獛獡獚獙"],["e6a1","獢璇璉璊璆璁瑽璅璈瑼瑹甈甇畾瘥瘞瘙瘝瘜瘣瘚瘨瘛皜皝皞皛瞍瞏瞉瞈磍碻磏磌磑磎磔磈磃磄磉禚禡禠禜禢禛歶稹窲窴窳箷篋箾箬篎箯箹篊箵糅糈糌糋緷緛緪緧緗緡縃緺緦緶緱緰緮緟罶羬羰羭翭翫翪翬翦翨聤聧膣膟"],["e740","膞膕膢膙膗舖艏艓艒艐艎艑蔤蔻蔏蔀蔩蔎蔉蔍蔟蔊蔧蔜蓻蔫蓺蔈蔌蓴蔪蓲蔕蓷蓫蓳蓼蔒蓪蓩蔖蓾蔨蔝蔮蔂蓽蔞蓶蔱蔦蓧蓨蓰蓯蓹蔘蔠蔰蔋蔙蔯虢"],["e7a1","蝖蝣蝤蝷蟡蝳蝘蝔蝛蝒蝡蝚蝑蝞蝭蝪蝐蝎蝟蝝蝯蝬蝺蝮蝜蝥蝏蝻蝵蝢蝧蝩衚褅褌褔褋褗褘褙褆褖褑褎褉覢覤覣觭觰觬諏諆誸諓諑諔諕誻諗誾諀諅諘諃誺誽諙谾豍貏賥賟賙賨賚賝賧趠趜趡趛踠踣踥踤踮踕踛踖踑踙踦踧"],["e840","踔踒踘踓踜踗踚輬輤輘輚輠輣輖輗遳遰遯遧遫鄯鄫鄩鄪鄲鄦鄮醅醆醊醁醂醄醀鋐鋃鋄鋀鋙銶鋏鋱鋟鋘鋩鋗鋝鋌鋯鋂鋨鋊鋈鋎鋦鋍鋕鋉鋠鋞鋧鋑鋓"],["e8a1","銵鋡鋆銴镼閬閫閮閰隤隢雓霅霈霂靚鞊鞎鞈韐韏頞頝頦頩頨頠頛頧颲餈飺餑餔餖餗餕駜駍駏駓駔駎駉駖駘駋駗駌骳髬髫髳髲髱魆魃魧魴魱魦魶魵魰魨魤魬鳼鳺鳽鳿鳷鴇鴀鳹鳻鴈鴅鴄麃黓鼏鼐儜儓儗儚儑凞匴叡噰噠噮"],["e940","噳噦噣噭噲噞噷圜圛壈墽壉墿墺壂墼壆嬗嬙嬛嬡嬔嬓嬐嬖嬨嬚嬠嬞寯嶬嶱嶩嶧嶵嶰嶮嶪嶨嶲嶭嶯嶴幧幨幦幯廩廧廦廨廥彋徼憝憨憖懅憴懆懁懌憺"],["e9a1","憿憸憌擗擖擐擏擉撽撉擃擛擳擙攳敿敼斢曈暾曀曊曋曏暽暻暺曌朣樴橦橉橧樲橨樾橝橭橶橛橑樨橚樻樿橁橪橤橐橏橔橯橩橠樼橞橖橕橍橎橆歕歔歖殧殪殫毈毇氄氃氆澭濋澣濇澼濎濈潞濄澽澞濊澨瀄澥澮澺澬澪濏澿澸"],["ea40","澢濉澫濍澯澲澰燅燂熿熸燖燀燁燋燔燊燇燏熽燘熼燆燚燛犝犞獩獦獧獬獥獫獪瑿璚璠璔璒璕璡甋疀瘯瘭瘱瘽瘳瘼瘵瘲瘰皻盦瞚瞝瞡瞜瞛瞢瞣瞕瞙"],["eaa1","瞗磝磩磥磪磞磣磛磡磢磭磟磠禤穄穈穇窶窸窵窱窷篞篣篧篝篕篥篚篨篹篔篪篢篜篫篘篟糒糔糗糐糑縒縡縗縌縟縠縓縎縜縕縚縢縋縏縖縍縔縥縤罃罻罼罺羱翯耪耩聬膱膦膮膹膵膫膰膬膴膲膷膧臲艕艖艗蕖蕅蕫蕍蕓蕡蕘"],["eb40","蕀蕆蕤蕁蕢蕄蕑蕇蕣蔾蕛蕱蕎蕮蕵蕕蕧蕠薌蕦蕝蕔蕥蕬虣虥虤螛螏螗螓螒螈螁螖螘蝹螇螣螅螐螑螝螄螔螜螚螉褞褦褰褭褮褧褱褢褩褣褯褬褟觱諠"],["eba1","諢諲諴諵諝謔諤諟諰諈諞諡諨諿諯諻貑貒貐賵賮賱賰賳赬赮趥趧踳踾踸蹀蹅踶踼踽蹁踰踿躽輶輮輵輲輹輷輴遶遹遻邆郺鄳鄵鄶醓醐醑醍醏錧錞錈錟錆錏鍺錸錼錛錣錒錁鍆錭錎錍鋋錝鋺錥錓鋹鋷錴錂錤鋿錩錹錵錪錔錌"],["ec40","錋鋾錉錀鋻錖閼闍閾閹閺閶閿閵閽隩雔霋霒霐鞙鞗鞔韰韸頵頯頲餤餟餧餩馞駮駬駥駤駰駣駪駩駧骹骿骴骻髶髺髹髷鬳鮀鮅鮇魼魾魻鮂鮓鮒鮐魺鮕"],["eca1","魽鮈鴥鴗鴠鴞鴔鴩鴝鴘鴢鴐鴙鴟麈麆麇麮麭黕黖黺鼒鼽儦儥儢儤儠儩勴嚓嚌嚍嚆嚄嚃噾嚂噿嚁壖壔壏壒嬭嬥嬲嬣嬬嬧嬦嬯嬮孻寱寲嶷幬幪徾徻懃憵憼懧懠懥懤懨懞擯擩擣擫擤擨斁斀斶旚曒檍檖檁檥檉檟檛檡檞檇檓檎"],["ed40","檕檃檨檤檑橿檦檚檅檌檒歛殭氉濌澩濴濔濣濜濭濧濦濞濲濝濢濨燡燱燨燲燤燰燢獳獮獯璗璲璫璐璪璭璱璥璯甐甑甒甏疄癃癈癉癇皤盩瞵瞫瞲瞷瞶"],["eda1","瞴瞱瞨矰磳磽礂磻磼磲礅磹磾礄禫禨穜穛穖穘穔穚窾竀竁簅簏篲簀篿篻簎篴簋篳簂簉簃簁篸篽簆篰篱簐簊糨縭縼繂縳顈縸縪繉繀繇縩繌縰縻縶繄縺罅罿罾罽翴翲耬膻臄臌臊臅臇膼臩艛艚艜薃薀薏薧薕薠薋薣蕻薤薚薞"],["ee40","蕷蕼薉薡蕺蕸蕗薎薖薆薍薙薝薁薢薂薈薅蕹蕶薘薐薟虨螾螪螭蟅螰螬螹螵螼螮蟉蟃蟂蟌螷螯蟄蟊螴螶螿螸螽蟞螲褵褳褼褾襁襒褷襂覭覯覮觲觳謞"],["eea1","謘謖謑謅謋謢謏謒謕謇謍謈謆謜謓謚豏豰豲豱豯貕貔賹赯蹎蹍蹓蹐蹌蹇轃轀邅遾鄸醚醢醛醙醟醡醝醠鎡鎃鎯鍤鍖鍇鍼鍘鍜鍶鍉鍐鍑鍠鍭鎏鍌鍪鍹鍗鍕鍒鍏鍱鍷鍻鍡鍞鍣鍧鎀鍎鍙闇闀闉闃闅閷隮隰隬霠霟霘霝霙鞚鞡鞜"],["ef40","鞞鞝韕韔韱顁顄顊顉顅顃餥餫餬餪餳餲餯餭餱餰馘馣馡騂駺駴駷駹駸駶駻駽駾駼騃骾髾髽鬁髼魈鮚鮨鮞鮛鮦鮡鮥鮤鮆鮢鮠鮯鴳鵁鵧鴶鴮鴯鴱鴸鴰"],["efa1","鵅鵂鵃鴾鴷鵀鴽翵鴭麊麉麍麰黈黚黻黿鼤鼣鼢齔龠儱儭儮嚘嚜嚗嚚嚝嚙奰嬼屩屪巀幭幮懘懟懭懮懱懪懰懫懖懩擿攄擽擸攁攃擼斔旛曚曛曘櫅檹檽櫡櫆檺檶檷櫇檴檭歞毉氋瀇瀌瀍瀁瀅瀔瀎濿瀀濻瀦濼濷瀊爁燿燹爃燽獶"],["f040","璸瓀璵瓁璾璶璻瓂甔甓癜癤癙癐癓癗癚皦皽盬矂瞺磿礌礓礔礉礐礒礑禭禬穟簜簩簙簠簟簭簝簦簨簢簥簰繜繐繖繣繘繢繟繑繠繗繓羵羳翷翸聵臑臒"],["f0a1","臐艟艞薴藆藀藃藂薳薵薽藇藄薿藋藎藈藅薱薶藒蘤薸薷薾虩蟧蟦蟢蟛蟫蟪蟥蟟蟳蟤蟔蟜蟓蟭蟘蟣螤蟗蟙蠁蟴蟨蟝襓襋襏襌襆襐襑襉謪謧謣謳謰謵譇謯謼謾謱謥謷謦謶謮謤謻謽謺豂豵貙貘貗賾贄贂贀蹜蹢蹠蹗蹖蹞蹥蹧"],["f140","蹛蹚蹡蹝蹩蹔轆轇轈轋鄨鄺鄻鄾醨醥醧醯醪鎵鎌鎒鎷鎛鎝鎉鎧鎎鎪鎞鎦鎕鎈鎙鎟鎍鎱鎑鎲鎤鎨鎴鎣鎥闒闓闑隳雗雚巂雟雘雝霣霢霥鞬鞮鞨鞫鞤鞪"],["f1a1","鞢鞥韗韙韖韘韺顐顑顒颸饁餼餺騏騋騉騍騄騑騊騅騇騆髀髜鬈鬄鬅鬩鬵魊魌魋鯇鯆鯃鮿鯁鮵鮸鯓鮶鯄鮹鮽鵜鵓鵏鵊鵛鵋鵙鵖鵌鵗鵒鵔鵟鵘鵚麎麌黟鼁鼀鼖鼥鼫鼪鼩鼨齌齕儴儵劖勷厴嚫嚭嚦嚧嚪嚬壚壝壛夒嬽嬾嬿巃幰"],["f240","徿懻攇攐攍攉攌攎斄旞旝曞櫧櫠櫌櫑櫙櫋櫟櫜櫐櫫櫏櫍櫞歠殰氌瀙瀧瀠瀖瀫瀡瀢瀣瀩瀗瀤瀜瀪爌爊爇爂爅犥犦犤犣犡瓋瓅璷瓃甖癠矉矊矄矱礝礛"],["f2a1","礡礜礗礞禰穧穨簳簼簹簬簻糬糪繶繵繸繰繷繯繺繲繴繨罋罊羃羆羷翽翾聸臗臕艤艡艣藫藱藭藙藡藨藚藗藬藲藸藘藟藣藜藑藰藦藯藞藢蠀蟺蠃蟶蟷蠉蠌蠋蠆蟼蠈蟿蠊蠂襢襚襛襗襡襜襘襝襙覈覷覶觶譐譈譊譀譓譖譔譋譕"],["f340","譑譂譒譗豃豷豶貚贆贇贉趬趪趭趫蹭蹸蹳蹪蹯蹻軂轒轑轏轐轓辴酀鄿醰醭鏞鏇鏏鏂鏚鏐鏹鏬鏌鏙鎩鏦鏊鏔鏮鏣鏕鏄鏎鏀鏒鏧镽闚闛雡霩霫霬霨霦"],["f3a1","鞳鞷鞶韝韞韟顜顙顝顗颿颽颻颾饈饇饃馦馧騚騕騥騝騤騛騢騠騧騣騞騜騔髂鬋鬊鬎鬌鬷鯪鯫鯠鯞鯤鯦鯢鯰鯔鯗鯬鯜鯙鯥鯕鯡鯚鵷鶁鶊鶄鶈鵱鶀鵸鶆鶋鶌鵽鵫鵴鵵鵰鵩鶅鵳鵻鶂鵯鵹鵿鶇鵨麔麑黀黼鼭齀齁齍齖齗齘匷嚲"],["f440","嚵嚳壣孅巆巇廮廯忀忁懹攗攖攕攓旟曨曣曤櫳櫰櫪櫨櫹櫱櫮櫯瀼瀵瀯瀷瀴瀱灂瀸瀿瀺瀹灀瀻瀳灁爓爔犨獽獼璺皫皪皾盭矌矎矏矍矲礥礣礧礨礤礩"],["f4a1","禲穮穬穭竷籉籈籊籇籅糮繻繾纁纀羺翿聹臛臙舋艨艩蘢藿蘁藾蘛蘀藶蘄蘉蘅蘌藽蠙蠐蠑蠗蠓蠖襣襦覹觷譠譪譝譨譣譥譧譭趮躆躈躄轙轖轗轕轘轚邍酃酁醷醵醲醳鐋鐓鏻鐠鐏鐔鏾鐕鐐鐨鐙鐍鏵鐀鏷鐇鐎鐖鐒鏺鐉鏸鐊鏿"],["f540","鏼鐌鏶鐑鐆闞闠闟霮霯鞹鞻韽韾顠顢顣顟飁飂饐饎饙饌饋饓騲騴騱騬騪騶騩騮騸騭髇髊髆鬐鬒鬑鰋鰈鯷鰅鰒鯸鱀鰇鰎鰆鰗鰔鰉鶟鶙鶤鶝鶒鶘鶐鶛"],["f5a1","鶠鶔鶜鶪鶗鶡鶚鶢鶨鶞鶣鶿鶩鶖鶦鶧麙麛麚黥黤黧黦鼰鼮齛齠齞齝齙龑儺儹劘劗囃嚽嚾孈孇巋巏廱懽攛欂櫼欃櫸欀灃灄灊灈灉灅灆爝爚爙獾甗癪矐礭礱礯籔籓糲纊纇纈纋纆纍罍羻耰臝蘘蘪蘦蘟蘣蘜蘙蘧蘮蘡蘠蘩蘞蘥"],["f640","蠩蠝蠛蠠蠤蠜蠫衊襭襩襮襫觺譹譸譅譺譻贐贔趯躎躌轞轛轝酆酄酅醹鐿鐻鐶鐩鐽鐼鐰鐹鐪鐷鐬鑀鐱闥闤闣霵霺鞿韡顤飉飆飀饘饖騹騽驆驄驂驁騺"],["f6a1","騿髍鬕鬗鬘鬖鬺魒鰫鰝鰜鰬鰣鰨鰩鰤鰡鶷鶶鶼鷁鷇鷊鷏鶾鷅鷃鶻鶵鷎鶹鶺鶬鷈鶱鶭鷌鶳鷍鶲鹺麜黫黮黭鼛鼘鼚鼱齎齥齤龒亹囆囅囋奱孋孌巕巑廲攡攠攦攢欋欈欉氍灕灖灗灒爞爟犩獿瓘瓕瓙瓗癭皭礵禴穰穱籗籜籙籛籚"],["f740","糴糱纑罏羇臞艫蘴蘵蘳蘬蘲蘶蠬蠨蠦蠪蠥襱覿覾觻譾讄讂讆讅譿贕躕躔躚躒躐躖躗轠轢酇鑌鑐鑊鑋鑏鑇鑅鑈鑉鑆霿韣顪顩飋饔饛驎驓驔驌驏驈驊"],["f7a1","驉驒驐髐鬙鬫鬻魖魕鱆鱈鰿鱄鰹鰳鱁鰼鰷鰴鰲鰽鰶鷛鷒鷞鷚鷋鷐鷜鷑鷟鷩鷙鷘鷖鷵鷕鷝麶黰鼵鼳鼲齂齫龕龢儽劙壨壧奲孍巘蠯彏戁戃戄攩攥斖曫欑欒欏毊灛灚爢玂玁玃癰矔籧籦纕艬蘺虀蘹蘼蘱蘻蘾蠰蠲蠮蠳襶襴襳觾"],["f840","讌讎讋讈豅贙躘轤轣醼鑢鑕鑝鑗鑞韄韅頀驖驙鬞鬟鬠鱒鱘鱐鱊鱍鱋鱕鱙鱌鱎鷻鷷鷯鷣鷫鷸鷤鷶鷡鷮鷦鷲鷰鷢鷬鷴鷳鷨鷭黂黐黲黳鼆鼜鼸鼷鼶齃齏"],["f8a1","齱齰齮齯囓囍孎屭攭曭曮欓灟灡灝灠爣瓛瓥矕礸禷禶籪纗羉艭虃蠸蠷蠵衋讔讕躞躟躠躝醾醽釂鑫鑨鑩雥靆靃靇韇韥驞髕魙鱣鱧鱦鱢鱞鱠鸂鷾鸇鸃鸆鸅鸀鸁鸉鷿鷽鸄麠鼞齆齴齵齶囔攮斸欘欙欗欚灢爦犪矘矙礹籩籫糶纚"],["f940","纘纛纙臠臡虆虇虈襹襺襼襻觿讘讙躥躤躣鑮鑭鑯鑱鑳靉顲饟鱨鱮鱭鸋鸍鸐鸏鸒鸑麡黵鼉齇齸齻齺齹圞灦籯蠼趲躦釃鑴鑸鑶鑵驠鱴鱳鱱鱵鸔鸓黶鼊"],["f9a1","龤灨灥糷虪蠾蠽蠿讞貜躩軉靋顳顴飌饡馫驤驦驧鬤鸕鸗齈戇欞爧虌躨钂钀钁驩驨鬮鸙爩虋讟钃鱹麷癵驫鱺鸝灩灪麤齾齉龘碁銹裏墻恒粧嫺╔╦╗╠╬╣╚╩╝╒╤╕╞╪╡╘╧╛╓╥╖╟╫╢╙╨╜║═╭╮╰╯▓"]] - -/***/ }), -/* 93 */ -/***/ (function(module, exports, __webpack_require__) { - -// Generated by CoffeeScript 1.7.1 -(function() { - var ArrayT, NumberT, utils; - - NumberT = __webpack_require__(22).Number; - - utils = __webpack_require__(12); - - ArrayT = (function() { - function ArrayT(type, length, lengthType) { - this.type = type; - this.length = length; - this.lengthType = lengthType != null ? lengthType : 'count'; - } - - ArrayT.prototype.decode = function(stream, parent) { - var ctx, i, length, pos, res, target, _i; - pos = stream.pos; - res = []; - ctx = parent; - if (this.length != null) { - length = utils.resolveLength(this.length, stream, parent); - } - if (this.length instanceof NumberT) { - Object.defineProperties(res, { - parent: { - value: parent - }, - _startOffset: { - value: pos - }, - _currentOffset: { - value: 0, - writable: true - }, - _length: { - value: length - } - }); - ctx = res; - } - if ((length == null) || this.lengthType === 'bytes') { - target = length != null ? stream.pos + length : (parent != null ? parent._length : void 0) ? parent._startOffset + parent._length : stream.length; - while (stream.pos < target) { - res.push(this.type.decode(stream, ctx)); - } - } else { - for (i = _i = 0; _i < length; i = _i += 1) { - res.push(this.type.decode(stream, ctx)); - } - } - return res; - }; - - ArrayT.prototype.size = function(array, ctx) { - var item, size, _i, _len; - if (!array) { - return this.type.size(null, ctx) * utils.resolveLength(this.length, null, ctx); - } - size = 0; - if (this.length instanceof NumberT) { - size += this.length.size(); - ctx = { - parent: ctx - }; - } - for (_i = 0, _len = array.length; _i < _len; _i++) { - item = array[_i]; - size += this.type.size(item, ctx); - } - return size; - }; - - ArrayT.prototype.encode = function(stream, array, parent) { - var ctx, i, item, ptr, _i, _len; - ctx = parent; - if (this.length instanceof NumberT) { - ctx = { - pointers: [], - startOffset: stream.pos, - parent: parent - }; - ctx.pointerOffset = stream.pos + this.size(array, ctx); - this.length.encode(stream, array.length); - } - for (_i = 0, _len = array.length; _i < _len; _i++) { - item = array[_i]; - this.type.encode(stream, item, ctx); - } - if (this.length instanceof NumberT) { - i = 0; - while (i < ctx.pointers.length) { - ptr = ctx.pointers[i++]; - ptr.type.encode(stream, ptr.val); - } - } - }; - - return ArrayT; - - })(); - - module.exports = ArrayT; - -}).call(this); - - -/***/ }), -/* 94 */ -/***/ (function(module, exports, __webpack_require__) { - -// Generated by CoffeeScript 1.7.1 -(function() { - var Struct, utils; - - utils = __webpack_require__(12); - - Struct = (function() { - function Struct(fields) { - this.fields = fields != null ? fields : {}; - } - - Struct.prototype.decode = function(stream, parent, length) { - var res, _ref; - if (length == null) { - length = 0; - } - res = this._setup(stream, parent, length); - this._parseFields(stream, res, this.fields); - if ((_ref = this.process) != null) { - _ref.call(res, stream); - } - return res; - }; - - Struct.prototype._setup = function(stream, parent, length) { - var res; - res = {}; - Object.defineProperties(res, { - parent: { - value: parent - }, - _startOffset: { - value: stream.pos - }, - _currentOffset: { - value: 0, - writable: true - }, - _length: { - value: length - } - }); - return res; - }; - - Struct.prototype._parseFields = function(stream, res, fields) { - var key, type, val; - for (key in fields) { - type = fields[key]; - if (typeof type === 'function') { - val = type.call(res, res); - } else { - val = type.decode(stream, res); - } - if (val !== void 0) { - if (val instanceof utils.PropertyDescriptor) { - Object.defineProperty(res, key, val); - } else { - res[key] = val; - } - } - res._currentOffset = stream.pos - res._startOffset; - } - }; - - Struct.prototype.size = function(val, parent, includePointers) { - var ctx, key, size, type, _ref; - if (val == null) { - val = {}; - } - if (includePointers == null) { - includePointers = true; - } - ctx = { - parent: parent, - val: val, - pointerSize: 0 - }; - size = 0; - _ref = this.fields; - for (key in _ref) { - type = _ref[key]; - if (type.size != null) { - size += type.size(val[key], ctx); - } - } - if (includePointers) { - size += ctx.pointerSize; - } - return size; - }; - - Struct.prototype.encode = function(stream, val, parent) { - var ctx, i, key, ptr, type, _ref, _ref1; - if ((_ref = this.preEncode) != null) { - _ref.call(val, stream); - } - ctx = { - pointers: [], - startOffset: stream.pos, - parent: parent, - val: val, - pointerSize: 0 - }; - ctx.pointerOffset = stream.pos + this.size(val, ctx, false); - _ref1 = this.fields; - for (key in _ref1) { - type = _ref1[key]; - if (type.encode != null) { - type.encode(stream, val[key], ctx); - } - } - i = 0; - while (i < ctx.pointers.length) { - ptr = ctx.pointers[i++]; - ptr.type.encode(stream, ptr.val, ptr.parent); - } - }; - - return Struct; - - })(); - - module.exports = Struct; - -}).call(this); - - -/***/ }), -/* 95 */ -/***/ (function(module, exports, __webpack_require__) { - -module.exports = !__webpack_require__(5) && !__webpack_require__(19)(function () { - return Object.defineProperty(__webpack_require__(96)('div'), 'a', { get: function () { return 7; } }).a != 7; -}); - - -/***/ }), -/* 96 */ -/***/ (function(module, exports, __webpack_require__) { - -var isObject = __webpack_require__(9); -var document = __webpack_require__(10).document; -// typeof document.createElement is 'object' in old IE -var is = isObject(document) && isObject(document.createElement); -module.exports = function (it) { - return is ? document.createElement(it) : {}; -}; - - -/***/ }), -/* 97 */ -/***/ (function(module, exports) { - -module.exports = function (it) { - if (typeof it != 'function') throw TypeError(it + ' is not a function!'); - return it; -}; - - -/***/ }), -/* 98 */ -/***/ (function(module, exports) { - -module.exports = function (done, value) { - return { value: value, done: !!done }; -}; - - -/***/ }), -/* 99 */ -/***/ (function(module, exports, __webpack_require__) { - -module.exports = __webpack_require__(13); - - -/***/ }), -/* 100 */ -/***/ (function(module, exports, __webpack_require__) { - -var dP = __webpack_require__(6); -var anObject = __webpack_require__(14); -var getKeys = __webpack_require__(29); - -module.exports = __webpack_require__(5) ? Object.defineProperties : function defineProperties(O, Properties) { - anObject(O); - var keys = getKeys(Properties); - var length = keys.length; - var i = 0; - var P; - while (length > i) dP.f(O, P = keys[i++], Properties[P]); - return O; -}; - - -/***/ }), -/* 101 */ -/***/ (function(module, exports, __webpack_require__) { - -var has = __webpack_require__(18); -var toIObject = __webpack_require__(17); -var arrayIndexOf = __webpack_require__(204)(false); -var IE_PROTO = __webpack_require__(64)('IE_PROTO'); - -module.exports = function (object, names) { - var O = toIObject(object); - var i = 0; - var result = []; - var key; - for (key in O) if (key != IE_PROTO) has(O, key) && result.push(key); - // Don't enum bug & hidden keys - while (names.length > i) if (has(O, key = names[i++])) { - ~arrayIndexOf(result, key) || result.push(key); - } - return result; -}; - - -/***/ }), -/* 102 */ -/***/ (function(module, exports, __webpack_require__) { - -var toInteger = __webpack_require__(63); -var max = Math.max; -var min = Math.min; -module.exports = function (index, length) { - index = toInteger(index); - return index < 0 ? max(index + length, 0) : min(index, length); -}; - - -/***/ }), -/* 103 */ -/***/ (function(module, exports, __webpack_require__) { - -module.exports = { "default": __webpack_require__(215), __esModule: true }; - -/***/ }), -/* 104 */ -/***/ (function(module, exports, __webpack_require__) { - -// 7.2.2 IsArray(argument) -var cof = __webpack_require__(55); -module.exports = Array.isArray || function isArray(arg) { - return cof(arg) == 'Array'; -}; - - -/***/ }), -/* 105 */ -/***/ (function(module, exports, __webpack_require__) { - -// 19.1.2.7 / 15.2.3.4 Object.getOwnPropertyNames(O) -var $keys = __webpack_require__(101); -var hiddenKeys = __webpack_require__(66).concat('length', 'prototype'); - -exports.f = Object.getOwnPropertyNames || function getOwnPropertyNames(O) { - return $keys(O, hiddenKeys); -}; - - -/***/ }), -/* 106 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -exports.__esModule = true; - -exports.default = function (instance, Constructor) { - if (!(instance instanceof Constructor)) { - throw new TypeError("Cannot call a class as a function"); - } -}; - -/***/ }), -/* 107 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -exports.__esModule = true; - -var _defineProperty = __webpack_require__(74); - -var _defineProperty2 = _interopRequireDefault(_defineProperty); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -exports.default = function () { - function defineProperties(target, props) { - for (var i = 0; i < props.length; i++) { - var descriptor = props[i]; - descriptor.enumerable = descriptor.enumerable || false; - descriptor.configurable = true; - if ("value" in descriptor) descriptor.writable = true; - (0, _defineProperty2.default)(target, descriptor.key, descriptor); - } - } - - return function (Constructor, protoProps, staticProps) { - if (protoProps) defineProperties(Constructor.prototype, protoProps); - if (staticProps) defineProperties(Constructor, staticProps); - return Constructor; - }; -}(); - -/***/ }), -/* 108 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var dP = __webpack_require__(6).f; -var create = __webpack_require__(36); -var redefineAll = __webpack_require__(109); -var ctx = __webpack_require__(20); -var anInstance = __webpack_require__(110); -var forOf = __webpack_require__(41); -var $iterDefine = __webpack_require__(61); -var step = __webpack_require__(98); -var setSpecies = __webpack_require__(228); -var DESCRIPTORS = __webpack_require__(5); -var fastKey = __webpack_require__(40).fastKey; -var validate = __webpack_require__(75); -var SIZE = DESCRIPTORS ? '_s' : 'size'; - -var getEntry = function (that, key) { - // fast case - var index = fastKey(key); - var entry; - if (index !== 'F') return that._i[index]; - // frozen object case - for (entry = that._f; entry; entry = entry.n) { - if (entry.k == key) return entry; - } -}; - -module.exports = { - getConstructor: function (wrapper, NAME, IS_MAP, ADDER) { - var C = wrapper(function (that, iterable) { - anInstance(that, C, NAME, '_i'); - that._t = NAME; // collection type - that._i = create(null); // index - that._f = undefined; // first entry - that._l = undefined; // last entry - that[SIZE] = 0; // size - if (iterable != undefined) forOf(iterable, IS_MAP, that[ADDER], that); - }); - redefineAll(C.prototype, { - // 23.1.3.1 Map.prototype.clear() - // 23.2.3.2 Set.prototype.clear() - clear: function clear() { - for (var that = validate(this, NAME), data = that._i, entry = that._f; entry; entry = entry.n) { - entry.r = true; - if (entry.p) entry.p = entry.p.n = undefined; - delete data[entry.i]; - } - that._f = that._l = undefined; - that[SIZE] = 0; - }, - // 23.1.3.3 Map.prototype.delete(key) - // 23.2.3.4 Set.prototype.delete(value) - 'delete': function (key) { - var that = validate(this, NAME); - var entry = getEntry(that, key); - if (entry) { - var next = entry.n; - var prev = entry.p; - delete that._i[entry.i]; - entry.r = true; - if (prev) prev.n = next; - if (next) next.p = prev; - if (that._f == entry) that._f = next; - if (that._l == entry) that._l = prev; - that[SIZE]--; - } return !!entry; - }, - // 23.2.3.6 Set.prototype.forEach(callbackfn, thisArg = undefined) - // 23.1.3.5 Map.prototype.forEach(callbackfn, thisArg = undefined) - forEach: function forEach(callbackfn /* , that = undefined */) { - validate(this, NAME); - var f = ctx(callbackfn, arguments.length > 1 ? arguments[1] : undefined, 3); - var entry; - while (entry = entry ? entry.n : this._f) { - f(entry.v, entry.k, this); - // revert to the last existing entry - while (entry && entry.r) entry = entry.p; - } - }, - // 23.1.3.7 Map.prototype.has(key) - // 23.2.3.7 Set.prototype.has(value) - has: function has(key) { - return !!getEntry(validate(this, NAME), key); - } - }); - if (DESCRIPTORS) dP(C.prototype, 'size', { - get: function () { - return validate(this, NAME)[SIZE]; - } - }); - return C; - }, - def: function (that, key, value) { - var entry = getEntry(that, key); - var prev, index; - // change existing entry - if (entry) { - entry.v = value; - // create new entry - } else { - that._l = entry = { - i: index = fastKey(key, true), // <- index - k: key, // <- key - v: value, // <- value - p: prev = that._l, // <- previous entry - n: undefined, // <- next entry - r: false // <- removed - }; - if (!that._f) that._f = entry; - if (prev) prev.n = entry; - that[SIZE]++; - // add to index - if (index !== 'F') that._i[index] = entry; - } return that; - }, - getEntry: getEntry, - setStrong: function (C, NAME, IS_MAP) { - // add .keys, .values, .entries, [@@iterator] - // 23.1.3.4, 23.1.3.8, 23.1.3.11, 23.1.3.12, 23.2.3.5, 23.2.3.8, 23.2.3.10, 23.2.3.11 - $iterDefine(C, NAME, function (iterated, kind) { - this._t = validate(iterated, NAME); // target - this._k = kind; // kind - this._l = undefined; // previous - }, function () { - var that = this; - var kind = that._k; - var entry = that._l; - // revert to the last existing entry - while (entry && entry.r) entry = entry.p; - // get next entry - if (!that._t || !(that._l = entry = entry ? entry.n : that._t._f)) { - // or finish the iteration - that._t = undefined; - return step(1); - } - // return step by kind - if (kind == 'keys') return step(0, entry.k); - if (kind == 'values') return step(0, entry.v); - return step(0, [entry.k, entry.v]); - }, IS_MAP ? 'entries' : 'values', !IS_MAP, true); - - // add [@@species], 23.1.2.2, 23.2.2.2 - setSpecies(NAME); - } -}; - - -/***/ }), -/* 109 */ -/***/ (function(module, exports, __webpack_require__) { - -var hide = __webpack_require__(13); -module.exports = function (target, src, safe) { - for (var key in src) { - if (safe && target[key]) target[key] = src[key]; - else hide(target, key, src[key]); - } return target; -}; - - -/***/ }), -/* 110 */ -/***/ (function(module, exports) { - -module.exports = function (it, Constructor, name, forbiddenField) { - if (!(it instanceof Constructor) || (forbiddenField !== undefined && forbiddenField in it)) { - throw TypeError(name + ': incorrect invocation!'); - } return it; -}; - - -/***/ }), -/* 111 */ -/***/ (function(module, exports, __webpack_require__) { - -// call something on iterator step with safe closing on error -var anObject = __webpack_require__(14); -module.exports = function (iterator, fn, value, entries) { - try { - return entries ? fn(anObject(value)[0], value[1]) : fn(value); - // 7.4.6 IteratorClose(iterator, completion) - } catch (e) { - var ret = iterator['return']; - if (ret !== undefined) anObject(ret.call(iterator)); - throw e; - } -}; - - -/***/ }), -/* 112 */ -/***/ (function(module, exports, __webpack_require__) { - -// check on default Array iterator -var Iterators = __webpack_require__(23); -var ITERATOR = __webpack_require__(4)('iterator'); -var ArrayProto = Array.prototype; - -module.exports = function (it) { - return it !== undefined && (Iterators.Array === it || ArrayProto[ITERATOR] === it); -}; - - -/***/ }), -/* 113 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var global = __webpack_require__(10); -var $export = __webpack_require__(3); -var meta = __webpack_require__(40); -var fails = __webpack_require__(19); -var hide = __webpack_require__(13); -var redefineAll = __webpack_require__(109); -var forOf = __webpack_require__(41); -var anInstance = __webpack_require__(110); -var isObject = __webpack_require__(9); -var setToStringTag = __webpack_require__(39); -var dP = __webpack_require__(6).f; -var each = __webpack_require__(229)(0); -var DESCRIPTORS = __webpack_require__(5); - -module.exports = function (NAME, wrapper, methods, common, IS_MAP, IS_WEAK) { - var Base = global[NAME]; - var C = Base; - var ADDER = IS_MAP ? 'set' : 'add'; - var proto = C && C.prototype; - var O = {}; - if (!DESCRIPTORS || typeof C != 'function' || !(IS_WEAK || proto.forEach && !fails(function () { - new C().entries().next(); - }))) { - // create collection constructor - C = common.getConstructor(wrapper, NAME, IS_MAP, ADDER); - redefineAll(C.prototype, methods); - meta.NEED = true; - } else { - C = wrapper(function (target, iterable) { - anInstance(target, C, NAME, '_c'); - target._c = new Base(); - if (iterable != undefined) forOf(iterable, IS_MAP, target[ADDER], target); - }); - each('add,clear,delete,forEach,get,has,set,keys,values,entries,toJSON'.split(','), function (KEY) { - var IS_ADDER = KEY == 'add' || KEY == 'set'; - if (KEY in proto && !(IS_WEAK && KEY == 'clear')) hide(C.prototype, KEY, function (a, b) { - anInstance(this, C, KEY); - if (!IS_ADDER && IS_WEAK && !isObject(a)) return KEY == 'get' ? undefined : false; - var result = this._c[KEY](a === 0 ? 0 : a, b); - return IS_ADDER ? this : result; - }); - }); - IS_WEAK || dP(C.prototype, 'size', { - get: function () { - return this._c.size; - } - }); - } - - setToStringTag(C, NAME); - - O[NAME] = C; - $export($export.G + $export.W + $export.F, O); - - if (!IS_WEAK) common.setStrong(C, NAME, IS_MAP); - - return C; -}; - - -/***/ }), -/* 114 */ -/***/ (function(module, exports, __webpack_require__) { - -// https://github.com/DavidBruant/Map-Set.prototype.toJSON -var classof = __webpack_require__(68); -var from = __webpack_require__(233); -module.exports = function (NAME) { - return function toJSON() { - if (classof(this) != NAME) throw TypeError(NAME + "#toJSON isn't generic"); - return from(this); - }; -}; - - -/***/ }), -/* 115 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -// https://tc39.github.io/proposal-setmap-offrom/ -var $export = __webpack_require__(3); - -module.exports = function (COLLECTION) { - $export($export.S, COLLECTION, { of: function of() { - var length = arguments.length; - var A = new Array(length); - while (length--) A[length] = arguments[length]; - return new this(A); - } }); -}; - - -/***/ }), -/* 116 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -// https://tc39.github.io/proposal-setmap-offrom/ -var $export = __webpack_require__(3); -var aFunction = __webpack_require__(97); -var ctx = __webpack_require__(20); -var forOf = __webpack_require__(41); - -module.exports = function (COLLECTION) { - $export($export.S, COLLECTION, { from: function from(source /* , mapFn, thisArg */) { - var mapFn = arguments[1]; - var mapping, A, n, cb; - aFunction(this); - mapping = mapFn !== undefined; - if (mapping) aFunction(mapFn); - if (source == undefined) return new this(); - A = []; - if (mapping) { - n = 0; - cb = ctx(mapFn, arguments[2], 2); - forOf(source, false, function (nextItem) { - A.push(cb(nextItem, n++)); - }); - } else { - forOf(source, false, A.push, A); - } - return new this(A); - } }); -}; - - -/***/ }), -/* 117 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Copyright 2013 Google Inc. All Rights Reserved. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -var BrotliInput = __webpack_require__(118).BrotliInput; -var BrotliOutput = __webpack_require__(118).BrotliOutput; -var BrotliBitReader = __webpack_require__(285); -var BrotliDictionary = __webpack_require__(119); -var HuffmanCode = __webpack_require__(120).HuffmanCode; -var BrotliBuildHuffmanTable = __webpack_require__(120).BrotliBuildHuffmanTable; -var Context = __webpack_require__(289); -var Prefix = __webpack_require__(290); -var Transform = __webpack_require__(291); - -var kDefaultCodeLength = 8; -var kCodeLengthRepeatCode = 16; -var kNumLiteralCodes = 256; -var kNumInsertAndCopyCodes = 704; -var kNumBlockLengthCodes = 26; -var kLiteralContextBits = 6; -var kDistanceContextBits = 2; - -var HUFFMAN_TABLE_BITS = 8; -var HUFFMAN_TABLE_MASK = 0xff; -/* Maximum possible Huffman table size for an alphabet size of 704, max code - * length 15 and root table bits 8. */ -var HUFFMAN_MAX_TABLE_SIZE = 1080; - -var CODE_LENGTH_CODES = 18; -var kCodeLengthCodeOrder = new Uint8Array([ - 1, 2, 3, 4, 0, 5, 17, 6, 16, 7, 8, 9, 10, 11, 12, 13, 14, 15, -]); - -var NUM_DISTANCE_SHORT_CODES = 16; -var kDistanceShortCodeIndexOffset = new Uint8Array([ - 3, 2, 1, 0, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2 -]); - -var kDistanceShortCodeValueOffset = new Int8Array([ - 0, 0, 0, 0, -1, 1, -2, 2, -3, 3, -1, 1, -2, 2, -3, 3 -]); - -var kMaxHuffmanTableSize = new Uint16Array([ - 256, 402, 436, 468, 500, 534, 566, 598, 630, 662, 694, 726, 758, 790, 822, - 854, 886, 920, 952, 984, 1016, 1048, 1080 -]); - -function DecodeWindowBits(br) { - var n; - if (br.readBits(1) === 0) { - return 16; - } - - n = br.readBits(3); - if (n > 0) { - return 17 + n; - } - - n = br.readBits(3); - if (n > 0) { - return 8 + n; - } - - return 17; -} - -/* Decodes a number in the range [0..255], by reading 1 - 11 bits. */ -function DecodeVarLenUint8(br) { - if (br.readBits(1)) { - var nbits = br.readBits(3); - if (nbits === 0) { - return 1; - } else { - return br.readBits(nbits) + (1 << nbits); - } - } - return 0; -} - -function MetaBlockLength() { - this.meta_block_length = 0; - this.input_end = 0; - this.is_uncompressed = 0; - this.is_metadata = false; -} - -function DecodeMetaBlockLength(br) { - var out = new MetaBlockLength; - var size_nibbles; - var size_bytes; - var i; - - out.input_end = br.readBits(1); - if (out.input_end && br.readBits(1)) { - return out; - } - - size_nibbles = br.readBits(2) + 4; - if (size_nibbles === 7) { - out.is_metadata = true; - - if (br.readBits(1) !== 0) - throw new Error('Invalid reserved bit'); - - size_bytes = br.readBits(2); - if (size_bytes === 0) - return out; - - for (i = 0; i < size_bytes; i++) { - var next_byte = br.readBits(8); - if (i + 1 === size_bytes && size_bytes > 1 && next_byte === 0) - throw new Error('Invalid size byte'); - - out.meta_block_length |= next_byte << (i * 8); - } - } else { - for (i = 0; i < size_nibbles; ++i) { - var next_nibble = br.readBits(4); - if (i + 1 === size_nibbles && size_nibbles > 4 && next_nibble === 0) - throw new Error('Invalid size nibble'); - - out.meta_block_length |= next_nibble << (i * 4); - } - } - - ++out.meta_block_length; - - if (!out.input_end && !out.is_metadata) { - out.is_uncompressed = br.readBits(1); - } - - return out; -} - -/* Decodes the next Huffman code from bit-stream. */ -function ReadSymbol(table, index, br) { - var start_index = index; - - var nbits; - br.fillBitWindow(); - index += (br.val_ >>> br.bit_pos_) & HUFFMAN_TABLE_MASK; - nbits = table[index].bits - HUFFMAN_TABLE_BITS; - if (nbits > 0) { - br.bit_pos_ += HUFFMAN_TABLE_BITS; - index += table[index].value; - index += (br.val_ >>> br.bit_pos_) & ((1 << nbits) - 1); - } - br.bit_pos_ += table[index].bits; - return table[index].value; -} - -function ReadHuffmanCodeLengths(code_length_code_lengths, num_symbols, code_lengths, br) { - var symbol = 0; - var prev_code_len = kDefaultCodeLength; - var repeat = 0; - var repeat_code_len = 0; - var space = 32768; - - var table = []; - for (var i = 0; i < 32; i++) - table.push(new HuffmanCode(0, 0)); - - BrotliBuildHuffmanTable(table, 0, 5, code_length_code_lengths, CODE_LENGTH_CODES); - - while (symbol < num_symbols && space > 0) { - var p = 0; - var code_len; - - br.readMoreInput(); - br.fillBitWindow(); - p += (br.val_ >>> br.bit_pos_) & 31; - br.bit_pos_ += table[p].bits; - code_len = table[p].value & 0xff; - if (code_len < kCodeLengthRepeatCode) { - repeat = 0; - code_lengths[symbol++] = code_len; - if (code_len !== 0) { - prev_code_len = code_len; - space -= 32768 >> code_len; - } - } else { - var extra_bits = code_len - 14; - var old_repeat; - var repeat_delta; - var new_len = 0; - if (code_len === kCodeLengthRepeatCode) { - new_len = prev_code_len; - } - if (repeat_code_len !== new_len) { - repeat = 0; - repeat_code_len = new_len; - } - old_repeat = repeat; - if (repeat > 0) { - repeat -= 2; - repeat <<= extra_bits; - } - repeat += br.readBits(extra_bits) + 3; - repeat_delta = repeat - old_repeat; - if (symbol + repeat_delta > num_symbols) { - throw new Error('[ReadHuffmanCodeLengths] symbol + repeat_delta > num_symbols'); - } - - for (var x = 0; x < repeat_delta; x++) - code_lengths[symbol + x] = repeat_code_len; - - symbol += repeat_delta; - - if (repeat_code_len !== 0) { - space -= repeat_delta << (15 - repeat_code_len); - } - } - } - if (space !== 0) { - throw new Error("[ReadHuffmanCodeLengths] space = " + space); - } - - for (; symbol < num_symbols; symbol++) - code_lengths[symbol] = 0; -} - -function ReadHuffmanCode(alphabet_size, tables, table, br) { - var table_size = 0; - var simple_code_or_skip; - var code_lengths = new Uint8Array(alphabet_size); - - br.readMoreInput(); - - /* simple_code_or_skip is used as follows: - 1 for simple code; - 0 for no skipping, 2 skips 2 code lengths, 3 skips 3 code lengths */ - simple_code_or_skip = br.readBits(2); - if (simple_code_or_skip === 1) { - /* Read symbols, codes & code lengths directly. */ - var i; - var max_bits_counter = alphabet_size - 1; - var max_bits = 0; - var symbols = new Int32Array(4); - var num_symbols = br.readBits(2) + 1; - while (max_bits_counter) { - max_bits_counter >>= 1; - ++max_bits; - } - - for (i = 0; i < num_symbols; ++i) { - symbols[i] = br.readBits(max_bits) % alphabet_size; - code_lengths[symbols[i]] = 2; - } - code_lengths[symbols[0]] = 1; - switch (num_symbols) { - case 1: - break; - case 3: - if ((symbols[0] === symbols[1]) || - (symbols[0] === symbols[2]) || - (symbols[1] === symbols[2])) { - throw new Error('[ReadHuffmanCode] invalid symbols'); - } - break; - case 2: - if (symbols[0] === symbols[1]) { - throw new Error('[ReadHuffmanCode] invalid symbols'); - } - - code_lengths[symbols[1]] = 1; - break; - case 4: - if ((symbols[0] === symbols[1]) || - (symbols[0] === symbols[2]) || - (symbols[0] === symbols[3]) || - (symbols[1] === symbols[2]) || - (symbols[1] === symbols[3]) || - (symbols[2] === symbols[3])) { - throw new Error('[ReadHuffmanCode] invalid symbols'); - } - - if (br.readBits(1)) { - code_lengths[symbols[2]] = 3; - code_lengths[symbols[3]] = 3; - } else { - code_lengths[symbols[0]] = 2; - } - break; - } - } else { /* Decode Huffman-coded code lengths. */ - var i; - var code_length_code_lengths = new Uint8Array(CODE_LENGTH_CODES); - var space = 32; - var num_codes = 0; - /* Static Huffman code for the code length code lengths */ - var huff = [ - new HuffmanCode(2, 0), new HuffmanCode(2, 4), new HuffmanCode(2, 3), new HuffmanCode(3, 2), - new HuffmanCode(2, 0), new HuffmanCode(2, 4), new HuffmanCode(2, 3), new HuffmanCode(4, 1), - new HuffmanCode(2, 0), new HuffmanCode(2, 4), new HuffmanCode(2, 3), new HuffmanCode(3, 2), - new HuffmanCode(2, 0), new HuffmanCode(2, 4), new HuffmanCode(2, 3), new HuffmanCode(4, 5) - ]; - for (i = simple_code_or_skip; i < CODE_LENGTH_CODES && space > 0; ++i) { - var code_len_idx = kCodeLengthCodeOrder[i]; - var p = 0; - var v; - br.fillBitWindow(); - p += (br.val_ >>> br.bit_pos_) & 15; - br.bit_pos_ += huff[p].bits; - v = huff[p].value; - code_length_code_lengths[code_len_idx] = v; - if (v !== 0) { - space -= (32 >> v); - ++num_codes; - } - } - - if (!(num_codes === 1 || space === 0)) - throw new Error('[ReadHuffmanCode] invalid num_codes or space'); - - ReadHuffmanCodeLengths(code_length_code_lengths, alphabet_size, code_lengths, br); - } - - table_size = BrotliBuildHuffmanTable(tables, table, HUFFMAN_TABLE_BITS, code_lengths, alphabet_size); - - if (table_size === 0) { - throw new Error("[ReadHuffmanCode] BuildHuffmanTable failed: "); - } - - return table_size; -} - -function ReadBlockLength(table, index, br) { - var code; - var nbits; - code = ReadSymbol(table, index, br); - nbits = Prefix.kBlockLengthPrefixCode[code].nbits; - return Prefix.kBlockLengthPrefixCode[code].offset + br.readBits(nbits); -} - -function TranslateShortCodes(code, ringbuffer, index) { - var val; - if (code < NUM_DISTANCE_SHORT_CODES) { - index += kDistanceShortCodeIndexOffset[code]; - index &= 3; - val = ringbuffer[index] + kDistanceShortCodeValueOffset[code]; - } else { - val = code - NUM_DISTANCE_SHORT_CODES + 1; - } - return val; -} - -function MoveToFront(v, index) { - var value = v[index]; - var i = index; - for (; i; --i) v[i] = v[i - 1]; - v[0] = value; -} - -function InverseMoveToFrontTransform(v, v_len) { - var mtf = new Uint8Array(256); - var i; - for (i = 0; i < 256; ++i) { - mtf[i] = i; - } - for (i = 0; i < v_len; ++i) { - var index = v[i]; - v[i] = mtf[index]; - if (index) MoveToFront(mtf, index); - } -} - -/* Contains a collection of huffman trees with the same alphabet size. */ -function HuffmanTreeGroup(alphabet_size, num_htrees) { - this.alphabet_size = alphabet_size; - this.num_htrees = num_htrees; - this.codes = new Array(num_htrees + num_htrees * kMaxHuffmanTableSize[(alphabet_size + 31) >>> 5]); - this.htrees = new Uint32Array(num_htrees); -} - -HuffmanTreeGroup.prototype.decode = function(br) { - var i; - var table_size; - var next = 0; - for (i = 0; i < this.num_htrees; ++i) { - this.htrees[i] = next; - table_size = ReadHuffmanCode(this.alphabet_size, this.codes, next, br); - next += table_size; - } -}; - -function DecodeContextMap(context_map_size, br) { - var out = { num_htrees: null, context_map: null }; - var use_rle_for_zeros; - var max_run_length_prefix = 0; - var table; - var i; - - br.readMoreInput(); - var num_htrees = out.num_htrees = DecodeVarLenUint8(br) + 1; - - var context_map = out.context_map = new Uint8Array(context_map_size); - if (num_htrees <= 1) { - return out; - } - - use_rle_for_zeros = br.readBits(1); - if (use_rle_for_zeros) { - max_run_length_prefix = br.readBits(4) + 1; - } - - table = []; - for (i = 0; i < HUFFMAN_MAX_TABLE_SIZE; i++) { - table[i] = new HuffmanCode(0, 0); - } - - ReadHuffmanCode(num_htrees + max_run_length_prefix, table, 0, br); - - for (i = 0; i < context_map_size;) { - var code; - - br.readMoreInput(); - code = ReadSymbol(table, 0, br); - if (code === 0) { - context_map[i] = 0; - ++i; - } else if (code <= max_run_length_prefix) { - var reps = 1 + (1 << code) + br.readBits(code); - while (--reps) { - if (i >= context_map_size) { - throw new Error("[DecodeContextMap] i >= context_map_size"); - } - context_map[i] = 0; - ++i; - } - } else { - context_map[i] = code - max_run_length_prefix; - ++i; - } - } - if (br.readBits(1)) { - InverseMoveToFrontTransform(context_map, context_map_size); - } - - return out; -} - -function DecodeBlockType(max_block_type, trees, tree_type, block_types, ringbuffers, indexes, br) { - var ringbuffer = tree_type * 2; - var index = tree_type; - var type_code = ReadSymbol(trees, tree_type * HUFFMAN_MAX_TABLE_SIZE, br); - var block_type; - if (type_code === 0) { - block_type = ringbuffers[ringbuffer + (indexes[index] & 1)]; - } else if (type_code === 1) { - block_type = ringbuffers[ringbuffer + ((indexes[index] - 1) & 1)] + 1; - } else { - block_type = type_code - 2; - } - if (block_type >= max_block_type) { - block_type -= max_block_type; - } - block_types[tree_type] = block_type; - ringbuffers[ringbuffer + (indexes[index] & 1)] = block_type; - ++indexes[index]; -} - -function CopyUncompressedBlockToOutput(output, len, pos, ringbuffer, ringbuffer_mask, br) { - var rb_size = ringbuffer_mask + 1; - var rb_pos = pos & ringbuffer_mask; - var br_pos = br.pos_ & BrotliBitReader.IBUF_MASK; - var nbytes; - - /* For short lengths copy byte-by-byte */ - if (len < 8 || br.bit_pos_ + (len << 3) < br.bit_end_pos_) { - while (len-- > 0) { - br.readMoreInput(); - ringbuffer[rb_pos++] = br.readBits(8); - if (rb_pos === rb_size) { - output.write(ringbuffer, rb_size); - rb_pos = 0; - } - } - return; - } - - if (br.bit_end_pos_ < 32) { - throw new Error('[CopyUncompressedBlockToOutput] br.bit_end_pos_ < 32'); - } - - /* Copy remaining 0-4 bytes from br.val_ to ringbuffer. */ - while (br.bit_pos_ < 32) { - ringbuffer[rb_pos] = (br.val_ >>> br.bit_pos_); - br.bit_pos_ += 8; - ++rb_pos; - --len; - } - - /* Copy remaining bytes from br.buf_ to ringbuffer. */ - nbytes = (br.bit_end_pos_ - br.bit_pos_) >> 3; - if (br_pos + nbytes > BrotliBitReader.IBUF_MASK) { - var tail = BrotliBitReader.IBUF_MASK + 1 - br_pos; - for (var x = 0; x < tail; x++) - ringbuffer[rb_pos + x] = br.buf_[br_pos + x]; - - nbytes -= tail; - rb_pos += tail; - len -= tail; - br_pos = 0; - } - - for (var x = 0; x < nbytes; x++) - ringbuffer[rb_pos + x] = br.buf_[br_pos + x]; - - rb_pos += nbytes; - len -= nbytes; - - /* If we wrote past the logical end of the ringbuffer, copy the tail of the - ringbuffer to its beginning and flush the ringbuffer to the output. */ - if (rb_pos >= rb_size) { - output.write(ringbuffer, rb_size); - rb_pos -= rb_size; - for (var x = 0; x < rb_pos; x++) - ringbuffer[x] = ringbuffer[rb_size + x]; - } - - /* If we have more to copy than the remaining size of the ringbuffer, then we - first fill the ringbuffer from the input and then flush the ringbuffer to - the output */ - while (rb_pos + len >= rb_size) { - nbytes = rb_size - rb_pos; - if (br.input_.read(ringbuffer, rb_pos, nbytes) < nbytes) { - throw new Error('[CopyUncompressedBlockToOutput] not enough bytes'); - } - output.write(ringbuffer, rb_size); - len -= nbytes; - rb_pos = 0; - } - - /* Copy straight from the input onto the ringbuffer. The ringbuffer will be - flushed to the output at a later time. */ - if (br.input_.read(ringbuffer, rb_pos, len) < len) { - throw new Error('[CopyUncompressedBlockToOutput] not enough bytes'); - } - - /* Restore the state of the bit reader. */ - br.reset(); -} - -/* Advances the bit reader position to the next byte boundary and verifies - that any skipped bits are set to zero. */ -function JumpToByteBoundary(br) { - var new_bit_pos = (br.bit_pos_ + 7) & ~7; - var pad_bits = br.readBits(new_bit_pos - br.bit_pos_); - return pad_bits == 0; -} - -function BrotliDecompressedSize(buffer) { - var input = new BrotliInput(buffer); - var br = new BrotliBitReader(input); - DecodeWindowBits(br); - var out = DecodeMetaBlockLength(br); - return out.meta_block_length; -} - -exports.BrotliDecompressedSize = BrotliDecompressedSize; - -function BrotliDecompressBuffer(buffer, output_size) { - var input = new BrotliInput(buffer); - - if (output_size == null) { - output_size = BrotliDecompressedSize(buffer); - } - - var output_buffer = new Uint8Array(output_size); - var output = new BrotliOutput(output_buffer); - - BrotliDecompress(input, output); - - if (output.pos < output.buffer.length) { - output.buffer = output.buffer.subarray(0, output.pos); - } - - return output.buffer; -} - -exports.BrotliDecompressBuffer = BrotliDecompressBuffer; - -function BrotliDecompress(input, output) { - var i; - var pos = 0; - var input_end = 0; - var window_bits = 0; - var max_backward_distance; - var max_distance = 0; - var ringbuffer_size; - var ringbuffer_mask; - var ringbuffer; - var ringbuffer_end; - /* This ring buffer holds a few past copy distances that will be used by */ - /* some special distance codes. */ - var dist_rb = [ 16, 15, 11, 4 ]; - var dist_rb_idx = 0; - /* The previous 2 bytes used for context. */ - var prev_byte1 = 0; - var prev_byte2 = 0; - var hgroup = [new HuffmanTreeGroup(0, 0), new HuffmanTreeGroup(0, 0), new HuffmanTreeGroup(0, 0)]; - var block_type_trees; - var block_len_trees; - var br; - - /* We need the slack region for the following reasons: - - always doing two 8-byte copies for fast backward copying - - transforms - - flushing the input ringbuffer when decoding uncompressed blocks */ - var kRingBufferWriteAheadSlack = 128 + BrotliBitReader.READ_SIZE; - - br = new BrotliBitReader(input); - - /* Decode window size. */ - window_bits = DecodeWindowBits(br); - max_backward_distance = (1 << window_bits) - 16; - - ringbuffer_size = 1 << window_bits; - ringbuffer_mask = ringbuffer_size - 1; - ringbuffer = new Uint8Array(ringbuffer_size + kRingBufferWriteAheadSlack + BrotliDictionary.maxDictionaryWordLength); - ringbuffer_end = ringbuffer_size; - - block_type_trees = []; - block_len_trees = []; - for (var x = 0; x < 3 * HUFFMAN_MAX_TABLE_SIZE; x++) { - block_type_trees[x] = new HuffmanCode(0, 0); - block_len_trees[x] = new HuffmanCode(0, 0); - } - - while (!input_end) { - var meta_block_remaining_len = 0; - var is_uncompressed; - var block_length = [ 1 << 28, 1 << 28, 1 << 28 ]; - var block_type = [ 0 ]; - var num_block_types = [ 1, 1, 1 ]; - var block_type_rb = [ 0, 1, 0, 1, 0, 1 ]; - var block_type_rb_index = [ 0 ]; - var distance_postfix_bits; - var num_direct_distance_codes; - var distance_postfix_mask; - var num_distance_codes; - var context_map = null; - var context_modes = null; - var num_literal_htrees; - var dist_context_map = null; - var num_dist_htrees; - var context_offset = 0; - var context_map_slice = null; - var literal_htree_index = 0; - var dist_context_offset = 0; - var dist_context_map_slice = null; - var dist_htree_index = 0; - var context_lookup_offset1 = 0; - var context_lookup_offset2 = 0; - var context_mode; - var htree_command; - - for (i = 0; i < 3; ++i) { - hgroup[i].codes = null; - hgroup[i].htrees = null; - } - - br.readMoreInput(); - - var _out = DecodeMetaBlockLength(br); - meta_block_remaining_len = _out.meta_block_length; - if (pos + meta_block_remaining_len > output.buffer.length) { - /* We need to grow the output buffer to fit the additional data. */ - var tmp = new Uint8Array( pos + meta_block_remaining_len ); - tmp.set( output.buffer ); - output.buffer = tmp; - } - input_end = _out.input_end; - is_uncompressed = _out.is_uncompressed; - - if (_out.is_metadata) { - JumpToByteBoundary(br); - - for (; meta_block_remaining_len > 0; --meta_block_remaining_len) { - br.readMoreInput(); - /* Read one byte and ignore it. */ - br.readBits(8); - } - - continue; - } - - if (meta_block_remaining_len === 0) { - continue; - } - - if (is_uncompressed) { - br.bit_pos_ = (br.bit_pos_ + 7) & ~7; - CopyUncompressedBlockToOutput(output, meta_block_remaining_len, pos, - ringbuffer, ringbuffer_mask, br); - pos += meta_block_remaining_len; - continue; - } - - for (i = 0; i < 3; ++i) { - num_block_types[i] = DecodeVarLenUint8(br) + 1; - if (num_block_types[i] >= 2) { - ReadHuffmanCode(num_block_types[i] + 2, block_type_trees, i * HUFFMAN_MAX_TABLE_SIZE, br); - ReadHuffmanCode(kNumBlockLengthCodes, block_len_trees, i * HUFFMAN_MAX_TABLE_SIZE, br); - block_length[i] = ReadBlockLength(block_len_trees, i * HUFFMAN_MAX_TABLE_SIZE, br); - block_type_rb_index[i] = 1; - } - } - - br.readMoreInput(); - - distance_postfix_bits = br.readBits(2); - num_direct_distance_codes = NUM_DISTANCE_SHORT_CODES + (br.readBits(4) << distance_postfix_bits); - distance_postfix_mask = (1 << distance_postfix_bits) - 1; - num_distance_codes = (num_direct_distance_codes + (48 << distance_postfix_bits)); - context_modes = new Uint8Array(num_block_types[0]); - - for (i = 0; i < num_block_types[0]; ++i) { - br.readMoreInput(); - context_modes[i] = (br.readBits(2) << 1); - } - - var _o1 = DecodeContextMap(num_block_types[0] << kLiteralContextBits, br); - num_literal_htrees = _o1.num_htrees; - context_map = _o1.context_map; - - var _o2 = DecodeContextMap(num_block_types[2] << kDistanceContextBits, br); - num_dist_htrees = _o2.num_htrees; - dist_context_map = _o2.context_map; - - hgroup[0] = new HuffmanTreeGroup(kNumLiteralCodes, num_literal_htrees); - hgroup[1] = new HuffmanTreeGroup(kNumInsertAndCopyCodes, num_block_types[1]); - hgroup[2] = new HuffmanTreeGroup(num_distance_codes, num_dist_htrees); - - for (i = 0; i < 3; ++i) { - hgroup[i].decode(br); - } - - context_map_slice = 0; - dist_context_map_slice = 0; - context_mode = context_modes[block_type[0]]; - context_lookup_offset1 = Context.lookupOffsets[context_mode]; - context_lookup_offset2 = Context.lookupOffsets[context_mode + 1]; - htree_command = hgroup[1].htrees[0]; - - while (meta_block_remaining_len > 0) { - var cmd_code; - var range_idx; - var insert_code; - var copy_code; - var insert_length; - var copy_length; - var distance_code; - var distance; - var context; - var j; - var copy_dst; - - br.readMoreInput(); - - if (block_length[1] === 0) { - DecodeBlockType(num_block_types[1], - block_type_trees, 1, block_type, block_type_rb, - block_type_rb_index, br); - block_length[1] = ReadBlockLength(block_len_trees, HUFFMAN_MAX_TABLE_SIZE, br); - htree_command = hgroup[1].htrees[block_type[1]]; - } - --block_length[1]; - cmd_code = ReadSymbol(hgroup[1].codes, htree_command, br); - range_idx = cmd_code >> 6; - if (range_idx >= 2) { - range_idx -= 2; - distance_code = -1; - } else { - distance_code = 0; - } - insert_code = Prefix.kInsertRangeLut[range_idx] + ((cmd_code >> 3) & 7); - copy_code = Prefix.kCopyRangeLut[range_idx] + (cmd_code & 7); - insert_length = Prefix.kInsertLengthPrefixCode[insert_code].offset + - br.readBits(Prefix.kInsertLengthPrefixCode[insert_code].nbits); - copy_length = Prefix.kCopyLengthPrefixCode[copy_code].offset + - br.readBits(Prefix.kCopyLengthPrefixCode[copy_code].nbits); - prev_byte1 = ringbuffer[pos-1 & ringbuffer_mask]; - prev_byte2 = ringbuffer[pos-2 & ringbuffer_mask]; - for (j = 0; j < insert_length; ++j) { - br.readMoreInput(); - - if (block_length[0] === 0) { - DecodeBlockType(num_block_types[0], - block_type_trees, 0, block_type, block_type_rb, - block_type_rb_index, br); - block_length[0] = ReadBlockLength(block_len_trees, 0, br); - context_offset = block_type[0] << kLiteralContextBits; - context_map_slice = context_offset; - context_mode = context_modes[block_type[0]]; - context_lookup_offset1 = Context.lookupOffsets[context_mode]; - context_lookup_offset2 = Context.lookupOffsets[context_mode + 1]; - } - context = (Context.lookup[context_lookup_offset1 + prev_byte1] | - Context.lookup[context_lookup_offset2 + prev_byte2]); - literal_htree_index = context_map[context_map_slice + context]; - --block_length[0]; - prev_byte2 = prev_byte1; - prev_byte1 = ReadSymbol(hgroup[0].codes, hgroup[0].htrees[literal_htree_index], br); - ringbuffer[pos & ringbuffer_mask] = prev_byte1; - if ((pos & ringbuffer_mask) === ringbuffer_mask) { - output.write(ringbuffer, ringbuffer_size); - } - ++pos; - } - meta_block_remaining_len -= insert_length; - if (meta_block_remaining_len <= 0) break; - - if (distance_code < 0) { - var context; - - br.readMoreInput(); - if (block_length[2] === 0) { - DecodeBlockType(num_block_types[2], - block_type_trees, 2, block_type, block_type_rb, - block_type_rb_index, br); - block_length[2] = ReadBlockLength(block_len_trees, 2 * HUFFMAN_MAX_TABLE_SIZE, br); - dist_context_offset = block_type[2] << kDistanceContextBits; - dist_context_map_slice = dist_context_offset; - } - --block_length[2]; - context = (copy_length > 4 ? 3 : copy_length - 2) & 0xff; - dist_htree_index = dist_context_map[dist_context_map_slice + context]; - distance_code = ReadSymbol(hgroup[2].codes, hgroup[2].htrees[dist_htree_index], br); - if (distance_code >= num_direct_distance_codes) { - var nbits; - var postfix; - var offset; - distance_code -= num_direct_distance_codes; - postfix = distance_code & distance_postfix_mask; - distance_code >>= distance_postfix_bits; - nbits = (distance_code >> 1) + 1; - offset = ((2 + (distance_code & 1)) << nbits) - 4; - distance_code = num_direct_distance_codes + - ((offset + br.readBits(nbits)) << - distance_postfix_bits) + postfix; - } - } - - /* Convert the distance code to the actual distance by possibly looking */ - /* up past distnaces from the ringbuffer. */ - distance = TranslateShortCodes(distance_code, dist_rb, dist_rb_idx); - if (distance < 0) { - throw new Error('[BrotliDecompress] invalid distance'); - } - - if (pos < max_backward_distance && - max_distance !== max_backward_distance) { - max_distance = pos; - } else { - max_distance = max_backward_distance; - } - - copy_dst = pos & ringbuffer_mask; - - if (distance > max_distance) { - if (copy_length >= BrotliDictionary.minDictionaryWordLength && - copy_length <= BrotliDictionary.maxDictionaryWordLength) { - var offset = BrotliDictionary.offsetsByLength[copy_length]; - var word_id = distance - max_distance - 1; - var shift = BrotliDictionary.sizeBitsByLength[copy_length]; - var mask = (1 << shift) - 1; - var word_idx = word_id & mask; - var transform_idx = word_id >> shift; - offset += word_idx * copy_length; - if (transform_idx < Transform.kNumTransforms) { - var len = Transform.transformDictionaryWord(ringbuffer, copy_dst, offset, copy_length, transform_idx); - copy_dst += len; - pos += len; - meta_block_remaining_len -= len; - if (copy_dst >= ringbuffer_end) { - output.write(ringbuffer, ringbuffer_size); - - for (var _x = 0; _x < (copy_dst - ringbuffer_end); _x++) - ringbuffer[_x] = ringbuffer[ringbuffer_end + _x]; - } - } else { - throw new Error("Invalid backward reference. pos: " + pos + " distance: " + distance + - " len: " + copy_length + " bytes left: " + meta_block_remaining_len); - } - } else { - throw new Error("Invalid backward reference. pos: " + pos + " distance: " + distance + - " len: " + copy_length + " bytes left: " + meta_block_remaining_len); - } - } else { - if (distance_code > 0) { - dist_rb[dist_rb_idx & 3] = distance; - ++dist_rb_idx; - } - - if (copy_length > meta_block_remaining_len) { - throw new Error("Invalid backward reference. pos: " + pos + " distance: " + distance + - " len: " + copy_length + " bytes left: " + meta_block_remaining_len); - } - - for (j = 0; j < copy_length; ++j) { - ringbuffer[pos & ringbuffer_mask] = ringbuffer[(pos - distance) & ringbuffer_mask]; - if ((pos & ringbuffer_mask) === ringbuffer_mask) { - output.write(ringbuffer, ringbuffer_size); - } - ++pos; - --meta_block_remaining_len; - } - } - - /* When we get here, we must have inserted at least one literal and */ - /* made a copy of at least length two, therefore accessing the last 2 */ - /* bytes is valid. */ - prev_byte1 = ringbuffer[(pos - 1) & ringbuffer_mask]; - prev_byte2 = ringbuffer[(pos - 2) & ringbuffer_mask]; - } - - /* Protect pos from overflow, wrap it around at every GB of input data */ - pos &= 0x3fffffff; - } - - output.write(ringbuffer, pos & ringbuffer_mask); -} - -exports.BrotliDecompress = BrotliDecompress; - -BrotliDictionary.init(); - - -/***/ }), -/* 118 */ -/***/ (function(module, exports) { - -function BrotliInput(buffer) { - this.buffer = buffer; - this.pos = 0; -} - -BrotliInput.prototype.read = function(buf, i, count) { - if (this.pos + count > this.buffer.length) { - count = this.buffer.length - this.pos; - } - - for (var p = 0; p < count; p++) - buf[i + p] = this.buffer[this.pos + p]; - - this.pos += count; - return count; -} - -exports.BrotliInput = BrotliInput; - -function BrotliOutput(buf) { - this.buffer = buf; - this.pos = 0; -} - -BrotliOutput.prototype.write = function(buf, count) { - if (this.pos + count > this.buffer.length) - throw new Error('Output buffer is not large enough'); - - this.buffer.set(buf.subarray(0, count), this.pos); - this.pos += count; - return count; -}; - -exports.BrotliOutput = BrotliOutput; - - -/***/ }), -/* 119 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Copyright 2013 Google Inc. All Rights Reserved. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - Collection of static dictionary words. -*/ - -var data = __webpack_require__(286); -exports.init = function() { - exports.dictionary = data.init(); -}; - -exports.offsetsByLength = new Uint32Array([ - 0, 0, 0, 0, 0, 4096, 9216, 21504, 35840, 44032, - 53248, 63488, 74752, 87040, 93696, 100864, 104704, 106752, 108928, 113536, - 115968, 118528, 119872, 121280, 122016, -]); - -exports.sizeBitsByLength = new Uint8Array([ - 0, 0, 0, 0, 10, 10, 11, 11, 10, 10, - 10, 10, 10, 9, 9, 8, 7, 7, 8, 7, - 7, 6, 6, 5, 5, -]); - -exports.minDictionaryWordLength = 4; -exports.maxDictionaryWordLength = 24; - - -/***/ }), -/* 120 */ -/***/ (function(module, exports) { - -function HuffmanCode(bits, value) { - this.bits = bits; /* number of bits used for this symbol */ - this.value = value; /* symbol value or table offset */ -} - -exports.HuffmanCode = HuffmanCode; - -var MAX_LENGTH = 15; - -/* Returns reverse(reverse(key, len) + 1, len), where reverse(key, len) is the - bit-wise reversal of the len least significant bits of key. */ -function GetNextKey(key, len) { - var step = 1 << (len - 1); - while (key & step) { - step >>= 1; - } - return (key & (step - 1)) + step; -} - -/* Stores code in table[0], table[step], table[2*step], ..., table[end] */ -/* Assumes that end is an integer multiple of step */ -function ReplicateValue(table, i, step, end, code) { - do { - end -= step; - table[i + end] = new HuffmanCode(code.bits, code.value); - } while (end > 0); -} - -/* Returns the table width of the next 2nd level table. count is the histogram - of bit lengths for the remaining symbols, len is the code length of the next - processed symbol */ -function NextTableBitSize(count, len, root_bits) { - var left = 1 << (len - root_bits); - while (len < MAX_LENGTH) { - left -= count[len]; - if (left <= 0) break; - ++len; - left <<= 1; - } - return len - root_bits; -} - -exports.BrotliBuildHuffmanTable = function(root_table, table, root_bits, code_lengths, code_lengths_size) { - var start_table = table; - var code; /* current table entry */ - var len; /* current code length */ - var symbol; /* symbol index in original or sorted table */ - var key; /* reversed prefix code */ - var step; /* step size to replicate values in current table */ - var low; /* low bits for current root entry */ - var mask; /* mask for low bits */ - var table_bits; /* key length of current table */ - var table_size; /* size of current table */ - var total_size; /* sum of root table size and 2nd level table sizes */ - var sorted; /* symbols sorted by code length */ - var count = new Int32Array(MAX_LENGTH + 1); /* number of codes of each length */ - var offset = new Int32Array(MAX_LENGTH + 1); /* offsets in sorted table for each length */ - - sorted = new Int32Array(code_lengths_size); - - /* build histogram of code lengths */ - for (symbol = 0; symbol < code_lengths_size; symbol++) { - count[code_lengths[symbol]]++; - } - - /* generate offsets into sorted symbol table by code length */ - offset[1] = 0; - for (len = 1; len < MAX_LENGTH; len++) { - offset[len + 1] = offset[len] + count[len]; - } - - /* sort symbols by length, by symbol order within each length */ - for (symbol = 0; symbol < code_lengths_size; symbol++) { - if (code_lengths[symbol] !== 0) { - sorted[offset[code_lengths[symbol]]++] = symbol; - } - } - - table_bits = root_bits; - table_size = 1 << table_bits; - total_size = table_size; - - /* special case code with only one value */ - if (offset[MAX_LENGTH] === 1) { - for (key = 0; key < total_size; ++key) { - root_table[table + key] = new HuffmanCode(0, sorted[0] & 0xffff); - } - - return total_size; - } - - /* fill in root table */ - key = 0; - symbol = 0; - for (len = 1, step = 2; len <= root_bits; ++len, step <<= 1) { - for (; count[len] > 0; --count[len]) { - code = new HuffmanCode(len & 0xff, sorted[symbol++] & 0xffff); - ReplicateValue(root_table, table + key, step, table_size, code); - key = GetNextKey(key, len); - } - } - - /* fill in 2nd level tables and add pointers to root table */ - mask = total_size - 1; - low = -1; - for (len = root_bits + 1, step = 2; len <= MAX_LENGTH; ++len, step <<= 1) { - for (; count[len] > 0; --count[len]) { - if ((key & mask) !== low) { - table += table_size; - table_bits = NextTableBitSize(count, len, root_bits); - table_size = 1 << table_bits; - total_size += table_size; - low = key & mask; - root_table[start_table + low] = new HuffmanCode((table_bits + root_bits) & 0xff, ((table - start_table) - low) & 0xffff); - } - code = new HuffmanCode((len - root_bits) & 0xff, sorted[symbol++] & 0xffff); - ReplicateValue(root_table, table + (key >> root_bits), step, table_size, code); - key = GetNextKey(key, len); - } - } - - return total_size; -} - - -/***/ }), -/* 121 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(Buffer) {// Generated by CoffeeScript 1.12.6 - -/* -PDFImage - embeds images in PDF documents -By Devon Govett - */ - -(function() { - var Data, JPEG, PDFImage, PNG, fs; - - fs = __webpack_require__(8); - - Data = __webpack_require__(298); - - JPEG = __webpack_require__(299); - - PNG = __webpack_require__(300); - - PDFImage = (function() { - function PDFImage() {} - - PDFImage.open = function(src, label) { - var data, match; - if (Buffer.isBuffer(src)) { - data = src; - } else if (src instanceof ArrayBuffer) { - data = new Buffer(new Uint8Array(src)); - } else { - if (match = /^data:.+;base64,(.*)$/.exec(src)) { - data = new Buffer(match[1], 'base64'); - } else { - data = fs.readFileSync(src); - if (!data) { - return; - } - } - } - if (data[0] === 0xff && data[1] === 0xd8) { - return new JPEG(data, label); - } else if (data[0] === 0x89 && data.toString('ascii', 1, 4) === 'PNG') { - return new PNG(data, label); - } else { - throw new Error('Unknown image format.'); - } - }; - - return PDFImage; - - })(); - - module.exports = PDFImage; - -}).call(this); - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1).Buffer)) - -/***/ }), -/* 122 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(global) {module.exports = global["pdfMake"] = __webpack_require__(123); -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(7))) - -/***/ }), -/* 123 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/* WEBPACK VAR INJECTION */(function(Buffer, global) { - -var PdfPrinter = __webpack_require__(126); -var isFunction = __webpack_require__(0).isFunction; -var FileSaver = __webpack_require__(306); -var saveAs = FileSaver.saveAs; - -var defaultClientFonts = { - Roboto: { - normal: 'Roboto-Regular.ttf', - bold: 'Roboto-Medium.ttf', - italics: 'Roboto-Italic.ttf', - bolditalics: 'Roboto-MediumItalic.ttf' - } -}; - -function Document(docDefinition, tableLayouts, fonts, vfs) { - this.docDefinition = docDefinition; - this.tableLayouts = tableLayouts || null; - this.fonts = fonts || defaultClientFonts; - this.vfs = vfs; -} - -function canCreatePdf() { - // Ensure the browser provides the level of support needed - if (!Object.keys) { - return false; - } - return true; -} - -Document.prototype._createDoc = function (options, callback) { - options = options || {}; - if (this.tableLayouts) { - options.tableLayouts = this.tableLayouts; - } - - var printer = new PdfPrinter(this.fonts); - __webpack_require__(8).bindFS(this.vfs); // bind virtual file system to file system - - var doc = printer.createPdfKitDocument(this.docDefinition, options); - var chunks = []; - var result; - - doc.on('readable', function () { - var chunk; - while ((chunk = doc.read(9007199254740991)) !== null) { - chunks.push(chunk); - } - }); - doc.on('end', function () { - result = Buffer.concat(chunks); - callback(result, doc._pdfMakePages); - }); - doc.end(); -}; - -Document.prototype._getPages = function (options, cb) { - if (!cb) { - throw '_getPages is an async method and needs a callback argument'; - } - this._createDoc(options, function (ignoreBuffer, pages) { - cb(pages); - }); -}; - -Document.prototype._bufferToBlob = function (buffer) { - var blob; - try { - blob = new Blob([buffer], {type: 'application/pdf'}); - } catch (e) { - // Old browser which can't handle it without making it an byte array (ie10) - if (e.name === 'InvalidStateError') { - var byteArray = new Uint8Array(buffer); - blob = new Blob([byteArray.buffer], {type: 'application/pdf'}); - } - } - - if (!blob) { - throw 'Could not generate blob'; - } - - return blob; -}; - -Document.prototype._openWindow = function () { - // we have to open the window immediately and store the reference - // otherwise popup blockers will stop us - var win = window.open('', '_blank'); - if (win === null) { - throw 'Open PDF in new window blocked by browser'; - } - - return win; -}; - -Document.prototype._openPdf = function (options, win) { - if (!win) { - win = this._openWindow(); - } - try { - this.getBlob(function (result) { - var urlCreator = window.URL || window.webkitURL; - var pdfUrl = urlCreator.createObjectURL(result); - win.location.href = pdfUrl; - }, options); - } catch (e) { - win.close(); - throw e; - } -}; - -Document.prototype.open = function (options, win) { - options = options || {}; - options.autoPrint = false; - win = win || null; - - this._openPdf(options, win); -}; - - -Document.prototype.print = function (options, win) { - options = options || {}; - options.autoPrint = true; - win = win || null; - - this._openPdf(options, win); -}; - -Document.prototype.download = function (defaultFileName, cb, options) { - if (isFunction(defaultFileName)) { - cb = defaultFileName; - defaultFileName = null; - } - - defaultFileName = defaultFileName || 'file.pdf'; - this.getBlob(function (result) { - saveAs(result, defaultFileName); - - if (isFunction(cb)) { - cb(); - } - }, options); -}; - -Document.prototype.getBase64 = function (cb, options) { - if (!cb) { - throw 'getBase64 is an async method and needs a callback argument'; - } - this.getBuffer(function (buffer) { - cb(buffer.toString('base64')); - }, options); -}; - -Document.prototype.getDataUrl = function (cb, options) { - if (!cb) { - throw 'getDataUrl is an async method and needs a callback argument'; - } - this.getBuffer(function (buffer) { - cb('data:application/pdf;base64,' + buffer.toString('base64')); - }, options); -}; - -Document.prototype.getBlob = function (cb, options) { - if (!cb) { - throw 'getBlob is an async method and needs a callback argument'; - } - var that = this; - this.getBuffer(function (result) { - var blob = that._bufferToBlob(result); - cb(blob); - }, options); -}; - -Document.prototype.getBuffer = function (cb, options) { - if (!cb) { - throw 'getBuffer is an async method and needs a callback argument'; - } - this._createDoc(options, function (buffer) { - cb(buffer); - }); -}; - -module.exports = { - createPdf: function (docDefinition) { - if (!canCreatePdf()) { - throw 'Your browser does not provide the level of support needed'; - } - return new Document(docDefinition, global.pdfMake.tableLayouts, global.pdfMake.fonts, global.pdfMake.vfs); - } -}; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1).Buffer, __webpack_require__(7))) - -/***/ }), -/* 124 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -exports.byteLength = byteLength -exports.toByteArray = toByteArray -exports.fromByteArray = fromByteArray - -var lookup = [] -var revLookup = [] -var Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array - -var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' -for (var i = 0, len = code.length; i < len; ++i) { - lookup[i] = code[i] - revLookup[code.charCodeAt(i)] = i -} - -// Support decoding URL-safe base64 strings, as Node.js does. -// See: https://en.wikipedia.org/wiki/Base64#URL_applications -revLookup['-'.charCodeAt(0)] = 62 -revLookup['_'.charCodeAt(0)] = 63 - -function placeHoldersCount (b64) { - var len = b64.length - if (len % 4 > 0) { - throw new Error('Invalid string. Length must be a multiple of 4') - } - - // the number of equal signs (place holders) - // if there are two placeholders, than the two characters before it - // represent one byte - // if there is only one, then the three characters before it represent 2 bytes - // this is just a cheap hack to not do indexOf twice - return b64[len - 2] === '=' ? 2 : b64[len - 1] === '=' ? 1 : 0 -} - -function byteLength (b64) { - // base64 is 4/3 + up to two characters of the original data - return (b64.length * 3 / 4) - placeHoldersCount(b64) -} - -function toByteArray (b64) { - var i, l, tmp, placeHolders, arr - var len = b64.length - placeHolders = placeHoldersCount(b64) - - arr = new Arr((len * 3 / 4) - placeHolders) - - // if there are placeholders, only get up to the last complete 4 chars - l = placeHolders > 0 ? len - 4 : len - - var L = 0 - - for (i = 0; i < l; i += 4) { - tmp = (revLookup[b64.charCodeAt(i)] << 18) | (revLookup[b64.charCodeAt(i + 1)] << 12) | (revLookup[b64.charCodeAt(i + 2)] << 6) | revLookup[b64.charCodeAt(i + 3)] - arr[L++] = (tmp >> 16) & 0xFF - arr[L++] = (tmp >> 8) & 0xFF - arr[L++] = tmp & 0xFF - } - - if (placeHolders === 2) { - tmp = (revLookup[b64.charCodeAt(i)] << 2) | (revLookup[b64.charCodeAt(i + 1)] >> 4) - arr[L++] = tmp & 0xFF - } else if (placeHolders === 1) { - tmp = (revLookup[b64.charCodeAt(i)] << 10) | (revLookup[b64.charCodeAt(i + 1)] << 4) | (revLookup[b64.charCodeAt(i + 2)] >> 2) - arr[L++] = (tmp >> 8) & 0xFF - arr[L++] = tmp & 0xFF - } - - return arr -} - -function tripletToBase64 (num) { - return lookup[num >> 18 & 0x3F] + lookup[num >> 12 & 0x3F] + lookup[num >> 6 & 0x3F] + lookup[num & 0x3F] -} - -function encodeChunk (uint8, start, end) { - var tmp - var output = [] - for (var i = start; i < end; i += 3) { - tmp = ((uint8[i] << 16) & 0xFF0000) + ((uint8[i + 1] << 8) & 0xFF00) + (uint8[i + 2] & 0xFF) - output.push(tripletToBase64(tmp)) - } - return output.join('') -} - -function fromByteArray (uint8) { - var tmp - var len = uint8.length - var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes - var output = '' - var parts = [] - var maxChunkLength = 16383 // must be multiple of 3 - - // go through the array every three bytes, we'll deal with trailing stuff later - for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) { - parts.push(encodeChunk(uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength))) - } - - // pad the end with zeros, but make sure to not forget the extra bytes - if (extraBytes === 1) { - tmp = uint8[len - 1] - output += lookup[tmp >> 2] - output += lookup[(tmp << 4) & 0x3F] - output += '==' - } else if (extraBytes === 2) { - tmp = (uint8[len - 2] << 8) + (uint8[len - 1]) - output += lookup[tmp >> 10] - output += lookup[(tmp >> 4) & 0x3F] - output += lookup[(tmp << 2) & 0x3F] - output += '=' - } - - parts.push(output) - - return parts.join('') -} - - -/***/ }), -/* 125 */ -/***/ (function(module, exports) { - -exports.read = function (buffer, offset, isLE, mLen, nBytes) { - var e, m - var eLen = nBytes * 8 - mLen - 1 - var eMax = (1 << eLen) - 1 - var eBias = eMax >> 1 - var nBits = -7 - var i = isLE ? (nBytes - 1) : 0 - var d = isLE ? -1 : 1 - var s = buffer[offset + i] - - i += d - - e = s & ((1 << (-nBits)) - 1) - s >>= (-nBits) - nBits += eLen - for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {} - - m = e & ((1 << (-nBits)) - 1) - e >>= (-nBits) - nBits += mLen - for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {} - - if (e === 0) { - e = 1 - eBias - } else if (e === eMax) { - return m ? NaN : ((s ? -1 : 1) * Infinity) - } else { - m = m + Math.pow(2, mLen) - e = e - eBias - } - return (s ? -1 : 1) * m * Math.pow(2, e - mLen) -} - -exports.write = function (buffer, value, offset, isLE, mLen, nBytes) { - var e, m, c - var eLen = nBytes * 8 - mLen - 1 - var eMax = (1 << eLen) - 1 - var eBias = eMax >> 1 - var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0) - var i = isLE ? 0 : (nBytes - 1) - var d = isLE ? 1 : -1 - var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0 - - value = Math.abs(value) - - if (isNaN(value) || value === Infinity) { - m = isNaN(value) ? 1 : 0 - e = eMax - } else { - e = Math.floor(Math.log(value) / Math.LN2) - if (value * (c = Math.pow(2, -e)) < 1) { - e-- - c *= 2 - } - if (e + eBias >= 1) { - value += rt / c - } else { - value += rt * Math.pow(2, 1 - eBias) - } - if (value * c >= 2) { - e++ - c /= 2 - } - - if (e + eBias >= eMax) { - m = 0 - e = eMax - } else if (e + eBias >= 1) { - m = (value * c - 1) * Math.pow(2, mLen) - e = e + eBias - } else { - m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen) - e = 0 - } - } - - for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {} - - e = (e << mLen) | m - eLen += mLen - for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {} - - buffer[offset + i - d] |= s * 128 -} - - -/***/ }), -/* 126 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*eslint no-unused-vars: ["error", {"args": "none"}]*/ - - -var FontProvider = __webpack_require__(127); -var LayoutBuilder = __webpack_require__(128); -var PdfKit = __webpack_require__(138); -var sizes = __webpack_require__(303); -var ImageMeasure = __webpack_require__(304); -var textDecorator = __webpack_require__(305); -var TextTools = __webpack_require__(42); -var isFunction = __webpack_require__(0).isFunction; -var isString = __webpack_require__(0).isString; -var isNumber = __webpack_require__(0).isNumber; -var isBoolean = __webpack_require__(0).isBoolean; -var isArray = __webpack_require__(0).isArray; - -//////////////////////////////////////// -// PdfPrinter - -/** - * @class Creates an instance of a PdfPrinter which turns document definition into a pdf - * - * @param {Object} fontDescriptors font definition dictionary - * - * @example - * var fontDescriptors = { - * Roboto: { - * normal: 'fonts/Roboto-Regular.ttf', - * bold: 'fonts/Roboto-Medium.ttf', - * italics: 'fonts/Roboto-Italic.ttf', - * bolditalics: 'fonts/Roboto-MediumItalic.ttf' - * } - * }; - * - * var printer = new PdfPrinter(fontDescriptors); - */ -function PdfPrinter(fontDescriptors) { - this.fontDescriptors = fontDescriptors; -} - -/** - * Executes layout engine for the specified document and renders it into a pdfkit document - * ready to be saved. - * - * @param {Object} docDefinition document definition - * @param {Object} docDefinition.content an array describing the pdf structure (for more information take a look at the examples in the /examples folder) - * @param {Object} [docDefinition.defaultStyle] default (implicit) style definition - * @param {Object} [docDefinition.styles] dictionary defining all styles which can be used in the document - * @param {Object} [docDefinition.pageSize] page size (pdfkit units, A4 dimensions by default) - * @param {Number} docDefinition.pageSize.width width - * @param {Number} docDefinition.pageSize.height height - * @param {Object} [docDefinition.pageMargins] page margins (pdfkit units) - * @param {Number} docDefinition.maxPagesNumber maximum number of pages to render - * - * @example - * - * var docDefinition = { - * info: { - * title: 'awesome Document', - * author: 'john doe', - * subject: 'subject of document', - * keywords: 'keywords for document', - * }, - * content: [ - * 'First paragraph', - * 'Second paragraph, this time a little bit longer', - * { text: 'Third paragraph, slightly bigger font size', fontSize: 20 }, - * { text: 'Another paragraph using a named style', style: 'header' }, - * { text: ['playing with ', 'inlines' ] }, - * { text: ['and ', { text: 'restyling ', bold: true }, 'them'] }, - * ], - * styles: { - * header: { fontSize: 30, bold: true } - * } - * } - * - * var pdfKitDoc = printer.createPdfKitDocument(docDefinition); - * - * pdfKitDoc.pipe(fs.createWriteStream('sample.pdf')); - * pdfKitDoc.end(); - * - * @return {Object} a pdfKit document object which can be saved or encode to data-url - */ -PdfPrinter.prototype.createPdfKitDocument = function (docDefinition, options) { - options = options || {}; - - var pageSize = fixPageSize(docDefinition.pageSize, docDefinition.pageOrientation); - var compressPdf = isBoolean(docDefinition.compress) ? docDefinition.compress : true; - - this.pdfKitDoc = new PdfKit({size: [pageSize.width, pageSize.height], autoFirstPage: false, compress: compressPdf}); - setMetadata(docDefinition, this.pdfKitDoc); - - this.fontProvider = new FontProvider(this.fontDescriptors, this.pdfKitDoc); - - docDefinition.images = docDefinition.images || {}; - - var builder = new LayoutBuilder(pageSize, fixPageMargins(docDefinition.pageMargins || 40), new ImageMeasure(this.pdfKitDoc, docDefinition.images)); - - registerDefaultTableLayouts(builder); - if (options.tableLayouts) { - builder.registerTableLayouts(options.tableLayouts); - } - - var pages = builder.layoutDocument(docDefinition.content, this.fontProvider, docDefinition.styles || {}, docDefinition.defaultStyle || {fontSize: 12, font: 'Roboto'}, docDefinition.background, docDefinition.header, docDefinition.footer, docDefinition.images, docDefinition.watermark, docDefinition.pageBreakBefore); - var maxNumberPages = docDefinition.maxPagesNumber || -1; - if (isNumber(maxNumberPages) && maxNumberPages > -1) { - pages = pages.slice(0, maxNumberPages); - } - - // if pageSize.height is set to Infinity, calculate the actual height of the page that - // was laid out using the height of each of the items in the page. - if (pageSize.height === Infinity) { - var pageHeight = calculatePageHeight(pages, docDefinition.pageMargins); - this.pdfKitDoc.options.size = [pageSize.width, pageHeight]; - } - - renderPages(pages, this.fontProvider, this.pdfKitDoc, options.progressCallback); - - if (options.autoPrint) { - var printActionRef = this.pdfKitDoc.ref({ - Type: 'Action', - S: 'Named', - N: 'Print' - }); - this.pdfKitDoc._root.data.OpenAction = printActionRef; - printActionRef.end(); - } - return this.pdfKitDoc; -}; - -function setMetadata(docDefinition, pdfKitDoc) { - // PDF standard has these properties reserved: Title, Author, Subject, Keywords, - // Creator, Producer, CreationDate, ModDate, Trapped. - // To keep the pdfmake api consistent, the info field are defined lowercase. - // Custom properties don't contain a space. - function standardizePropertyKey(key) { - var standardProperties = ['Title', 'Author', 'Subject', 'Keywords', - 'Creator', 'Producer', 'CreationDate', 'ModDate', 'Trapped']; - var standardizedKey = key.charAt(0).toUpperCase() + key.slice(1); - if (standardProperties.indexOf(standardizedKey) !== -1) { - return standardizedKey; - } - - return key.replace(/\s+/g, ''); - } - - pdfKitDoc.info.Producer = 'pdfmake'; - pdfKitDoc.info.Creator = 'pdfmake'; - - if (docDefinition.info) { - for (var key in docDefinition.info) { - var value = docDefinition.info[key]; - if (value) { - key = standardizePropertyKey(key); - pdfKitDoc.info[key] = value; - } - } - } -} - -function calculatePageHeight(pages, margins) { - function getItemHeight(item) { - if (isFunction(item.item.getHeight)) { - return item.item.getHeight(); - } else if (item.item._height) { - return item.item._height; - } else { - // TODO: add support for next item types - return 0; - } - } - - var fixedMargins = fixPageMargins(margins || 40); - var height = fixedMargins.top + fixedMargins.bottom; - pages.forEach(function (page) { - page.items.forEach(function (item) { - height += getItemHeight(item); - }); - }); - return height; -} - -function fixPageSize(pageSize, pageOrientation) { - function isNeedSwapPageSizes(pageOrientation) { - if (isString(pageOrientation)) { - pageOrientation = pageOrientation.toLowerCase(); - return ((pageOrientation === 'portrait') && (size.width > size.height)) || - ((pageOrientation === 'landscape') && (size.width < size.height)); - } - return false; - } - - // if pageSize.height is set to auto, set the height to infinity so there are no page breaks. - if (pageSize && pageSize.height === 'auto') { - pageSize.height = Infinity; - } - - var size = pageSize2widthAndHeight(pageSize || 'A4'); - if (isNeedSwapPageSizes(pageOrientation)) { // swap page sizes - size = {width: size.height, height: size.width}; - } - size.orientation = size.width > size.height ? 'landscape' : 'portrait'; - return size; -} - -function fixPageMargins(margin) { - if (!margin) { - return null; - } - - if (isNumber(margin)) { - margin = {left: margin, right: margin, top: margin, bottom: margin}; - } else if (isArray(margin)) { - if (margin.length === 2) { - margin = {left: margin[0], top: margin[1], right: margin[0], bottom: margin[1]}; - } else if (margin.length === 4) { - margin = {left: margin[0], top: margin[1], right: margin[2], bottom: margin[3]}; - } else { - throw 'Invalid pageMargins definition'; - } - } - - return margin; -} - -function registerDefaultTableLayouts(layoutBuilder) { - layoutBuilder.registerTableLayouts({ - noBorders: { - hLineWidth: function (i) { - return 0; - }, - vLineWidth: function (i) { - return 0; - }, - paddingLeft: function (i) { - return i && 4 || 0; - }, - paddingRight: function (i, node) { - return (i < node.table.widths.length - 1) ? 4 : 0; - } - }, - headerLineOnly: { - hLineWidth: function (i, node) { - if (i === 0 || i === node.table.body.length) { - return 0; - } - return (i === node.table.headerRows) ? 2 : 0; - }, - vLineWidth: function (i) { - return 0; - }, - paddingLeft: function (i) { - return i === 0 ? 0 : 8; - }, - paddingRight: function (i, node) { - return (i === node.table.widths.length - 1) ? 0 : 8; - } - }, - lightHorizontalLines: { - hLineWidth: function (i, node) { - if (i === 0 || i === node.table.body.length) { - return 0; - } - return (i === node.table.headerRows) ? 2 : 1; - }, - vLineWidth: function (i) { - return 0; - }, - hLineColor: function (i) { - return i === 1 ? 'black' : '#aaa'; - }, - paddingLeft: function (i) { - return i === 0 ? 0 : 8; - }, - paddingRight: function (i, node) { - return (i === node.table.widths.length - 1) ? 0 : 8; - } - } - }); -} - -function pageSize2widthAndHeight(pageSize) { - if (isString(pageSize)) { - var size = sizes[pageSize.toUpperCase()]; - if (!size) { - throw 'Page size ' + pageSize + ' not recognized'; - } - return {width: size[0], height: size[1]}; - } - - return pageSize; -} - -function updatePageOrientationInOptions(currentPage, pdfKitDoc) { - var previousPageOrientation = pdfKitDoc.options.size[0] > pdfKitDoc.options.size[1] ? 'landscape' : 'portrait'; - - if (currentPage.pageSize.orientation !== previousPageOrientation) { - var width = pdfKitDoc.options.size[0]; - var height = pdfKitDoc.options.size[1]; - pdfKitDoc.options.size = [height, width]; - } -} - -function renderPages(pages, fontProvider, pdfKitDoc, progressCallback) { - pdfKitDoc._pdfMakePages = pages; - pdfKitDoc.addPage(); - - var totalItems = 0; - if (progressCallback) { - pages.forEach(function (page) { - totalItems += page.items.length; - }); - } - - var renderedItems = 0; - progressCallback = progressCallback || function () {}; - - for (var i = 0; i < pages.length; i++) { - if (i > 0) { - updatePageOrientationInOptions(pages[i], pdfKitDoc); - pdfKitDoc.addPage(pdfKitDoc.options); - } - - var page = pages[i]; - for (var ii = 0, il = page.items.length; ii < il; ii++) { - var item = page.items[ii]; - switch (item.type) { - case 'vector': - renderVector(item.item, pdfKitDoc); - break; - case 'line': - renderLine(item.item, item.item.x, item.item.y, pdfKitDoc); - break; - case 'image': - renderImage(item.item, item.item.x, item.item.y, pdfKitDoc); - break; - case 'beginClip': - beginClip(item.item, pdfKitDoc); - break; - case 'endClip': - endClip(pdfKitDoc); - break; - } - renderedItems++; - progressCallback(renderedItems / totalItems); - } - if (page.watermark) { - renderWatermark(page, pdfKitDoc); - } - } -} - -function renderLine(line, x, y, pdfKitDoc) { - if (line._pageNodeRef) { - var newWidth; - var diffWidth; - var textTools = new TextTools(null); - var pageNumber = line._pageNodeRef.positions[0].pageNumber.toString(); - - line.inlines[0].text = pageNumber; - line.inlines[0].linkToPage = pageNumber; - newWidth = textTools.widthOfString(line.inlines[0].text, line.inlines[0].font, line.inlines[0].fontSize, line.inlines[0].characterSpacing, line.inlines[0].fontFeatures); - diffWidth = line.inlines[0].width - newWidth; - line.inlines[0].width = newWidth; - - switch (line.inlines[0].alignment) { - case 'right': - line.inlines[0].x += diffWidth; - break; - case 'center': - line.inlines[0].x += diffWidth / 2; - break; - } - } - - x = x || 0; - y = y || 0; - - var lineHeight = line.getHeight(); - var ascenderHeight = line.getAscenderHeight(); - var descent = lineHeight - ascenderHeight; - - textDecorator.drawBackground(line, x, y, pdfKitDoc); - - //TODO: line.optimizeInlines(); - for (var i = 0, l = line.inlines.length; i < l; i++) { - var inline = line.inlines[i]; - var shiftToBaseline = lineHeight - ((inline.font.ascender / 1000) * inline.fontSize) - descent; - var options = { - lineBreak: false, - textWidth: inline.width, - characterSpacing: inline.characterSpacing, - wordCount: 1, - link: inline.link - }; - - if (inline.fontFeatures) { - options.features = inline.fontFeatures; - } - - pdfKitDoc.fill(inline.color || 'black'); - - pdfKitDoc._font = inline.font; - pdfKitDoc.fontSize(inline.fontSize); - pdfKitDoc.text(inline.text, x + inline.x, y + shiftToBaseline, options); - - if (inline.linkToPage) { - var _ref = pdfKitDoc.ref({Type: 'Action', S: 'GoTo', D: [inline.linkToPage, 0, 0]}).end(); - pdfKitDoc.annotate(x + inline.x, y + shiftToBaseline, inline.width, inline.height, {Subtype: 'Link', Dest: [inline.linkToPage - 1, 'XYZ', null, null, null]}); - } - - } - - textDecorator.drawDecorations(line, x, y, pdfKitDoc); -} - -function renderWatermark(page, pdfKitDoc) { - var watermark = page.watermark; - - pdfKitDoc.fill(watermark.color); - pdfKitDoc.opacity(watermark.opacity); - - pdfKitDoc.save(); - - var angle = Math.atan2(pdfKitDoc.page.height, pdfKitDoc.page.width) * -180 / Math.PI; - pdfKitDoc.rotate(angle, {origin: [pdfKitDoc.page.width / 2, pdfKitDoc.page.height / 2]}); - - var x = pdfKitDoc.page.width / 2 - watermark.size.size.width / 2; - var y = pdfKitDoc.page.height / 2 - watermark.size.size.height / 4; - - pdfKitDoc._font = watermark.font; - pdfKitDoc.fontSize(watermark.size.fontSize); - pdfKitDoc.text(watermark.text, x, y, {lineBreak: false}); - - pdfKitDoc.restore(); -} - -function renderVector(vector, pdfKitDoc) { - //TODO: pdf optimization (there's no need to write all properties everytime) - pdfKitDoc.lineWidth(vector.lineWidth || 1); - if (vector.dash) { - pdfKitDoc.dash(vector.dash.length, {space: vector.dash.space || vector.dash.length, phase: vector.dash.phase || 0}); - } else { - pdfKitDoc.undash(); - } - pdfKitDoc.lineJoin(vector.lineJoin || 'miter'); - pdfKitDoc.lineCap(vector.lineCap || 'butt'); - - //TODO: clipping - - switch (vector.type) { - case 'ellipse': - pdfKitDoc.ellipse(vector.x, vector.y, vector.r1, vector.r2); - break; - case 'rect': - if (vector.r) { - pdfKitDoc.roundedRect(vector.x, vector.y, vector.w, vector.h, vector.r); - } else { - pdfKitDoc.rect(vector.x, vector.y, vector.w, vector.h); - } - - if (vector.linearGradient) { - var gradient = pdfKitDoc.linearGradient(vector.x, vector.y, vector.x + vector.w, vector.y); - var step = 1 / (vector.linearGradient.length - 1); - - for (var i = 0; i < vector.linearGradient.length; i++) { - gradient.stop(i * step, vector.linearGradient[i]); - } - - vector.color = gradient; - } - break; - case 'line': - pdfKitDoc.moveTo(vector.x1, vector.y1); - pdfKitDoc.lineTo(vector.x2, vector.y2); - break; - case 'polyline': - if (vector.points.length === 0) { - break; - } - - pdfKitDoc.moveTo(vector.points[0].x, vector.points[0].y); - for (var i = 1, l = vector.points.length; i < l; i++) { - pdfKitDoc.lineTo(vector.points[i].x, vector.points[i].y); - } - - if (vector.points.length > 1) { - var p1 = vector.points[0]; - var pn = vector.points[vector.points.length - 1]; - - if (vector.closePath || p1.x === pn.x && p1.y === pn.y) { - pdfKitDoc.closePath(); - } - } - break; - case 'path': - pdfKitDoc.path(vector.d); - break; - } - - if (vector.color && vector.lineColor) { - pdfKitDoc.fillColor(vector.color, vector.fillOpacity || 1); - pdfKitDoc.strokeColor(vector.lineColor, vector.strokeOpacity || 1); - pdfKitDoc.fillAndStroke(); - } else if (vector.color) { - pdfKitDoc.fillColor(vector.color, vector.fillOpacity || 1); - pdfKitDoc.fill(); - } else { - pdfKitDoc.strokeColor(vector.lineColor || 'black', vector.strokeOpacity || 1); - pdfKitDoc.stroke(); - } -} - -function renderImage(image, x, y, pdfKitDoc) { - pdfKitDoc.image(image.image, image.x, image.y, {width: image._width, height: image._height}); - if (image.link) { - pdfKitDoc.link(image.x, image.y, image._width, image._height, image.link); - } -} - -function beginClip(rect, pdfKitDoc) { - pdfKitDoc.save(); - pdfKitDoc.addContent('' + rect.x + ' ' + rect.y + ' ' + rect.width + ' ' + rect.height + ' re'); - pdfKitDoc.clip(); -} - -function endClip(pdfKitDoc) { - pdfKitDoc.restore(); -} - -module.exports = PdfPrinter; - - -/***/ }), -/* 127 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var isArray = __webpack_require__(0).isArray; - -function typeName(bold, italics) { - var type = 'normal'; - if (bold && italics) { - type = 'bolditalics'; - } else if (bold) { - type = 'bold'; - } else if (italics) { - type = 'italics'; - } - return type; -} - -function FontProvider(fontDescriptors, pdfKitDoc) { - this.fonts = {}; - this.pdfKitDoc = pdfKitDoc; - this.fontCache = {}; - - for (var font in fontDescriptors) { - if (fontDescriptors.hasOwnProperty(font)) { - var fontDef = fontDescriptors[font]; - - this.fonts[font] = { - normal: fontDef.normal, - bold: fontDef.bold, - italics: fontDef.italics, - bolditalics: fontDef.bolditalics - }; - } - } -} - -FontProvider.prototype.provideFont = function (familyName, bold, italics) { - var type = typeName(bold, italics); - if (!this.fonts[familyName] || !this.fonts[familyName][type]) { - throw new Error('Font \'' + familyName + '\' in style \'' + type + '\' is not defined in the font section of the document definition.'); - } - - this.fontCache[familyName] = this.fontCache[familyName] || {}; - - if (!this.fontCache[familyName][type]) { - var def = this.fonts[familyName][type]; - if (!isArray(def)) { - def = [def]; - } - this.fontCache[familyName][type] = this.pdfKitDoc.font.apply(this.pdfKitDoc, def)._font; - } - - return this.fontCache[familyName][type]; -}; - -module.exports = FontProvider; - - -/***/ }), -/* 128 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var TraversalTracker = __webpack_require__(77); -var DocPreprocessor = __webpack_require__(129); -var DocMeasure = __webpack_require__(130); -var DocumentContext = __webpack_require__(81); -var PageElementWriter = __webpack_require__(135); -var ColumnCalculator = __webpack_require__(44); -var TableProcessor = __webpack_require__(137); -var Line = __webpack_require__(82); -var isString = __webpack_require__(0).isString; -var isArray = __webpack_require__(0).isArray; -var pack = __webpack_require__(0).pack; -var offsetVector = __webpack_require__(0).offsetVector; -var fontStringify = __webpack_require__(0).fontStringify; -var isFunction = __webpack_require__(0).isFunction; -var TextTools = __webpack_require__(42); -var StyleContextStack = __webpack_require__(80); - -function addAll(target, otherArray) { - otherArray.forEach(function (item) { - target.push(item); - }); -} - -/** - * Creates an instance of LayoutBuilder - layout engine which turns document-definition-object - * into a set of pages, lines, inlines and vectors ready to be rendered into a PDF - * - * @param {Object} pageSize - an object defining page width and height - * @param {Object} pageMargins - an object defining top, left, right and bottom margins - */ -function LayoutBuilder(pageSize, pageMargins, imageMeasure) { - this.pageSize = pageSize; - this.pageMargins = pageMargins; - this.tracker = new TraversalTracker(); - this.imageMeasure = imageMeasure; - this.tableLayouts = {}; -} - -LayoutBuilder.prototype.registerTableLayouts = function (tableLayouts) { - this.tableLayouts = pack(this.tableLayouts, tableLayouts); -}; - -/** - * Executes layout engine on document-definition-object and creates an array of pages - * containing positioned Blocks, Lines and inlines - * - * @param {Object} docStructure document-definition-object - * @param {Object} fontProvider font provider - * @param {Object} styleDictionary dictionary with style definitions - * @param {Object} defaultStyle default style definition - * @return {Array} an array of pages - */ -LayoutBuilder.prototype.layoutDocument = function (docStructure, fontProvider, styleDictionary, defaultStyle, background, header, footer, images, watermark, pageBreakBeforeFct) { - - function addPageBreaksIfNecessary(linearNodeList, pages) { - - if (!isFunction(pageBreakBeforeFct)) { - return false; - } - - linearNodeList = linearNodeList.filter(function (node) { - return node.positions.length > 0; - }); - - linearNodeList.forEach(function (node) { - var nodeInfo = {}; - [ - 'id', 'text', 'ul', 'ol', 'table', 'image', 'qr', 'canvas', 'columns', - 'headlineLevel', 'style', 'pageBreak', 'pageOrientation', - 'width', 'height' - ].forEach(function (key) { - if (node[key] !== undefined) { - nodeInfo[key] = node[key]; - } - }); - nodeInfo.startPosition = node.positions[0]; - nodeInfo.pageNumbers = node.positions.map(function (node) { - return node.pageNumber; - }).filter(function (element, position, array) { - return array.indexOf(element) === position; - }); - nodeInfo.pages = pages.length; - nodeInfo.stack = isArray(node.stack); - - node.nodeInfo = nodeInfo; - }); - - return linearNodeList.some(function (node, index, followingNodeList) { - if (node.pageBreak !== 'before' && !node.pageBreakCalculated) { - node.pageBreakCalculated = true; - var pageNumber = node.nodeInfo.pageNumbers[0]; - - var followingNodesOnPage = followingNodeList.slice(index + 1).filter(function (node0) { - return node0.nodeInfo.pageNumbers.indexOf(pageNumber) > -1; - }); - - var nodesOnNextPage = followingNodeList.slice(index + 1).filter(function (node0) { - return node0.nodeInfo.pageNumbers.indexOf(pageNumber + 1) > -1; - }); - - var previousNodesOnPage = followingNodeList.slice(0, index).filter(function (node0) { - return node0.nodeInfo.pageNumbers.indexOf(pageNumber) > -1; - }); - - if ( - pageBreakBeforeFct( - node.nodeInfo, - followingNodesOnPage.map(function (node) { - return node.nodeInfo; - }), - nodesOnNextPage.map(function (node) { - return node.nodeInfo; - }), - previousNodesOnPage.map(function (node) { - return node.nodeInfo; - }))) { - node.pageBreak = 'before'; - return true; - } - } - }); - } - - this.docPreprocessor = new DocPreprocessor(); - this.docMeasure = new DocMeasure(fontProvider, styleDictionary, defaultStyle, this.imageMeasure, this.tableLayouts, images); - - - function resetXYs(result) { - result.linearNodeList.forEach(function (node) { - node.resetXY(); - }); - } - - var result = this.tryLayoutDocument(docStructure, fontProvider, styleDictionary, defaultStyle, background, header, footer, images, watermark); - while (addPageBreaksIfNecessary(result.linearNodeList, result.pages)) { - resetXYs(result); - result = this.tryLayoutDocument(docStructure, fontProvider, styleDictionary, defaultStyle, background, header, footer, images, watermark); - } - - return result.pages; -}; - -LayoutBuilder.prototype.tryLayoutDocument = function (docStructure, fontProvider, styleDictionary, defaultStyle, background, header, footer, images, watermark, pageBreakBeforeFct) { - - this.linearNodeList = []; - docStructure = this.docPreprocessor.preprocessDocument(docStructure); - docStructure = this.docMeasure.measureDocument(docStructure); - - this.writer = new PageElementWriter( - new DocumentContext(this.pageSize, this.pageMargins), this.tracker); - - var _this = this; - this.writer.context().tracker.startTracking('pageAdded', function () { - _this.addBackground(background); - }); - - this.addBackground(background); - this.processNode(docStructure); - this.addHeadersAndFooters(header, footer); - if (watermark != null) { - this.addWatermark(watermark, fontProvider, defaultStyle); - } - - return {pages: this.writer.context().pages, linearNodeList: this.linearNodeList}; -}; - - -LayoutBuilder.prototype.addBackground = function (background) { - var backgroundGetter = isFunction(background) ? background : function () { - return background; - }; - - var pageBackground = backgroundGetter(this.writer.context().page + 1); - - if (pageBackground) { - var pageSize = this.writer.context().getCurrentPage().pageSize; - this.writer.beginUnbreakableBlock(pageSize.width, pageSize.height); - pageBackground = this.docPreprocessor.preprocessDocument(pageBackground); - this.processNode(this.docMeasure.measureDocument(pageBackground)); - this.writer.commitUnbreakableBlock(0, 0); - this.writer.context().hasBackground = true; - } -}; - -LayoutBuilder.prototype.addStaticRepeatable = function (headerOrFooter, sizeFunction) { - this.addDynamicRepeatable(function () { - return JSON.parse(JSON.stringify(headerOrFooter)); // copy to new object - }, sizeFunction); -}; - -LayoutBuilder.prototype.addDynamicRepeatable = function (nodeGetter, sizeFunction) { - var pages = this.writer.context().pages; - - for (var pageIndex = 0, l = pages.length; pageIndex < l; pageIndex++) { - this.writer.context().page = pageIndex; - - var node = nodeGetter(pageIndex + 1, l, this.writer.context().pages[pageIndex].pageSize); - - if (node) { - var sizes = sizeFunction(this.writer.context().getCurrentPage().pageSize, this.pageMargins); - this.writer.beginUnbreakableBlock(sizes.width, sizes.height); - node = this.docPreprocessor.preprocessDocument(node); - this.processNode(this.docMeasure.measureDocument(node)); - this.writer.commitUnbreakableBlock(sizes.x, sizes.y); - } - } -}; - -LayoutBuilder.prototype.addHeadersAndFooters = function (header, footer) { - var headerSizeFct = function (pageSize, pageMargins) { - return { - x: 0, - y: 0, - width: pageSize.width, - height: pageMargins.top - }; - }; - - var footerSizeFct = function (pageSize, pageMargins) { - return { - x: 0, - y: pageSize.height - pageMargins.bottom, - width: pageSize.width, - height: pageMargins.bottom - }; - }; - - if (isFunction(header)) { - this.addDynamicRepeatable(header, headerSizeFct); - } else if (header) { - this.addStaticRepeatable(header, headerSizeFct); - } - - if (isFunction(footer)) { - this.addDynamicRepeatable(footer, footerSizeFct); - } else if (footer) { - this.addStaticRepeatable(footer, footerSizeFct); - } -}; - -LayoutBuilder.prototype.addWatermark = function (watermark, fontProvider, defaultStyle) { - if (isString(watermark)) { - watermark = {'text': watermark}; - } - - if (!watermark.text) { // empty watermark text - return; - } - - watermark.font = watermark.font || defaultStyle.font || 'Roboto'; - watermark.color = watermark.color || 'black'; - watermark.opacity = watermark.opacity || 0.6; - watermark.bold = watermark.bold || false; - watermark.italics = watermark.italics || false; - - var watermarkObject = { - text: watermark.text, - font: fontProvider.provideFont(watermark.font, watermark.bold, watermark.italics), - size: getSize(this.pageSize, watermark, fontProvider), - color: watermark.color, - opacity: watermark.opacity - }; - - var pages = this.writer.context().pages; - for (var i = 0, l = pages.length; i < l; i++) { - pages[i].watermark = watermarkObject; - } - - function getSize(pageSize, watermark, fontProvider) { - var width = pageSize.width; - var height = pageSize.height; - var targetWidth = Math.sqrt(width * width + height * height) * 0.8; /* page diagonal * sample factor */ - var textTools = new TextTools(fontProvider); - var styleContextStack = new StyleContextStack(null, {font: watermark.font, bold: watermark.bold, italics: watermark.italics}); - var size; - - /** - * Binary search the best font size. - * Initial bounds [0, 1000] - * Break when range < 1 - */ - var a = 0; - var b = 1000; - var c = (a + b) / 2; - while (Math.abs(a - b) > 1) { - styleContextStack.push({ - fontSize: c - }); - size = textTools.sizeOfString(watermark.text, styleContextStack); - if (size.width > targetWidth) { - b = c; - c = (a + b) / 2; - } else if (size.width < targetWidth) { - a = c; - c = (a + b) / 2; - } - styleContextStack.pop(); - } - /* - End binary search - */ - return {size: size, fontSize: c}; - } -}; - -function decorateNode(node) { - var x = node.x, y = node.y; - node.positions = []; - - if (isArray(node.canvas)) { - node.canvas.forEach(function (vector) { - var x = vector.x, y = vector.y, x1 = vector.x1, y1 = vector.y1, x2 = vector.x2, y2 = vector.y2; - vector.resetXY = function () { - vector.x = x; - vector.y = y; - vector.x1 = x1; - vector.y1 = y1; - vector.x2 = x2; - vector.y2 = y2; - }; - }); - } - - node.resetXY = function () { - node.x = x; - node.y = y; - if (isArray(node.canvas)) { - node.canvas.forEach(function (vector) { - vector.resetXY(); - }); - } - }; -} - -LayoutBuilder.prototype.processNode = function (node) { - var self = this; - - this.linearNodeList.push(node); - decorateNode(node); - - applyMargins(function () { - var unbreakable = node.unbreakable; - if (unbreakable) { - self.writer.beginUnbreakableBlock(); - } - - var absPosition = node.absolutePosition; - if (absPosition) { - self.writer.context().beginDetachedBlock(); - self.writer.context().moveTo(absPosition.x || 0, absPosition.y || 0); - } - - var relPosition = node.relativePosition; - if (relPosition) { - self.writer.context().beginDetachedBlock(); - self.writer.context().moveTo((relPosition.x || 0) + self.writer.context().x, (relPosition.y || 0) + self.writer.context().y); - } - - if (node.stack) { - self.processVerticalContainer(node); - } else if (node.columns) { - self.processColumns(node); - } else if (node.ul) { - self.processList(false, node); - } else if (node.ol) { - self.processList(true, node); - } else if (node.table) { - self.processTable(node); - } else if (node.text !== undefined) { - self.processLeaf(node); - } else if (node.toc) { - self.processToc(node); - } else if (node.image) { - self.processImage(node); - } else if (node.canvas) { - self.processCanvas(node); - } else if (node.qr) { - self.processQr(node); - } else if (!node._span) { - throw 'Unrecognized document structure: ' + JSON.stringify(node, fontStringify); - } - - if (absPosition || relPosition) { - self.writer.context().endDetachedBlock(); - } - - if (unbreakable) { - self.writer.commitUnbreakableBlock(); - } - }); - - function applyMargins(callback) { - var margin = node._margin; - - if (node.pageBreak === 'before') { - self.writer.moveToNextPage(node.pageOrientation); - } - - if (margin) { - self.writer.context().moveDown(margin[1]); - self.writer.context().addMargin(margin[0], margin[2]); - } - - callback(); - - if (margin) { - self.writer.context().addMargin(-margin[0], -margin[2]); - self.writer.context().moveDown(margin[3]); - } - - if (node.pageBreak === 'after') { - self.writer.moveToNextPage(node.pageOrientation); - } - } -}; - -// vertical container -LayoutBuilder.prototype.processVerticalContainer = function (node) { - var self = this; - node.stack.forEach(function (item) { - self.processNode(item); - addAll(node.positions, item.positions); - - //TODO: paragraph gap - }); -}; - -// columns -LayoutBuilder.prototype.processColumns = function (columnNode) { - var columns = columnNode.columns; - var availableWidth = this.writer.context().availableWidth; - var gaps = gapArray(columnNode._gap); - - if (gaps) { - availableWidth -= (gaps.length - 1) * columnNode._gap; - } - - ColumnCalculator.buildColumnWidths(columns, availableWidth); - var result = this.processRow(columns, columns, gaps); - addAll(columnNode.positions, result.positions); - - - function gapArray(gap) { - if (!gap) { - return null; - } - - var gaps = []; - gaps.push(0); - - for (var i = columns.length - 1; i > 0; i--) { - gaps.push(gap); - } - - return gaps; - } -}; - -LayoutBuilder.prototype.processRow = function (columns, widths, gaps, tableBody, tableRow, height) { - var self = this; - var pageBreaks = [], positions = []; - - this.tracker.auto('pageChanged', storePageBreakData, function () { - widths = widths || columns; - - self.writer.context().beginColumnGroup(); - - for (var i = 0, l = columns.length; i < l; i++) { - var column = columns[i]; - var width = widths[i]._calcWidth; - var leftOffset = colLeftOffset(i); - - if (column.colSpan && column.colSpan > 1) { - for (var j = 1; j < column.colSpan; j++) { - width += widths[++i]._calcWidth + gaps[i]; - } - } - - self.writer.context().beginColumn(width, leftOffset, getEndingCell(column, i)); - if (!column._span) { - self.processNode(column); - addAll(positions, column.positions); - } else if (column._columnEndingContext) { - // row-span ending - self.writer.context().markEnding(column); - } - } - - self.writer.context().completeColumnGroup(height); - }); - - return {pageBreaks: pageBreaks, positions: positions}; - - function storePageBreakData(data) { - var pageDesc; - - for (var i = 0, l = pageBreaks.length; i < l; i++) { - var desc = pageBreaks[i]; - if (desc.prevPage === data.prevPage) { - pageDesc = desc; - break; - } - } - - if (!pageDesc) { - pageDesc = data; - pageBreaks.push(pageDesc); - } - pageDesc.prevY = Math.max(pageDesc.prevY, data.prevY); - pageDesc.y = Math.min(pageDesc.y, data.y); - } - - function colLeftOffset(i) { - if (gaps && gaps.length > i) { - return gaps[i]; - } - return 0; - } - - function getEndingCell(column, columnIndex) { - if (column.rowSpan && column.rowSpan > 1) { - var endingRow = tableRow + column.rowSpan - 1; - if (endingRow >= tableBody.length) { - throw 'Row span for column ' + columnIndex + ' (with indexes starting from 0) exceeded row count'; - } - return tableBody[endingRow][columnIndex]; - } - - return null; - } -}; - -// lists -LayoutBuilder.prototype.processList = function (orderedList, node) { - var self = this, - items = orderedList ? node.ol : node.ul, - gapSize = node._gapSize; - - this.writer.context().addMargin(gapSize.width); - - var nextMarker; - this.tracker.auto('lineAdded', addMarkerToFirstLeaf, function () { - items.forEach(function (item) { - nextMarker = item.listMarker; - self.processNode(item); - addAll(node.positions, item.positions); - }); - }); - - this.writer.context().addMargin(-gapSize.width); - - function addMarkerToFirstLeaf(line) { - // I'm not very happy with the way list processing is implemented - // (both code and algorithm should be rethinked) - if (nextMarker) { - var marker = nextMarker; - nextMarker = null; - - if (marker.canvas) { - var vector = marker.canvas[0]; - - offsetVector(vector, -marker._minWidth, 0); - self.writer.addVector(vector); - } else if (marker._inlines) { - var markerLine = new Line(self.pageSize.width); - markerLine.addInline(marker._inlines[0]); - markerLine.x = -marker._minWidth; - markerLine.y = line.getAscenderHeight() - markerLine.getAscenderHeight(); - self.writer.addLine(markerLine, true); - } - } - } -}; - -// tables -LayoutBuilder.prototype.processTable = function (tableNode) { - var processor = new TableProcessor(tableNode); - - processor.beginTable(this.writer); - - var rowHeights = tableNode.table.heights; - for (var i = 0, l = tableNode.table.body.length; i < l; i++) { - processor.beginRow(i, this.writer); - - var height; - if (isFunction(rowHeights)) { - height = rowHeights(i); - } else if (isArray(rowHeights)) { - height = rowHeights[i]; - } else { - height = rowHeights; - } - - if (height === 'auto') { - height = undefined; - } - - var result = this.processRow(tableNode.table.body[i], tableNode.table.widths, tableNode._offsets.offsets, tableNode.table.body, i, height); - addAll(tableNode.positions, result.positions); - - processor.endRow(i, this.writer, result.pageBreaks); - } - - processor.endTable(this.writer); -}; - -// leafs (texts) -LayoutBuilder.prototype.processLeaf = function (node) { - var line = this.buildNextLine(node); - var currentHeight = (line) ? line.getHeight() : 0; - var maxHeight = node.maxHeight || -1; - - if (node._tocItemRef) { - line._pageNodeRef = node._tocItemRef; - } - - if (node._pageRef) { - line._pageNodeRef = node._pageRef._nodeRef; - } - - while (line && (maxHeight === -1 || currentHeight < maxHeight)) { - var positions = this.writer.addLine(line); - node.positions.push(positions); - line = this.buildNextLine(node); - if (line) { - currentHeight += line.getHeight(); - } - } -}; - -LayoutBuilder.prototype.processToc = function (node) { - if (node.toc.title) { - this.processNode(node.toc.title); - } - this.processNode(node.toc._table); -}; - -LayoutBuilder.prototype.buildNextLine = function (textNode) { - - function cloneInline(inline) { - var newInline = inline.constructor(); - for (var key in inline) { - newInline[key] = inline[key]; - } - return newInline; - } - - if (!textNode._inlines || textNode._inlines.length === 0) { - return null; - } - - var line = new Line(this.writer.context().availableWidth); - var textTools = new TextTools(null); - - while (textNode._inlines && textNode._inlines.length > 0 && line.hasEnoughSpaceForInline(textNode._inlines[0])) { - var inline = textNode._inlines.shift(); - - if (!inline.noWrap && inline.text.length > 1 && inline.width > line.maxWidth) { - var widthPerChar = inline.width / inline.text.length; - var maxChars = Math.floor(line.maxWidth / widthPerChar); - if (maxChars < 1) { - maxChars = 1; - } - if (maxChars < inline.text.length) { - var newInline = cloneInline(inline); - - newInline.text = inline.text.substr(maxChars); - inline.text = inline.text.substr(0, maxChars); - - newInline.width = textTools.widthOfString(newInline.text, newInline.font, newInline.fontSize, newInline.characterSpacing, newInline.fontFeatures); - inline.width = textTools.widthOfString(inline.text, inline.font, inline.fontSize, inline.characterSpacing, inline.fontFeatures); - - textNode._inlines.unshift(newInline); - } - } - - line.addInline(inline); - } - - line.lastLineInParagraph = textNode._inlines.length === 0; - - return line; -}; - -// images -LayoutBuilder.prototype.processImage = function (node) { - var position = this.writer.addImage(node); - node.positions.push(position); -}; - -LayoutBuilder.prototype.processCanvas = function (node) { - var height = node._minHeight; - - if (node.absolutePosition === undefined && this.writer.context().availableHeight < height) { - // TODO: support for canvas larger than a page - // TODO: support for other overflow methods - - this.writer.moveToNextPage(); - } - - this.writer.alignCanvas(node); - - node.canvas.forEach(function (vector) { - var position = this.writer.addVector(vector); - node.positions.push(position); - }, this); - - this.writer.context().moveDown(height); -}; - -LayoutBuilder.prototype.processQr = function (node) { - var position = this.writer.addQr(node); - node.positions.push(position); -}; - -module.exports = LayoutBuilder; - - -/***/ }), -/* 129 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/* WEBPACK VAR INJECTION */(function(Buffer) { - -var isString = __webpack_require__(0).isString; -var isNumber = __webpack_require__(0).isNumber; -var isBoolean = __webpack_require__(0).isBoolean; -var isArray = __webpack_require__(0).isArray; -var isUndefined = __webpack_require__(0).isUndefined; -var fontStringify = __webpack_require__(0).fontStringify; - -function DocPreprocessor() { - -} - -DocPreprocessor.prototype.preprocessDocument = function (docStructure) { - this.tocs = []; - this.nodeReferences = []; - return this.preprocessNode(docStructure); -}; - -DocPreprocessor.prototype.preprocessNode = function (node) { - // expand shortcuts and casting values - if (isArray(node)) { - node = {stack: node}; - } else if (isString(node)) { - node = {text: node}; - } else if (isNumber(node) || isBoolean(node)) { - node = {text: node.toString()}; - } else if (node === null) { - node = {text: ''}; - } else if (Object.keys(node).length === 0) { // empty object - node = {text: ''}; - } - - if (node.columns) { - return this.preprocessColumns(node); - } else if (node.stack) { - return this.preprocessVerticalContainer(node); - } else if (node.ul) { - return this.preprocessList(node); - } else if (node.ol) { - return this.preprocessList(node); - } else if (node.table) { - return this.preprocessTable(node); - } else if (node.text !== undefined) { - return this.preprocessText(node); - } else if (node.toc) { - return this.preprocessToc(node); - } else if (node.image) { - return this.preprocessImage(node); - } else if (node.canvas) { - return this.preprocessCanvas(node); - } else if (node.qr) { - return this.preprocessQr(node); - } else if (node.pageReference || node.textReference) { - return this.preprocessText(node); - } else { - throw 'Unrecognized document structure: ' + JSON.stringify(node, fontStringify); - } -}; - -DocPreprocessor.prototype.preprocessColumns = function (node) { - var columns = node.columns; - - for (var i = 0, l = columns.length; i < l; i++) { - columns[i] = this.preprocessNode(columns[i]); - } - - return node; -}; - -DocPreprocessor.prototype.preprocessVerticalContainer = function (node) { - var items = node.stack; - - for (var i = 0, l = items.length; i < l; i++) { - items[i] = this.preprocessNode(items[i]); - } - - return node; -}; - -DocPreprocessor.prototype.preprocessList = function (node) { - var items = node.ul || node.ol; - - for (var i = 0, l = items.length; i < l; i++) { - items[i] = this.preprocessNode(items[i]); - } - - return node; -}; - -DocPreprocessor.prototype.preprocessTable = function (node) { - var col, row, cols, rows; - - for (col = 0, cols = node.table.body[0].length; col < cols; col++) { - for (row = 0, rows = node.table.body.length; row < rows; row++) { - var rowData = node.table.body[row]; - var data = rowData[col]; - if (data !== undefined) { - if (data === null) { // transform to object - data = ''; - } - if (!data._span) { - rowData[col] = this.preprocessNode(data); - } - } - } - } - - return node; -}; - -DocPreprocessor.prototype.preprocessText = function (node) { - if (node.tocItem) { - if (!isArray(node.tocItem)) { - node.tocItem = [node.tocItem]; - } - - for (var i = 0, l = node.tocItem.length; i < l; i++) { - if (!isString(node.tocItem[i])) { - node.tocItem[i] = '_default_'; - } - - var tocItemId = node.tocItem[i]; - - if (!this.tocs[tocItemId]) { - this.tocs[tocItemId] = {toc: {_items: [], _pseudo: true}}; - } - - this.tocs[tocItemId].toc._items.push(node); - } - } - - if (node.id) { - if (this.nodeReferences[node.id]) { - if (!this.nodeReferences[node.id]._pseudo) { - throw "Node id '" + node.id + "' already exists"; - } - - this.nodeReferences[node.id]._nodeRef = node; - this.nodeReferences[node.id]._pseudo = false; - } else { - this.nodeReferences[node.id] = {_nodeRef: node}; - } - } - - if (node.pageReference) { - if (!this.nodeReferences[node.pageReference]) { - this.nodeReferences[node.pageReference] = {_nodeRef: {}, _pseudo: true}; - } - node.text = '00000'; - node._pageRef = this.nodeReferences[node.pageReference]; - } - - if (node.textReference) { - if (!this.nodeReferences[node.textReference]) { - this.nodeReferences[node.textReference] = {_nodeRef: {}, _pseudo: true}; - } - - node.text = ''; - node._textRef = this.nodeReferences[node.textReference]; - } - - if (node.text && node.text.text) { - node.text = [this.preprocessNode(node.text)]; - } - - return node; -}; - -DocPreprocessor.prototype.preprocessToc = function (node) { - if (!node.toc.id) { - node.toc.id = '_default_'; - } - - node.toc.title = node.toc.title ? this.preprocessNode(node.toc.title) : null; - node.toc._items = []; - - if (this.tocs[node.toc.id]) { - if (!this.tocs[node.toc.id].toc._pseudo) { - throw "TOC '" + node.toc.id + "' already exists"; - } - - node.toc._items = this.tocs[node.toc.id].toc._items; - } - - this.tocs[node.toc.id] = node; - - return node; -}; - -DocPreprocessor.prototype.preprocessImage = function (node) { - if (!isUndefined(node.image.type) && !isUndefined(node.image.data) && (node.image.type === 'Buffer') && isArray(node.image.data)) { - node.image = Buffer.from(node.image.data); - } - return node; -}; - -DocPreprocessor.prototype.preprocessCanvas = function (node) { - return node; -}; - -DocPreprocessor.prototype.preprocessQr = function (node) { - return node; -}; - -module.exports = DocPreprocessor; -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1).Buffer)) - -/***/ }), -/* 130 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*eslint no-unused-vars: ["error", {"args": "none"}]*/ - - - -var TextTools = __webpack_require__(42); -var StyleContextStack = __webpack_require__(80); -var ColumnCalculator = __webpack_require__(44); -var isString = __webpack_require__(0).isString; -var isNumber = __webpack_require__(0).isNumber; -var isObject = __webpack_require__(0).isObject; -var isArray = __webpack_require__(0).isArray; -var fontStringify = __webpack_require__(0).fontStringify; -var pack = __webpack_require__(0).pack; -var qrEncoder = __webpack_require__(134); - -/** - * @private - */ -function DocMeasure(fontProvider, styleDictionary, defaultStyle, imageMeasure, tableLayouts, images) { - this.textTools = new TextTools(fontProvider); - this.styleStack = new StyleContextStack(styleDictionary, defaultStyle); - this.imageMeasure = imageMeasure; - this.tableLayouts = tableLayouts; - this.images = images; - this.autoImageIndex = 1; -} - -/** - * Measures all nodes and sets min/max-width properties required for the second - * layout-pass. - * @param {Object} docStructure document-definition-object - * @return {Object} document-measurement-object - */ -DocMeasure.prototype.measureDocument = function (docStructure) { - return this.measureNode(docStructure); -}; - -DocMeasure.prototype.measureNode = function (node) { - - var self = this; - - return this.styleStack.auto(node, function () { - // TODO: refactor + rethink whether this is the proper way to handle margins - node._margin = getNodeMargin(node); - - if (node.columns) { - return extendMargins(self.measureColumns(node)); - } else if (node.stack) { - return extendMargins(self.measureVerticalContainer(node)); - } else if (node.ul) { - return extendMargins(self.measureUnorderedList(node)); - } else if (node.ol) { - return extendMargins(self.measureOrderedList(node)); - } else if (node.table) { - return extendMargins(self.measureTable(node)); - } else if (node.text !== undefined) { - return extendMargins(self.measureLeaf(node)); - } else if (node.toc) { - return extendMargins(self.measureToc(node)); - } else if (node.image) { - return extendMargins(self.measureImage(node)); - } else if (node.canvas) { - return extendMargins(self.measureCanvas(node)); - } else if (node.qr) { - return extendMargins(self.measureQr(node)); - } else { - throw 'Unrecognized document structure: ' + JSON.stringify(node, fontStringify); - } - }); - - function extendMargins(node) { - var margin = node._margin; - - if (margin) { - node._minWidth += margin[0] + margin[2]; - node._maxWidth += margin[0] + margin[2]; - } - - return node; - } - - function getNodeMargin() { - - function processSingleMargins(node, currentMargin) { - if (node.marginLeft || node.marginTop || node.marginRight || node.marginBottom) { - return [ - node.marginLeft || currentMargin[0] || 0, - node.marginTop || currentMargin[1] || 0, - node.marginRight || currentMargin[2] || 0, - node.marginBottom || currentMargin[3] || 0 - ]; - } - return currentMargin; - } - - function flattenStyleArray(styleArray) { - var flattenedStyles = {}; - for (var i = styleArray.length - 1; i >= 0; i--) { - var styleName = styleArray[i]; - var style = self.styleStack.styleDictionary[styleName]; - for (var key in style) { - if (style.hasOwnProperty(key)) { - flattenedStyles[key] = style[key]; - } - } - } - return flattenedStyles; - } - - function convertMargin(margin) { - if (isNumber(margin)) { - margin = [margin, margin, margin, margin]; - } else if (isArray(margin)) { - if (margin.length === 2) { - margin = [margin[0], margin[1], margin[0], margin[1]]; - } - } - return margin; - } - - var margin = [undefined, undefined, undefined, undefined]; - - if (node.style) { - var styleArray = isArray(node.style) ? node.style : [node.style]; - var flattenedStyleArray = flattenStyleArray(styleArray); - - if (flattenedStyleArray) { - margin = processSingleMargins(flattenedStyleArray, margin); - } - - if (flattenedStyleArray.margin) { - margin = convertMargin(flattenedStyleArray.margin); - } - } - - margin = processSingleMargins(node, margin); - - if (node.margin) { - margin = convertMargin(node.margin); - } - - if (margin[0] === undefined && margin[1] === undefined && margin[2] === undefined && margin[3] === undefined) { - return null; - } else { - return margin; - } - } -}; - -DocMeasure.prototype.convertIfBase64Image = function (node) { - if (/^data:image\/(jpeg|jpg|png);base64,/.test(node.image)) { - var label = '$$pdfmake$$' + this.autoImageIndex++; - this.images[label] = node.image; - node.image = label; - } -}; - -DocMeasure.prototype.measureImage = function (node) { - if (this.images) { - this.convertIfBase64Image(node); - } - - var imageSize = this.imageMeasure.measureImage(node.image); - - if (node.fit) { - var factor = (imageSize.width / imageSize.height > node.fit[0] / node.fit[1]) ? node.fit[0] / imageSize.width : node.fit[1] / imageSize.height; - node._width = node._minWidth = node._maxWidth = imageSize.width * factor; - node._height = imageSize.height * factor; - } else { - node._width = node._minWidth = node._maxWidth = node.width || imageSize.width; - node._height = node.height || (imageSize.height * node._width / imageSize.width); - - if (isNumber(node.maxWidth) && node.maxWidth < node._width) { - node._width = node._minWidth = node._maxWidth = node.maxWidth; - node._height = node._width * imageSize.height / imageSize.width; - } - - if (isNumber(node.maxHeight) && node.maxHeight < node._height) { - node._height = node.maxHeight; - node._width = node._minWidth = node._maxWidth = node._height * imageSize.width / imageSize.height; - } - - if (isNumber(node.minWidth) && node.minWidth > node._width) { - node._width = node._minWidth = node._maxWidth = node.minWidth; - node._height = node._width * imageSize.height / imageSize.width; - } - - if (isNumber(node.minHeight) && node.minHeight > node._height) { - node._height = node.minHeight; - node._width = node._minWidth = node._maxWidth = node._height * imageSize.width / imageSize.height; - } - } - - node._alignment = this.styleStack.getProperty('alignment'); - return node; -}; - -DocMeasure.prototype.measureLeaf = function (node) { - - if (node._textRef && node._textRef._nodeRef.text) { - node.text = node._textRef._nodeRef.text; - } - - // Make sure style properties of the node itself are considered when building inlines. - // We could also just pass [node] to buildInlines, but that fails for bullet points. - var styleStack = this.styleStack.clone(); - styleStack.push(node); - - var data = this.textTools.buildInlines(node.text, styleStack); - - node._inlines = data.items; - node._minWidth = data.minWidth; - node._maxWidth = data.maxWidth; - - return node; -}; - -DocMeasure.prototype.measureToc = function (node) { - if (node.toc.title) { - node.toc.title = this.measureNode(node.toc.title); - } - - var body = []; - var textStyle = node.toc.textStyle || {}; - var numberStyle = node.toc.numberStyle || textStyle; - var textMargin = node.toc.textMargin || [0, 0, 0, 0]; - for (var i = 0, l = node.toc._items.length; i < l; i++) { - var item = node.toc._items[i]; - var lineStyle = node.toc._items[i].tocStyle || textStyle; - var lineMargin = node.toc._items[i].tocMargin || textMargin; - body.push([ - {text: item.text, alignment: 'left', style: lineStyle, margin: lineMargin}, - {text: '00000', alignment: 'right', _tocItemRef: item, style: numberStyle, margin: [0, lineMargin[1], 0, lineMargin[3]]} - ]); - } - - - node.toc._table = { - table: { - dontBreakRows: true, - widths: ['*', 'auto'], - body: body - }, - layout: 'noBorders' - }; - - node.toc._table = this.measureNode(node.toc._table); - - return node; -}; - -DocMeasure.prototype.measureVerticalContainer = function (node) { - var items = node.stack; - - node._minWidth = 0; - node._maxWidth = 0; - - for (var i = 0, l = items.length; i < l; i++) { - items[i] = this.measureNode(items[i]); - - node._minWidth = Math.max(node._minWidth, items[i]._minWidth); - node._maxWidth = Math.max(node._maxWidth, items[i]._maxWidth); - } - - return node; -}; - -DocMeasure.prototype.gapSizeForList = function () { - return this.textTools.sizeOfString('9. ', this.styleStack); -}; - -DocMeasure.prototype.buildUnorderedMarker = function (styleStack, gapSize, type) { - function buildDisc(gapSize, color) { - // TODO: ascender-based calculations - var radius = gapSize.fontSize / 6; - return { - canvas: [{ - x: radius, - y: (gapSize.height / gapSize.lineHeight) + gapSize.descender - gapSize.fontSize / 3, - r1: radius, - r2: radius, - type: 'ellipse', - color: color - }] - }; - } - - function buildSquare(gapSize, color) { - // TODO: ascender-based calculations - var size = gapSize.fontSize / 3; - return { - canvas: [{ - x: 0, - y: (gapSize.height / gapSize.lineHeight) + gapSize.descender - (gapSize.fontSize / 3) - (size / 2), - h: size, - w: size, - type: 'rect', - color: color - }] - }; - } - - function buildCircle(gapSize, color) { - // TODO: ascender-based calculations - var radius = gapSize.fontSize / 6; - return { - canvas: [{ - x: radius, - y: (gapSize.height / gapSize.lineHeight) + gapSize.descender - gapSize.fontSize / 3, - r1: radius, - r2: radius, - type: 'ellipse', - lineColor: color - }] - }; - } - - var marker; - var color = styleStack.getProperty('markerColor') || styleStack.getProperty('color') || 'black'; - - switch (type) { - case 'circle': - marker = buildCircle(gapSize, color); - break; - - case 'square': - marker = buildSquare(gapSize, color); - break; - - case 'none': - marker = {}; - break; - - case 'disc': - default: - marker = buildDisc(gapSize, color); - break; - } - - marker._minWidth = marker._maxWidth = gapSize.width; - marker._minHeight = marker._maxHeight = gapSize.height; - - return marker; -}; - -DocMeasure.prototype.buildOrderedMarker = function (counter, styleStack, type, separator) { - function prepareAlpha(counter) { - function toAlpha(num) { - return (num >= 26 ? toAlpha((num / 26 >> 0) - 1) : '') + 'abcdefghijklmnopqrstuvwxyz'[num % 26 >> 0]; - } - - if (counter < 1) { - return counter.toString(); - } - - return toAlpha(counter - 1); - } - - function prepareRoman(counter) { - if (counter < 1 || counter > 4999) { - return counter.toString(); - } - var num = counter; - var lookup = {M: 1000, CM: 900, D: 500, CD: 400, C: 100, XC: 90, L: 50, XL: 40, X: 10, IX: 9, V: 5, IV: 4, I: 1}, roman = '', i; - for (i in lookup) { - while (num >= lookup[i]) { - roman += i; - num -= lookup[i]; - } - } - return roman; - } - - function prepareDecimal(counter) { - return counter.toString(); - } - - var counterText; - switch (type) { - case 'none': - counterText = null; - break; - - case 'upper-alpha': - counterText = prepareAlpha(counter).toUpperCase(); - break; - - case 'lower-alpha': - counterText = prepareAlpha(counter); - break; - - case 'upper-roman': - counterText = prepareRoman(counter); - break; - - case 'lower-roman': - counterText = prepareRoman(counter).toLowerCase(); - break; - - case 'decimal': - default: - counterText = prepareDecimal(counter); - break; - } - - if (counterText === null) { - return {}; - } - - if (separator) { - if (isArray(separator)) { - if (separator[0]) { - counterText = separator[0] + counterText; - } - - if (separator[1]) { - counterText += separator[1]; - } - counterText += ' '; - } else { - counterText += separator + ' '; - } - } - - var textArray = {text: counterText}; - var markerColor = styleStack.getProperty('markerColor'); - if (markerColor) { - textArray.color = markerColor; - } - - return {_inlines: this.textTools.buildInlines(textArray, styleStack).items}; -}; - -DocMeasure.prototype.measureUnorderedList = function (node) { - var style = this.styleStack.clone(); - var items = node.ul; - node.type = node.type || 'disc'; - node._gapSize = this.gapSizeForList(); - node._minWidth = 0; - node._maxWidth = 0; - - for (var i = 0, l = items.length; i < l; i++) { - var item = items[i] = this.measureNode(items[i]); - - if (!item.ol && !item.ul) { - item.listMarker = this.buildUnorderedMarker(style, node._gapSize, item.listType || node.type); - } - - node._minWidth = Math.max(node._minWidth, items[i]._minWidth + node._gapSize.width); - node._maxWidth = Math.max(node._maxWidth, items[i]._maxWidth + node._gapSize.width); - } - - return node; -}; - -DocMeasure.prototype.measureOrderedList = function (node) { - var style = this.styleStack.clone(); - var items = node.ol; - node.type = node.type || 'decimal'; - node.separator = node.separator || '.'; - node.reversed = node.reversed || false; - if (!node.start) { - node.start = node.reversed ? items.length : 1; - } - node._gapSize = this.gapSizeForList(); - node._minWidth = 0; - node._maxWidth = 0; - - var counter = node.start; - for (var i = 0, l = items.length; i < l; i++) { - var item = items[i] = this.measureNode(items[i]); - - if (!item.ol && !item.ul) { - item.listMarker = this.buildOrderedMarker(item.counter || counter, style, item.listType || node.type, node.separator); - if (item.listMarker._inlines) { - node._gapSize.width = Math.max(node._gapSize.width, item.listMarker._inlines[0].width); - } - } // TODO: else - nested lists numbering - - node._minWidth = Math.max(node._minWidth, items[i]._minWidth); - node._maxWidth = Math.max(node._maxWidth, items[i]._maxWidth); - - if (node.reversed) { - counter--; - } else { - counter++; - } - } - - node._minWidth += node._gapSize.width; - node._maxWidth += node._gapSize.width; - - for (var i = 0, l = items.length; i < l; i++) { - var item = items[i]; - if (!item.ol && !item.ul) { - item.listMarker._minWidth = item.listMarker._maxWidth = node._gapSize.width; - } - } - - return node; -}; - -DocMeasure.prototype.measureColumns = function (node) { - var columns = node.columns; - node._gap = this.styleStack.getProperty('columnGap') || 0; - - for (var i = 0, l = columns.length; i < l; i++) { - columns[i] = this.measureNode(columns[i]); - } - - var measures = ColumnCalculator.measureMinMax(columns); - - var numGaps = (columns.length > 0) ? (columns.length - 1) : 0; - node._minWidth = measures.min + node._gap * numGaps; - node._maxWidth = measures.max + node._gap * numGaps; - - return node; -}; - -DocMeasure.prototype.measureTable = function (node) { - extendTableWidths(node); - node._layout = getLayout(this.tableLayouts); - node._offsets = getOffsets(node._layout); - - var colSpans = []; - var col, row, cols, rows; - - for (col = 0, cols = node.table.body[0].length; col < cols; col++) { - var c = node.table.widths[col]; - c._minWidth = 0; - c._maxWidth = 0; - - for (row = 0, rows = node.table.body.length; row < rows; row++) { - var rowData = node.table.body[row]; - var data = rowData[col]; - if (data === undefined) { - console.error('Malformed table row ', rowData, 'in node ', node); - throw 'Malformed table row, a cell is undefined.'; - } - if (data === null) { // transform to object - data = ''; - } - - if (!data._span) { - data = rowData[col] = this.styleStack.auto(data, measureCb(this, data)); - - if (data.colSpan && data.colSpan > 1) { - markSpans(rowData, col, data.colSpan); - colSpans.push({col: col, span: data.colSpan, minWidth: data._minWidth, maxWidth: data._maxWidth}); - } else { - c._minWidth = Math.max(c._minWidth, data._minWidth); - c._maxWidth = Math.max(c._maxWidth, data._maxWidth); - } - } - - if (data.rowSpan && data.rowSpan > 1) { - markVSpans(node.table, row, col, data.rowSpan); - } - } - } - - extendWidthsForColSpans(); - - var measures = ColumnCalculator.measureMinMax(node.table.widths); - - node._minWidth = measures.min + node._offsets.total; - node._maxWidth = measures.max + node._offsets.total; - - return node; - - function measureCb(_this, data) { - return function () { - if (isObject(data)) { - data.fillColor = _this.styleStack.getProperty('fillColor'); - } - return _this.measureNode(data); - }; - } - - function getLayout(tableLayouts) { - var layout = node.layout; - - if (isString(layout)) { - layout = tableLayouts[layout]; - } - - var defaultLayout = { - hLineWidth: function (i, node) { - return 1; - }, - vLineWidth: function (i, node) { - return 1; - }, - hLineColor: function (i, node) { - return 'black'; - }, - vLineColor: function (i, node) { - return 'black'; - }, - paddingLeft: function (i, node) { - return 4; - }, - paddingRight: function (i, node) { - return 4; - }, - paddingTop: function (i, node) { - return 2; - }, - paddingBottom: function (i, node) { - return 2; - }, - fillColor: function (i, node) { - return null; - }, - defaultBorder: true - }; - - return pack(defaultLayout, layout); - } - - function getOffsets(layout) { - var offsets = []; - var totalOffset = 0; - var prevRightPadding = 0; - - for (var i = 0, l = node.table.widths.length; i < l; i++) { - var lOffset = prevRightPadding + layout.vLineWidth(i, node) + layout.paddingLeft(i, node); - offsets.push(lOffset); - totalOffset += lOffset; - prevRightPadding = layout.paddingRight(i, node); - } - - totalOffset += prevRightPadding + layout.vLineWidth(node.table.widths.length, node); - - return { - total: totalOffset, - offsets: offsets - }; - } - - function extendWidthsForColSpans() { - var q, j; - - for (var i = 0, l = colSpans.length; i < l; i++) { - var span = colSpans[i]; - - var currentMinMax = getMinMax(span.col, span.span, node._offsets); - var minDifference = span.minWidth - currentMinMax.minWidth; - var maxDifference = span.maxWidth - currentMinMax.maxWidth; - - if (minDifference > 0) { - q = minDifference / span.span; - - for (j = 0; j < span.span; j++) { - node.table.widths[span.col + j]._minWidth += q; - } - } - - if (maxDifference > 0) { - q = maxDifference / span.span; - - for (j = 0; j < span.span; j++) { - node.table.widths[span.col + j]._maxWidth += q; - } - } - } - } - - function getMinMax(col, span, offsets) { - var result = {minWidth: 0, maxWidth: 0}; - - for (var i = 0; i < span; i++) { - result.minWidth += node.table.widths[col + i]._minWidth + (i ? offsets.offsets[col + i] : 0); - result.maxWidth += node.table.widths[col + i]._maxWidth + (i ? offsets.offsets[col + i] : 0); - } - - return result; - } - - function markSpans(rowData, col, span) { - for (var i = 1; i < span; i++) { - rowData[col + i] = { - _span: true, - _minWidth: 0, - _maxWidth: 0, - rowSpan: rowData[col].rowSpan - }; - } - } - - function markVSpans(table, row, col, span) { - for (var i = 1; i < span; i++) { - table.body[row + i][col] = { - _span: true, - _minWidth: 0, - _maxWidth: 0, - fillColor: table.body[row][col].fillColor - }; - } - } - - function extendTableWidths(node) { - if (!node.table.widths) { - node.table.widths = 'auto'; - } - - if (isString(node.table.widths)) { - node.table.widths = [node.table.widths]; - - while (node.table.widths.length < node.table.body[0].length) { - node.table.widths.push(node.table.widths[node.table.widths.length - 1]); - } - } - - for (var i = 0, l = node.table.widths.length; i < l; i++) { - var w = node.table.widths[i]; - if (isNumber(w) || isString(w)) { - node.table.widths[i] = {width: w}; - } - } - } -}; - -DocMeasure.prototype.measureCanvas = function (node) { - var w = 0, h = 0; - - for (var i = 0, l = node.canvas.length; i < l; i++) { - var vector = node.canvas[i]; - - switch (vector.type) { - case 'ellipse': - w = Math.max(w, vector.x + vector.r1); - h = Math.max(h, vector.y + vector.r2); - break; - case 'rect': - w = Math.max(w, vector.x + vector.w); - h = Math.max(h, vector.y + vector.h); - break; - case 'line': - w = Math.max(w, vector.x1, vector.x2); - h = Math.max(h, vector.y1, vector.y2); - break; - case 'polyline': - for (var i2 = 0, l2 = vector.points.length; i2 < l2; i2++) { - w = Math.max(w, vector.points[i2].x); - h = Math.max(h, vector.points[i2].y); - } - break; - } - } - - node._minWidth = node._maxWidth = w; - node._minHeight = node._maxHeight = h; - node._alignment = this.styleStack.getProperty('alignment'); - - return node; -}; - -DocMeasure.prototype.measureQr = function (node) { - node = qrEncoder.measure(node); - node._alignment = this.styleStack.getProperty('alignment'); - return node; -}; - -module.exports = DocMeasure; - - -/***/ }), -/* 131 */ -/***/ (function(module, exports, __webpack_require__) { - -var lookup = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; - -;(function (exports) { - 'use strict'; - - var Arr = (typeof Uint8Array !== 'undefined') - ? Uint8Array - : Array - - var PLUS = '+'.charCodeAt(0) - var SLASH = '/'.charCodeAt(0) - var NUMBER = '0'.charCodeAt(0) - var LOWER = 'a'.charCodeAt(0) - var UPPER = 'A'.charCodeAt(0) - var PLUS_URL_SAFE = '-'.charCodeAt(0) - var SLASH_URL_SAFE = '_'.charCodeAt(0) - - function decode (elt) { - var code = elt.charCodeAt(0) - if (code === PLUS || - code === PLUS_URL_SAFE) - return 62 // '+' - if (code === SLASH || - code === SLASH_URL_SAFE) - return 63 // '/' - if (code < NUMBER) - return -1 //no match - if (code < NUMBER + 10) - return code - NUMBER + 26 + 26 - if (code < UPPER + 26) - return code - UPPER - if (code < LOWER + 26) - return code - LOWER + 26 - } - - function b64ToByteArray (b64) { - var i, j, l, tmp, placeHolders, arr - - if (b64.length % 4 > 0) { - throw new Error('Invalid string. Length must be a multiple of 4') - } - - // the number of equal signs (place holders) - // if there are two placeholders, than the two characters before it - // represent one byte - // if there is only one, then the three characters before it represent 2 bytes - // this is just a cheap hack to not do indexOf twice - var len = b64.length - placeHolders = '=' === b64.charAt(len - 2) ? 2 : '=' === b64.charAt(len - 1) ? 1 : 0 - - // base64 is 4/3 + up to two characters of the original data - arr = new Arr(b64.length * 3 / 4 - placeHolders) - - // if there are placeholders, only get up to the last complete 4 chars - l = placeHolders > 0 ? b64.length - 4 : b64.length - - var L = 0 - - function push (v) { - arr[L++] = v - } - - for (i = 0, j = 0; i < l; i += 4, j += 3) { - tmp = (decode(b64.charAt(i)) << 18) | (decode(b64.charAt(i + 1)) << 12) | (decode(b64.charAt(i + 2)) << 6) | decode(b64.charAt(i + 3)) - push((tmp & 0xFF0000) >> 16) - push((tmp & 0xFF00) >> 8) - push(tmp & 0xFF) - } - - if (placeHolders === 2) { - tmp = (decode(b64.charAt(i)) << 2) | (decode(b64.charAt(i + 1)) >> 4) - push(tmp & 0xFF) - } else if (placeHolders === 1) { - tmp = (decode(b64.charAt(i)) << 10) | (decode(b64.charAt(i + 1)) << 4) | (decode(b64.charAt(i + 2)) >> 2) - push((tmp >> 8) & 0xFF) - push(tmp & 0xFF) - } - - return arr - } - - function uint8ToBase64 (uint8) { - var i, - extraBytes = uint8.length % 3, // if we have 1 byte left, pad 2 bytes - output = "", - temp, length - - function encode (num) { - return lookup.charAt(num) - } - - function tripletToBase64 (num) { - return encode(num >> 18 & 0x3F) + encode(num >> 12 & 0x3F) + encode(num >> 6 & 0x3F) + encode(num & 0x3F) - } - - // go through the array every three bytes, we'll deal with trailing stuff later - for (i = 0, length = uint8.length - extraBytes; i < length; i += 3) { - temp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2]) - output += tripletToBase64(temp) - } - - // pad the end with zeros, but make sure to not forget the extra bytes - switch (extraBytes) { - case 1: - temp = uint8[uint8.length - 1] - output += encode(temp >> 2) - output += encode((temp << 4) & 0x3F) - output += '==' - break - case 2: - temp = (uint8[uint8.length - 2] << 8) + (uint8[uint8.length - 1]) - output += encode(temp >> 10) - output += encode((temp >> 4) & 0x3F) - output += encode((temp << 2) & 0x3F) - output += '=' - break - } - - return output - } - - exports.toByteArray = b64ToByteArray - exports.fromByteArray = uint8ToBase64 -}( false ? (this.base64js = {}) : exports)) - - -/***/ }), -/* 132 */ -/***/ (function(module, exports) { - -// Generated by CoffeeScript 1.7.1 -(function() { - var AI, AL, B2, BA, BB, BK, CB, CJ, CL, CM, CP, CR, EX, GL, H2, H3, HL, HY, ID, IN, IS, JL, JT, JV, LF, NL, NS, NU, OP, PO, PR, QU, RI, SA, SG, SP, SY, WJ, XX, ZW; - - exports.OP = OP = 0; - - exports.CL = CL = 1; - - exports.CP = CP = 2; - - exports.QU = QU = 3; - - exports.GL = GL = 4; - - exports.NS = NS = 5; - - exports.EX = EX = 6; - - exports.SY = SY = 7; - - exports.IS = IS = 8; - - exports.PR = PR = 9; - - exports.PO = PO = 10; - - exports.NU = NU = 11; - - exports.AL = AL = 12; - - exports.HL = HL = 13; - - exports.ID = ID = 14; - - exports.IN = IN = 15; - - exports.HY = HY = 16; - - exports.BA = BA = 17; - - exports.BB = BB = 18; - - exports.B2 = B2 = 19; - - exports.ZW = ZW = 20; - - exports.CM = CM = 21; - - exports.WJ = WJ = 22; - - exports.H2 = H2 = 23; - - exports.H3 = H3 = 24; - - exports.JL = JL = 25; - - exports.JV = JV = 26; - - exports.JT = JT = 27; - - exports.RI = RI = 28; - - exports.AI = AI = 29; - - exports.BK = BK = 30; - - exports.CB = CB = 31; - - exports.CJ = CJ = 32; - - exports.CR = CR = 33; - - exports.LF = LF = 34; - - exports.NL = NL = 35; - - exports.SA = SA = 36; - - exports.SG = SG = 37; - - exports.SP = SP = 38; - - exports.XX = XX = 39; - -}).call(this); - - -/***/ }), -/* 133 */ -/***/ (function(module, exports) { - -// Generated by CoffeeScript 1.7.1 -(function() { - var CI_BRK, CP_BRK, DI_BRK, IN_BRK, PR_BRK; - - exports.DI_BRK = DI_BRK = 0; - - exports.IN_BRK = IN_BRK = 1; - - exports.CI_BRK = CI_BRK = 2; - - exports.CP_BRK = CP_BRK = 3; - - exports.PR_BRK = PR_BRK = 4; - - exports.pairTable = [[PR_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK, CP_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK], [DI_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, PR_BRK, CI_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK], [DI_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, PR_BRK, CI_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK], [PR_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, CI_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK], [IN_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, CI_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK], [DI_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, PR_BRK, CI_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK], [DI_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, PR_BRK, CI_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK], [DI_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, DI_BRK, DI_BRK, IN_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, PR_BRK, CI_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK], [DI_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, PR_BRK, CI_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK], [IN_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, DI_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, PR_BRK, CI_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, DI_BRK], [IN_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, PR_BRK, CI_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK], [IN_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, DI_BRK, IN_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, PR_BRK, CI_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK], [IN_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, IN_BRK, DI_BRK, IN_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, PR_BRK, CI_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK], [IN_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, IN_BRK, DI_BRK, IN_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, PR_BRK, CI_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK], [DI_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, DI_BRK, IN_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, PR_BRK, CI_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK], [DI_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, PR_BRK, CI_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK], [DI_BRK, PR_BRK, PR_BRK, IN_BRK, DI_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, DI_BRK, DI_BRK, IN_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, PR_BRK, CI_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK], [DI_BRK, PR_BRK, PR_BRK, IN_BRK, DI_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, PR_BRK, CI_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK], [IN_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, CI_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK], [DI_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, DI_BRK, PR_BRK, PR_BRK, CI_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK], [DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK], [IN_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, IN_BRK, DI_BRK, IN_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, PR_BRK, CI_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK], [IN_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, CI_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK], [DI_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, DI_BRK, IN_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, PR_BRK, CI_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, DI_BRK], [DI_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, DI_BRK, IN_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, PR_BRK, CI_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, IN_BRK, DI_BRK], [DI_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, DI_BRK, IN_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, PR_BRK, CI_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK], [DI_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, DI_BRK, IN_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, PR_BRK, CI_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, DI_BRK], [DI_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, DI_BRK, IN_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, PR_BRK, CI_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, IN_BRK, DI_BRK], [DI_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, PR_BRK, CI_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, IN_BRK]]; - -}).call(this); - - -/***/ }), -/* 134 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*eslint no-unused-vars: ["error", {"args": "none"}]*/ -/*eslint no-redeclare: "off"*/ - - -/* qr.js -- QR code generator in Javascript (revision 2011-01-19) - * Written by Kang Seonghoon . - * - * This source code is in the public domain; if your jurisdiction does not - * recognize the public domain the terms of Creative Commons CC0 license - * apply. In the other words, you can always do what you want. - */ - - -// per-version information (cf. JIS X 0510:2004 pp. 30--36, 71) -// -// [0]: the degree of generator polynomial by ECC levels -// [1]: # of code blocks by ECC levels -// [2]: left-top positions of alignment patterns -// -// the number in this table (in particular, [0]) does not exactly match with -// the numbers in the specficiation. see augumenteccs below for the reason. -var VERSIONS = [ - null, - [[10, 7, 17, 13], [1, 1, 1, 1], []], - [[16, 10, 28, 22], [1, 1, 1, 1], [4, 16]], - [[26, 15, 22, 18], [1, 1, 2, 2], [4, 20]], - [[18, 20, 16, 26], [2, 1, 4, 2], [4, 24]], - [[24, 26, 22, 18], [2, 1, 4, 4], [4, 28]], - [[16, 18, 28, 24], [4, 2, 4, 4], [4, 32]], - [[18, 20, 26, 18], [4, 2, 5, 6], [4, 20, 36]], - [[22, 24, 26, 22], [4, 2, 6, 6], [4, 22, 40]], - [[22, 30, 24, 20], [5, 2, 8, 8], [4, 24, 44]], - [[26, 18, 28, 24], [5, 4, 8, 8], [4, 26, 48]], - [[30, 20, 24, 28], [5, 4, 11, 8], [4, 28, 52]], - [[22, 24, 28, 26], [8, 4, 11, 10], [4, 30, 56]], - [[22, 26, 22, 24], [9, 4, 16, 12], [4, 32, 60]], - [[24, 30, 24, 20], [9, 4, 16, 16], [4, 24, 44, 64]], - [[24, 22, 24, 30], [10, 6, 18, 12], [4, 24, 46, 68]], - [[28, 24, 30, 24], [10, 6, 16, 17], [4, 24, 48, 72]], - [[28, 28, 28, 28], [11, 6, 19, 16], [4, 28, 52, 76]], - [[26, 30, 28, 28], [13, 6, 21, 18], [4, 28, 54, 80]], - [[26, 28, 26, 26], [14, 7, 25, 21], [4, 28, 56, 84]], - [[26, 28, 28, 30], [16, 8, 25, 20], [4, 32, 60, 88]], - [[26, 28, 30, 28], [17, 8, 25, 23], [4, 26, 48, 70, 92]], - [[28, 28, 24, 30], [17, 9, 34, 23], [4, 24, 48, 72, 96]], - [[28, 30, 30, 30], [18, 9, 30, 25], [4, 28, 52, 76, 100]], - [[28, 30, 30, 30], [20, 10, 32, 27], [4, 26, 52, 78, 104]], - [[28, 26, 30, 30], [21, 12, 35, 29], [4, 30, 56, 82, 108]], - [[28, 28, 30, 28], [23, 12, 37, 34], [4, 28, 56, 84, 112]], - [[28, 30, 30, 30], [25, 12, 40, 34], [4, 32, 60, 88, 116]], - [[28, 30, 30, 30], [26, 13, 42, 35], [4, 24, 48, 72, 96, 120]], - [[28, 30, 30, 30], [28, 14, 45, 38], [4, 28, 52, 76, 100, 124]], - [[28, 30, 30, 30], [29, 15, 48, 40], [4, 24, 50, 76, 102, 128]], - [[28, 30, 30, 30], [31, 16, 51, 43], [4, 28, 54, 80, 106, 132]], - [[28, 30, 30, 30], [33, 17, 54, 45], [4, 32, 58, 84, 110, 136]], - [[28, 30, 30, 30], [35, 18, 57, 48], [4, 28, 56, 84, 112, 140]], - [[28, 30, 30, 30], [37, 19, 60, 51], [4, 32, 60, 88, 116, 144]], - [[28, 30, 30, 30], [38, 19, 63, 53], [4, 28, 52, 76, 100, 124, 148]], - [[28, 30, 30, 30], [40, 20, 66, 56], [4, 22, 48, 74, 100, 126, 152]], - [[28, 30, 30, 30], [43, 21, 70, 59], [4, 26, 52, 78, 104, 130, 156]], - [[28, 30, 30, 30], [45, 22, 74, 62], [4, 30, 56, 82, 108, 134, 160]], - [[28, 30, 30, 30], [47, 24, 77, 65], [4, 24, 52, 80, 108, 136, 164]], - [[28, 30, 30, 30], [49, 25, 81, 68], [4, 28, 56, 84, 112, 140, 168]]]; - -// mode constants (cf. Table 2 in JIS X 0510:2004 p. 16) -var MODE_TERMINATOR = 0; -var MODE_NUMERIC = 1, MODE_ALPHANUMERIC = 2, MODE_OCTET = 4, MODE_KANJI = 8; - -// validation regexps -var NUMERIC_REGEXP = /^\d*$/; -var ALPHANUMERIC_REGEXP = /^[A-Za-z0-9 $%*+\-./:]*$/; -var ALPHANUMERIC_OUT_REGEXP = /^[A-Z0-9 $%*+\-./:]*$/; - -// ECC levels (cf. Table 22 in JIS X 0510:2004 p. 45) -var ECCLEVEL_L = 1, ECCLEVEL_M = 0, ECCLEVEL_Q = 3, ECCLEVEL_H = 2; - -// GF(2^8)-to-integer mapping with a reducing polynomial x^8+x^4+x^3+x^2+1 -// invariant: GF256_MAP[GF256_INVMAP[i]] == i for all i in [1,256) -var GF256_MAP = [], GF256_INVMAP = [-1]; -for (var i = 0, v = 1; i < 255; ++i) { - GF256_MAP.push(v); - GF256_INVMAP[v] = i; - v = (v * 2) ^ (v >= 128 ? 0x11d : 0); -} - -// generator polynomials up to degree 30 -// (should match with polynomials in JIS X 0510:2004 Appendix A) -// -// generator polynomial of degree K is product of (x-\alpha^0), (x-\alpha^1), -// ..., (x-\alpha^(K-1)). by convention, we omit the K-th coefficient (always 1) -// from the result; also other coefficients are written in terms of the exponent -// to \alpha to avoid the redundant calculation. (see also calculateecc below.) -var GF256_GENPOLY = [[]]; -for (var i = 0; i < 30; ++i) { - var prevpoly = GF256_GENPOLY[i], poly = []; - for (var j = 0; j <= i; ++j) { - var a = (j < i ? GF256_MAP[prevpoly[j]] : 0); - var b = GF256_MAP[(i + (prevpoly[j - 1] || 0)) % 255]; - poly.push(GF256_INVMAP[a ^ b]); - } - GF256_GENPOLY.push(poly); -} - -// alphanumeric character mapping (cf. Table 5 in JIS X 0510:2004 p. 19) -var ALPHANUMERIC_MAP = {}; -for (var i = 0; i < 45; ++i) { - ALPHANUMERIC_MAP['0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:'.charAt(i)] = i; -} - -// mask functions in terms of row # and column # -// (cf. Table 20 in JIS X 0510:2004 p. 42) -/*jshint unused: false */ -var MASKFUNCS = [ - function (i, j) { - return (i + j) % 2 === 0; - }, - function (i, j) { - return i % 2 === 0; - }, - function (i, j) { - return j % 3 === 0; - }, - function (i, j) { - return (i + j) % 3 === 0; - }, - function (i, j) { - return (((i / 2) | 0) + ((j / 3) | 0)) % 2 === 0; - }, - function (i, j) { - return (i * j) % 2 + (i * j) % 3 === 0; - }, - function (i, j) { - return ((i * j) % 2 + (i * j) % 3) % 2 === 0; - }, - function (i, j) { - return ((i + j) % 2 + (i * j) % 3) % 2 === 0; - }]; - -// returns true when the version information has to be embeded. -var needsverinfo = function (ver) { - return ver > 6; -}; - -// returns the size of entire QR code for given version. -var getsizebyver = function (ver) { - return 4 * ver + 17; -}; - -// returns the number of bits available for code words in this version. -var nfullbits = function (ver) { - /* - * |<--------------- n --------------->| - * | |<----- n-17 ---->| | - * +-------+ ///+-------+ ---- - * | | ///| | ^ - * | 9x9 | @@@@@ ///| 9x8 | | - * | | # # # @5x5@ # # # | | | - * +-------+ @@@@@ +-------+ | - * # ---| - * ^ | - * # | - * @@@@@ @@@@@ @@@@@ | n - * @5x5@ @5x5@ @5x5@ n-17 - * @@@@@ @@@@@ @@@@@ | | - * # | | - * ////// v | - * //////# ---| - * +-------+ @@@@@ @@@@@ | - * | | @5x5@ @5x5@ | - * | 8x9 | @@@@@ @@@@@ | - * | | v - * +-------+ ---- - * - * when the entire code has n^2 modules and there are m^2-3 alignment - * patterns, we have: - * - 225 (= 9x9 + 9x8 + 8x9) modules for finder patterns and - * format information; - * - 2n-34 (= 2(n-17)) modules for timing patterns; - * - 36 (= 3x6 + 6x3) modules for version information, if any; - * - 25m^2-75 (= (m^2-3)(5x5)) modules for alignment patterns - * if any, but 10m-20 (= 2(m-2)x5) of them overlaps with - * timing patterns. - */ - var v = VERSIONS[ver]; - var nbits = 16 * ver * ver + 128 * ver + 64; // finder, timing and format info. - if (needsverinfo(ver)) - nbits -= 36; // version information - if (v[2].length) { // alignment patterns - nbits -= 25 * v[2].length * v[2].length - 10 * v[2].length - 55; - } - return nbits; -}; - -// returns the number of bits available for data portions (i.e. excludes ECC -// bits but includes mode and length bits) in this version and ECC level. -var ndatabits = function (ver, ecclevel) { - var nbits = nfullbits(ver) & ~7; // no sub-octet code words - var v = VERSIONS[ver]; - nbits -= 8 * v[0][ecclevel] * v[1][ecclevel]; // ecc bits - return nbits; -}; - -// returns the number of bits required for the length of data. -// (cf. Table 3 in JIS X 0510:2004 p. 16) -var ndatalenbits = function (ver, mode) { - switch (mode) { - case MODE_NUMERIC: - return (ver < 10 ? 10 : ver < 27 ? 12 : 14); - case MODE_ALPHANUMERIC: - return (ver < 10 ? 9 : ver < 27 ? 11 : 13); - case MODE_OCTET: - return (ver < 10 ? 8 : 16); - case MODE_KANJI: - return (ver < 10 ? 8 : ver < 27 ? 10 : 12); - } -}; - -// returns the maximum length of data possible in given configuration. -var getmaxdatalen = function (ver, mode, ecclevel) { - var nbits = ndatabits(ver, ecclevel) - 4 - ndatalenbits(ver, mode); // 4 for mode bits - switch (mode) { - case MODE_NUMERIC: - return ((nbits / 10) | 0) * 3 + (nbits % 10 < 4 ? 0 : nbits % 10 < 7 ? 1 : 2); - case MODE_ALPHANUMERIC: - return ((nbits / 11) | 0) * 2 + (nbits % 11 < 6 ? 0 : 1); - case MODE_OCTET: - return (nbits / 8) | 0; - case MODE_KANJI: - return (nbits / 13) | 0; - } -}; - -// checks if the given data can be encoded in given mode, and returns -// the converted data for the further processing if possible. otherwise -// returns null. -// -// this function does not check the length of data; it is a duty of -// encode function below (as it depends on the version and ECC level too). -var validatedata = function (mode, data) { - switch (mode) { - case MODE_NUMERIC: - if (!data.match(NUMERIC_REGEXP)) - return null; - return data; - - case MODE_ALPHANUMERIC: - if (!data.match(ALPHANUMERIC_REGEXP)) - return null; - return data.toUpperCase(); - - case MODE_OCTET: - if (typeof data === 'string') { // encode as utf-8 string - var newdata = []; - for (var i = 0; i < data.length; ++i) { - var ch = data.charCodeAt(i); - if (ch < 0x80) { - newdata.push(ch); - } else if (ch < 0x800) { - newdata.push(0xc0 | (ch >> 6), - 0x80 | (ch & 0x3f)); - } else if (ch < 0x10000) { - newdata.push(0xe0 | (ch >> 12), - 0x80 | ((ch >> 6) & 0x3f), - 0x80 | (ch & 0x3f)); - } else { - newdata.push(0xf0 | (ch >> 18), - 0x80 | ((ch >> 12) & 0x3f), - 0x80 | ((ch >> 6) & 0x3f), - 0x80 | (ch & 0x3f)); - } - } - return newdata; - } else { - return data; - } - } -}; - -// returns the code words (sans ECC bits) for given data and configurations. -// requires data to be preprocessed by validatedata. no length check is -// performed, and everything has to be checked before calling this function. -var encode = function (ver, mode, data, maxbuflen) { - var buf = []; - var bits = 0, remaining = 8; - var datalen = data.length; - - // this function is intentionally no-op when n=0. - var pack = function (x, n) { - if (n >= remaining) { - buf.push(bits | (x >> (n -= remaining))); - while (n >= 8) - buf.push((x >> (n -= 8)) & 255); - bits = 0; - remaining = 8; - } - if (n > 0) - bits |= (x & ((1 << n) - 1)) << (remaining -= n); - }; - - var nlenbits = ndatalenbits(ver, mode); - pack(mode, 4); - pack(datalen, nlenbits); - - switch (mode) { - case MODE_NUMERIC: - for (var i = 2; i < datalen; i += 3) { - pack(parseInt(data.substring(i - 2, i + 1), 10), 10); - } - pack(parseInt(data.substring(i - 2), 10), [0, 4, 7][datalen % 3]); - break; - - case MODE_ALPHANUMERIC: - for (var i = 1; i < datalen; i += 2) { - pack(ALPHANUMERIC_MAP[data.charAt(i - 1)] * 45 + - ALPHANUMERIC_MAP[data.charAt(i)], 11); - } - if (datalen % 2 == 1) { - pack(ALPHANUMERIC_MAP[data.charAt(i - 1)], 6); - } - break; - - case MODE_OCTET: - for (var i = 0; i < datalen; ++i) { - pack(data[i], 8); - } - break; - } - - // final bits. it is possible that adding terminator causes the buffer - // to overflow, but then the buffer truncated to the maximum size will - // be valid as the truncated terminator mode bits and padding is - // identical in appearance (cf. JIS X 0510:2004 sec 8.4.8). - pack(MODE_TERMINATOR, 4); - if (remaining < 8) - buf.push(bits); - - // the padding to fill up the remaining space. we should not add any - // words when the overflow already occurred. - while (buf.length + 1 < maxbuflen) - buf.push(0xec, 0x11); - if (buf.length < maxbuflen) - buf.push(0xec); - return buf; -}; - -// calculates ECC code words for given code words and generator polynomial. -// -// this is quite similar to CRC calculation as both Reed-Solomon and CRC use -// the certain kind of cyclic codes, which is effectively the division of -// zero-augumented polynomial by the generator polynomial. the only difference -// is that Reed-Solomon uses GF(2^8), instead of CRC's GF(2), and Reed-Solomon -// uses the different generator polynomial than CRC's. -var calculateecc = function (poly, genpoly) { - var modulus = poly.slice(0); - var polylen = poly.length, genpolylen = genpoly.length; - for (var i = 0; i < genpolylen; ++i) - modulus.push(0); - for (var i = 0; i < polylen; ) { - var quotient = GF256_INVMAP[modulus[i++]]; - if (quotient >= 0) { - for (var j = 0; j < genpolylen; ++j) { - modulus[i + j] ^= GF256_MAP[(quotient + genpoly[j]) % 255]; - } - } - } - return modulus.slice(polylen); -}; - -// auguments ECC code words to given code words. the resulting words are -// ready to be encoded in the matrix. -// -// the much of actual augumenting procedure follows JIS X 0510:2004 sec 8.7. -// the code is simplified using the fact that the size of each code & ECC -// blocks is almost same; for example, when we have 4 blocks and 46 data words -// the number of code words in those blocks are 11, 11, 12, 12 respectively. -var augumenteccs = function (poly, nblocks, genpoly) { - var subsizes = []; - var subsize = (poly.length / nblocks) | 0, subsize0 = 0; - var pivot = nblocks - poly.length % nblocks; - for (var i = 0; i < pivot; ++i) { - subsizes.push(subsize0); - subsize0 += subsize; - } - for (var i = pivot; i < nblocks; ++i) { - subsizes.push(subsize0); - subsize0 += subsize + 1; - } - subsizes.push(subsize0); - - var eccs = []; - for (var i = 0; i < nblocks; ++i) { - eccs.push(calculateecc(poly.slice(subsizes[i], subsizes[i + 1]), genpoly)); - } - - var result = []; - var nitemsperblock = (poly.length / nblocks) | 0; - for (var i = 0; i < nitemsperblock; ++i) { - for (var j = 0; j < nblocks; ++j) { - result.push(poly[subsizes[j] + i]); - } - } - for (var j = pivot; j < nblocks; ++j) { - result.push(poly[subsizes[j + 1] - 1]); - } - for (var i = 0; i < genpoly.length; ++i) { - for (var j = 0; j < nblocks; ++j) { - result.push(eccs[j][i]); - } - } - return result; -}; - -// auguments BCH(p+q,q) code to the polynomial over GF(2), given the proper -// genpoly. the both input and output are in binary numbers, and unlike -// calculateecc genpoly should include the 1 bit for the highest degree. -// -// actual polynomials used for this procedure are as follows: -// - p=10, q=5, genpoly=x^10+x^8+x^5+x^4+x^2+x+1 (JIS X 0510:2004 Appendix C) -// - p=18, q=6, genpoly=x^12+x^11+x^10+x^9+x^8+x^5+x^2+1 (ibid. Appendix D) -var augumentbch = function (poly, p, genpoly, q) { - var modulus = poly << q; - for (var i = p - 1; i >= 0; --i) { - if ((modulus >> (q + i)) & 1) - modulus ^= genpoly << i; - } - return (poly << q) | modulus; -}; - -// creates the base matrix for given version. it returns two matrices, one of -// them is the actual one and the another represents the "reserved" portion -// (e.g. finder and timing patterns) of the matrix. -// -// some entries in the matrix may be undefined, rather than 0 or 1. this is -// intentional (no initialization needed!), and putdata below will fill -// the remaining ones. -var makebasematrix = function (ver) { - var v = VERSIONS[ver], n = getsizebyver(ver); - var matrix = [], reserved = []; - for (var i = 0; i < n; ++i) { - matrix.push([]); - reserved.push([]); - } - - var blit = function (y, x, h, w, bits) { - for (var i = 0; i < h; ++i) { - for (var j = 0; j < w; ++j) { - matrix[y + i][x + j] = (bits[i] >> j) & 1; - reserved[y + i][x + j] = 1; - } - } - }; - - // finder patterns and a part of timing patterns - // will also mark the format information area (not yet written) as reserved. - blit(0, 0, 9, 9, [0x7f, 0x41, 0x5d, 0x5d, 0x5d, 0x41, 0x17f, 0x00, 0x40]); - blit(n - 8, 0, 8, 9, [0x100, 0x7f, 0x41, 0x5d, 0x5d, 0x5d, 0x41, 0x7f]); - blit(0, n - 8, 9, 8, [0xfe, 0x82, 0xba, 0xba, 0xba, 0x82, 0xfe, 0x00, 0x00]); - - // the rest of timing patterns - for (var i = 9; i < n - 8; ++i) { - matrix[6][i] = matrix[i][6] = ~i & 1; - reserved[6][i] = reserved[i][6] = 1; - } - - // alignment patterns - var aligns = v[2], m = aligns.length; - for (var i = 0; i < m; ++i) { - var minj = (i === 0 || i === m - 1 ? 1 : 0), maxj = (i === 0 ? m - 1 : m); - for (var j = minj; j < maxj; ++j) { - blit(aligns[i], aligns[j], 5, 5, [0x1f, 0x11, 0x15, 0x11, 0x1f]); - } - } - - // version information - if (needsverinfo(ver)) { - var code = augumentbch(ver, 6, 0x1f25, 12); - var k = 0; - for (var i = 0; i < 6; ++i) { - for (var j = 0; j < 3; ++j) { - matrix[i][(n - 11) + j] = matrix[(n - 11) + j][i] = (code >> k++) & 1; - reserved[i][(n - 11) + j] = reserved[(n - 11) + j][i] = 1; - } - } - } - - return {matrix: matrix, reserved: reserved}; -}; - -// fills the data portion (i.e. unmarked in reserved) of the matrix with given -// code words. the size of code words should be no more than available bits, -// and remaining bits are padded to 0 (cf. JIS X 0510:2004 sec 8.7.3). -var putdata = function (matrix, reserved, buf) { - var n = matrix.length; - var k = 0, dir = -1; - for (var i = n - 1; i >= 0; i -= 2) { - if (i == 6) - --i; // skip the entire timing pattern column - var jj = (dir < 0 ? n - 1 : 0); - for (var j = 0; j < n; ++j) { - for (var ii = i; ii > i - 2; --ii) { - if (!reserved[jj][ii]) { - // may overflow, but (undefined >> x) - // is 0 so it will auto-pad to zero. - matrix[jj][ii] = (buf[k >> 3] >> (~k & 7)) & 1; - ++k; - } - } - jj += dir; - } - dir = -dir; - } - return matrix; -}; - -// XOR-masks the data portion of the matrix. repeating the call with the same -// arguments will revert the prior call (convenient in the matrix evaluation). -var maskdata = function (matrix, reserved, mask) { - var maskf = MASKFUNCS[mask]; - var n = matrix.length; - for (var i = 0; i < n; ++i) { - for (var j = 0; j < n; ++j) { - if (!reserved[i][j]) - matrix[i][j] ^= maskf(i, j); - } - } - return matrix; -}; - -// puts the format information. -var putformatinfo = function (matrix, reserved, ecclevel, mask) { - var n = matrix.length; - var code = augumentbch((ecclevel << 3) | mask, 5, 0x537, 10) ^ 0x5412; - for (var i = 0; i < 15; ++i) { - var r = [0, 1, 2, 3, 4, 5, 7, 8, n - 7, n - 6, n - 5, n - 4, n - 3, n - 2, n - 1][i]; - var c = [n - 1, n - 2, n - 3, n - 4, n - 5, n - 6, n - 7, n - 8, 7, 5, 4, 3, 2, 1, 0][i]; - matrix[r][8] = matrix[8][c] = (code >> i) & 1; - // we don't have to mark those bits reserved; always done - // in makebasematrix above. - } - return matrix; -}; - -// evaluates the resulting matrix and returns the score (lower is better). -// (cf. JIS X 0510:2004 sec 8.8.2) -// -// the evaluation procedure tries to avoid the problematic patterns naturally -// occuring from the original matrix. for example, it penaltizes the patterns -// which just look like the finder pattern which will confuse the decoder. -// we choose the mask which results in the lowest score among 8 possible ones. -// -// note: zxing seems to use the same procedure and in many cases its choice -// agrees to ours, but sometimes it does not. practically it doesn't matter. -var evaluatematrix = function (matrix) { - // N1+(k-5) points for each consecutive row of k same-colored modules, - // where k >= 5. no overlapping row counts. - var PENALTY_CONSECUTIVE = 3; - // N2 points for each 2x2 block of same-colored modules. - // overlapping block does count. - var PENALTY_TWOBYTWO = 3; - // N3 points for each pattern with >4W:1B:1W:3B:1W:1B or - // 1B:1W:3B:1W:1B:>4W, or their multiples (e.g. highly unlikely, - // but 13W:3B:3W:9B:3W:3B counts). - var PENALTY_FINDERLIKE = 40; - // N4*k points for every (5*k)% deviation from 50% black density. - // i.e. k=1 for 55~60% and 40~45%, k=2 for 60~65% and 35~40%, etc. - var PENALTY_DENSITY = 10; - - var evaluategroup = function (groups) { // assumes [W,B,W,B,W,...,B,W] - var score = 0; - for (var i = 0; i < groups.length; ++i) { - if (groups[i] >= 5) - score += PENALTY_CONSECUTIVE + (groups[i] - 5); - } - for (var i = 5; i < groups.length; i += 2) { - var p = groups[i]; - if (groups[i - 1] == p && groups[i - 2] == 3 * p && groups[i - 3] == p && - groups[i - 4] == p && (groups[i - 5] >= 4 * p || groups[i + 1] >= 4 * p)) { - // this part differs from zxing... - score += PENALTY_FINDERLIKE; - } - } - return score; - }; - - var n = matrix.length; - var score = 0, nblacks = 0; - for (var i = 0; i < n; ++i) { - var row = matrix[i]; - var groups; - - // evaluate the current row - groups = [0]; // the first empty group of white - for (var j = 0; j < n; ) { - var k; - for (k = 0; j < n && row[j]; ++k) - ++j; - groups.push(k); - for (k = 0; j < n && !row[j]; ++k) - ++j; - groups.push(k); - } - score += evaluategroup(groups); - - // evaluate the current column - groups = [0]; - for (var j = 0; j < n; ) { - var k; - for (k = 0; j < n && matrix[j][i]; ++k) - ++j; - groups.push(k); - for (k = 0; j < n && !matrix[j][i]; ++k) - ++j; - groups.push(k); - } - score += evaluategroup(groups); - - // check the 2x2 box and calculate the density - var nextrow = matrix[i + 1] || []; - nblacks += row[0]; - for (var j = 1; j < n; ++j) { - var p = row[j]; - nblacks += p; - // at least comparison with next row should be strict... - if (row[j - 1] == p && nextrow[j] === p && nextrow[j - 1] === p) { - score += PENALTY_TWOBYTWO; - } - } - } - - score += PENALTY_DENSITY * ((Math.abs(nblacks / n / n - 0.5) / 0.05) | 0); - return score; -}; - -// returns the fully encoded QR code matrix which contains given data. -// it also chooses the best mask automatically when mask is -1. -var generate = function (data, ver, mode, ecclevel, mask) { - var v = VERSIONS[ver]; - var buf = encode(ver, mode, data, ndatabits(ver, ecclevel) >> 3); - buf = augumenteccs(buf, v[1][ecclevel], GF256_GENPOLY[v[0][ecclevel]]); - - var result = makebasematrix(ver); - var matrix = result.matrix, reserved = result.reserved; - putdata(matrix, reserved, buf); - - if (mask < 0) { - // find the best mask - maskdata(matrix, reserved, 0); - putformatinfo(matrix, reserved, ecclevel, 0); - var bestmask = 0, bestscore = evaluatematrix(matrix); - maskdata(matrix, reserved, 0); - for (mask = 1; mask < 8; ++mask) { - maskdata(matrix, reserved, mask); - putformatinfo(matrix, reserved, ecclevel, mask); - var score = evaluatematrix(matrix); - if (bestscore > score) { - bestscore = score; - bestmask = mask; - } - maskdata(matrix, reserved, mask); - } - mask = bestmask; - } - - maskdata(matrix, reserved, mask); - putformatinfo(matrix, reserved, ecclevel, mask); - return matrix; -}; - -// the public interface is trivial; the options available are as follows: -// -// - version: an integer in [1,40]. when omitted (or -1) the smallest possible -// version is chosen. -// - mode: one of 'numeric', 'alphanumeric', 'octet'. when omitted the smallest -// possible mode is chosen. -// - eccLevel: one of 'L', 'M', 'Q', 'H'. defaults to 'L'. -// - mask: an integer in [0,7]. when omitted (or -1) the best mask is chosen. -// - -function generateFrame(data, options) { - var MODES = {'numeric': MODE_NUMERIC, 'alphanumeric': MODE_ALPHANUMERIC, - 'octet': MODE_OCTET}; - var ECCLEVELS = {'L': ECCLEVEL_L, 'M': ECCLEVEL_M, 'Q': ECCLEVEL_Q, - 'H': ECCLEVEL_H}; - - options = options || {}; - var ver = options.version || -1; - var ecclevel = ECCLEVELS[(options.eccLevel || 'L').toUpperCase()]; - var mode = options.mode ? MODES[options.mode.toLowerCase()] : -1; - var mask = 'mask' in options ? options.mask : -1; - - if (mode < 0) { - if (typeof data === 'string') { - if (data.match(NUMERIC_REGEXP)) { - mode = MODE_NUMERIC; - } else if (data.match(ALPHANUMERIC_OUT_REGEXP)) { - // while encode supports case-insensitive encoding, we restrict the data to be uppercased when auto-selecting the mode. - mode = MODE_ALPHANUMERIC; - } else { - mode = MODE_OCTET; - } - } else { - mode = MODE_OCTET; - } - } else if (!(mode == MODE_NUMERIC || mode == MODE_ALPHANUMERIC || - mode == MODE_OCTET)) { - throw 'invalid or unsupported mode'; - } - - data = validatedata(mode, data); - if (data === null) - throw 'invalid data format'; - - if (ecclevel < 0 || ecclevel > 3) - throw 'invalid ECC level'; - - if (ver < 0) { - for (ver = 1; ver <= 40; ++ver) { - if (data.length <= getmaxdatalen(ver, mode, ecclevel)) - break; - } - if (ver > 40) - throw 'too large data for the Qr format'; - } else if (ver < 1 || ver > 40) { - throw 'invalid Qr version! should be between 1 and 40'; - } - - if (mask != -1 && (mask < 0 || mask > 8)) - throw 'invalid mask'; - //console.log('version:', ver, 'mode:', mode, 'ECC:', ecclevel, 'mask:', mask ) - return generate(data, ver, mode, ecclevel, mask); -} - - -// options -// - modulesize: a number. this is a size of each modules in pixels, and -// defaults to 5px. -// - margin: a number. this is a size of margin in *modules*, and defaults to -// 4 (white modules). the specficiation mandates the margin no less than 4 -// modules, so it is better not to alter this value unless you know what -// you're doing. -function buildCanvas(data, options) { - - var canvas = []; - var background = options.background || '#fff'; - var foreground = options.foreground || '#000'; - //var margin = options.margin || 4; - var matrix = generateFrame(data, options); - var n = matrix.length; - var modSize = Math.floor(options.fit ? options.fit / n : 5); - var size = n * modSize; - - canvas.push({ - type: 'rect', - x: 0, y: 0, w: size, h: size, lineWidth: 0, color: background - }); - - for (var i = 0; i < n; ++i) { - for (var j = 0; j < n; ++j) { - if (matrix[i][j]) { - canvas.push({ - type: 'rect', - x: modSize * j, - y: modSize * i, - w: modSize, - h: modSize, - lineWidth: 0, - color: foreground - }); - } - } - } - - return { - canvas: canvas, - size: size - }; - -} - -function measure(node) { - var cd = buildCanvas(node.qr, node); - node._canvas = cd.canvas; - node._width = node._height = node._minWidth = node._maxWidth = node._minHeight = node._maxHeight = cd.size; - return node; -} - -module.exports = { - measure: measure -}; - -/***/ }), -/* 135 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var ElementWriter = __webpack_require__(136); - -/** - * Creates an instance of PageElementWriter - an extended ElementWriter - * which can handle: - * - page-breaks (it adds new pages when there's not enough space left), - * - repeatable fragments (like table-headers, which are repeated everytime - * a page-break occurs) - * - transactions (used for unbreakable-blocks when we want to make sure - * whole block will be rendered on the same page) - */ -function PageElementWriter(context, tracker) { - this.transactionLevel = 0; - this.repeatables = []; - this.tracker = tracker; - this.writer = new ElementWriter(context, tracker); -} - -function fitOnPage(self, addFct) { - var position = addFct(self); - if (!position) { - self.moveToNextPage(); - position = addFct(self); - } - return position; -} - -PageElementWriter.prototype.addLine = function (line, dontUpdateContextPosition, index) { - return fitOnPage(this, function (self) { - return self.writer.addLine(line, dontUpdateContextPosition, index); - }); -}; - -PageElementWriter.prototype.addImage = function (image, index) { - return fitOnPage(this, function (self) { - return self.writer.addImage(image, index); - }); -}; - -PageElementWriter.prototype.addQr = function (qr, index) { - return fitOnPage(this, function (self) { - return self.writer.addQr(qr, index); - }); -}; - -PageElementWriter.prototype.addVector = function (vector, ignoreContextX, ignoreContextY, index) { - return this.writer.addVector(vector, ignoreContextX, ignoreContextY, index); -}; - -PageElementWriter.prototype.beginClip = function (width, height) { - return this.writer.beginClip(width, height); -}; - -PageElementWriter.prototype.endClip = function () { - return this.writer.endClip(); -}; - -PageElementWriter.prototype.alignCanvas = function (node) { - this.writer.alignCanvas(node); -}; - -PageElementWriter.prototype.addFragment = function (fragment, useBlockXOffset, useBlockYOffset, dontUpdateContextPosition) { - if (!this.writer.addFragment(fragment, useBlockXOffset, useBlockYOffset, dontUpdateContextPosition)) { - this.moveToNextPage(); - this.writer.addFragment(fragment, useBlockXOffset, useBlockYOffset, dontUpdateContextPosition); - } -}; - -PageElementWriter.prototype.moveToNextPage = function (pageOrientation) { - - var nextPage = this.writer.context.moveToNextPage(pageOrientation); - - if (nextPage.newPageCreated) { - this.repeatables.forEach(function (rep) { - this.writer.addFragment(rep, true); - }, this); - } else { - this.repeatables.forEach(function (rep) { - this.writer.context.moveDown(rep.height); - }, this); - } - - this.writer.tracker.emit('pageChanged', { - prevPage: nextPage.prevPage, - prevY: nextPage.prevY, - y: nextPage.y - }); -}; - -PageElementWriter.prototype.beginUnbreakableBlock = function (width, height) { - if (this.transactionLevel++ === 0) { - this.originalX = this.writer.context.x; - this.writer.pushContext(width, height); - } -}; - -PageElementWriter.prototype.commitUnbreakableBlock = function (forcedX, forcedY) { - if (--this.transactionLevel === 0) { - var unbreakableContext = this.writer.context; - this.writer.popContext(); - - var nbPages = unbreakableContext.pages.length; - if (nbPages > 0) { - // no support for multi-page unbreakableBlocks - var fragment = unbreakableContext.pages[0]; - fragment.xOffset = forcedX; - fragment.yOffset = forcedY; - - //TODO: vectors can influence height in some situations - if (nbPages > 1) { - // on out-of-context blocs (headers, footers, background) height should be the whole DocumentContext height - if (forcedX !== undefined || forcedY !== undefined) { - fragment.height = unbreakableContext.getCurrentPage().pageSize.height - unbreakableContext.pageMargins.top - unbreakableContext.pageMargins.bottom; - } else { - fragment.height = this.writer.context.getCurrentPage().pageSize.height - this.writer.context.pageMargins.top - this.writer.context.pageMargins.bottom; - for (var i = 0, l = this.repeatables.length; i < l; i++) { - fragment.height -= this.repeatables[i].height; - } - } - } else { - fragment.height = unbreakableContext.y; - } - - if (forcedX !== undefined || forcedY !== undefined) { - this.writer.addFragment(fragment, true, true, true); - } else { - this.addFragment(fragment); - } - } - } -}; - -PageElementWriter.prototype.currentBlockToRepeatable = function () { - var unbreakableContext = this.writer.context; - var rep = {items: []}; - - unbreakableContext.pages[0].items.forEach(function (item) { - rep.items.push(item); - }); - - rep.xOffset = this.originalX; - - //TODO: vectors can influence height in some situations - rep.height = unbreakableContext.y; - - return rep; -}; - -PageElementWriter.prototype.pushToRepeatables = function (rep) { - this.repeatables.push(rep); -}; - -PageElementWriter.prototype.popFromRepeatables = function () { - this.repeatables.pop(); -}; - -PageElementWriter.prototype.context = function () { - return this.writer.context; -}; - -module.exports = PageElementWriter; - - -/***/ }), -/* 136 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var Line = __webpack_require__(82); -var isNumber = __webpack_require__(0).isNumber; -var pack = __webpack_require__(0).pack; -var offsetVector = __webpack_require__(0).offsetVector; -var DocumentContext = __webpack_require__(81); - -/** - * Creates an instance of ElementWriter - a line/vector writer, which adds - * elements to current page and sets their positions based on the context - */ -function ElementWriter(context, tracker) { - this.context = context; - this.contextStack = []; - this.tracker = tracker; -} - -function addPageItem(page, item, index) { - if (index === null || index === undefined || index < 0 || index > page.items.length) { - page.items.push(item); - } else { - page.items.splice(index, 0, item); - } -} - -ElementWriter.prototype.addLine = function (line, dontUpdateContextPosition, index) { - var height = line.getHeight(); - var context = this.context; - var page = context.getCurrentPage(), - position = this.getCurrentPositionOnPage(); - - if (context.availableHeight < height || !page) { - return false; - } - - line.x = context.x + (line.x || 0); - line.y = context.y + (line.y || 0); - - this.alignLine(line); - - addPageItem(page, { - type: 'line', - item: line - }, index); - this.tracker.emit('lineAdded', line); - - if (!dontUpdateContextPosition) { - context.moveDown(height); - } - - return position; -}; - -ElementWriter.prototype.alignLine = function (line) { - var width = this.context.availableWidth; - var lineWidth = line.getWidth(); - - var alignment = line.inlines && line.inlines.length > 0 && line.inlines[0].alignment; - - var offset = 0; - switch (alignment) { - case 'right': - offset = width - lineWidth; - break; - case 'center': - offset = (width - lineWidth) / 2; - break; - } - - if (offset) { - line.x = (line.x || 0) + offset; - } - - if (alignment === 'justify' && - !line.newLineForced && - !line.lastLineInParagraph && - line.inlines.length > 1) { - var additionalSpacing = (width - lineWidth) / (line.inlines.length - 1); - - for (var i = 1, l = line.inlines.length; i < l; i++) { - offset = i * additionalSpacing; - - line.inlines[i].x += offset; - line.inlines[i].justifyShift = additionalSpacing; - } - } -}; - -ElementWriter.prototype.addImage = function (image, index) { - var context = this.context; - var page = context.getCurrentPage(), - position = this.getCurrentPositionOnPage(); - - if (!page || (image.absolutePosition === undefined && context.availableHeight < image._height && page.items.length > 0)) { - return false; - } - - if (image._x === undefined) { - image._x = image.x || 0; - } - - image.x = context.x + image._x; - image.y = context.y; - - this.alignImage(image); - - addPageItem(page, { - type: 'image', - item: image - }, index); - - context.moveDown(image._height); - - return position; -}; - -ElementWriter.prototype.addQr = function (qr, index) { - var context = this.context; - var page = context.getCurrentPage(), - position = this.getCurrentPositionOnPage(); - - if (!page || (qr.absolutePosition === undefined && context.availableHeight < qr._height)) { - return false; - } - - if (qr._x === undefined) { - qr._x = qr.x || 0; - } - - qr.x = context.x + qr._x; - qr.y = context.y; - - this.alignImage(qr); - - for (var i = 0, l = qr._canvas.length; i < l; i++) { - var vector = qr._canvas[i]; - vector.x += qr.x; - vector.y += qr.y; - this.addVector(vector, true, true, index); - } - - context.moveDown(qr._height); - - return position; -}; - -ElementWriter.prototype.alignImage = function (image) { - var width = this.context.availableWidth; - var imageWidth = image._minWidth; - var offset = 0; - switch (image._alignment) { - case 'right': - offset = width - imageWidth; - break; - case 'center': - offset = (width - imageWidth) / 2; - break; - } - - if (offset) { - image.x = (image.x || 0) + offset; - } -}; - -ElementWriter.prototype.alignCanvas = function (node) { - var width = this.context.availableWidth; - var canvasWidth = node._minWidth; - var offset = 0; - switch (node._alignment) { - case 'right': - offset = width - canvasWidth; - break; - case 'center': - offset = (width - canvasWidth) / 2; - break; - } - if (offset) { - node.canvas.forEach(function (vector) { - offsetVector(vector, offset, 0); - }); - } -}; - -ElementWriter.prototype.addVector = function (vector, ignoreContextX, ignoreContextY, index) { - var context = this.context; - var page = context.getCurrentPage(), - position = this.getCurrentPositionOnPage(); - - if (page) { - offsetVector(vector, ignoreContextX ? 0 : context.x, ignoreContextY ? 0 : context.y); - addPageItem(page, { - type: 'vector', - item: vector - }, index); - return position; - } -}; - -ElementWriter.prototype.beginClip = function (width, height) { - var ctx = this.context; - var page = ctx.getCurrentPage(); - page.items.push({ - type: 'beginClip', - item: {x: ctx.x, y: ctx.y, width: width, height: height} - }); - return true; -}; - -ElementWriter.prototype.endClip = function () { - var ctx = this.context; - var page = ctx.getCurrentPage(); - page.items.push({ - type: 'endClip' - }); - return true; -}; - -function cloneLine(line) { - var result = new Line(line.maxWidth); - - for (var key in line) { - if (line.hasOwnProperty(key)) { - result[key] = line[key]; - } - } - - return result; -} - -ElementWriter.prototype.addFragment = function (block, useBlockXOffset, useBlockYOffset, dontUpdateContextPosition) { - var ctx = this.context; - var page = ctx.getCurrentPage(); - - if (!useBlockXOffset && block.height > ctx.availableHeight) { - return false; - } - - block.items.forEach(function (item) { - switch (item.type) { - case 'line': - var l = cloneLine(item.item); - - l.x = (l.x || 0) + (useBlockXOffset ? (block.xOffset || 0) : ctx.x); - l.y = (l.y || 0) + (useBlockYOffset ? (block.yOffset || 0) : ctx.y); - - page.items.push({ - type: 'line', - item: l - }); - break; - - case 'vector': - var v = pack(item.item); - - offsetVector(v, useBlockXOffset ? (block.xOffset || 0) : ctx.x, useBlockYOffset ? (block.yOffset || 0) : ctx.y); - page.items.push({ - type: 'vector', - item: v - }); - break; - - case 'image': - var img = pack(item.item); - - img.x = (img.x || 0) + (useBlockXOffset ? (block.xOffset || 0) : ctx.x); - img.y = (img.y || 0) + (useBlockYOffset ? (block.yOffset || 0) : ctx.y); - - page.items.push({ - type: 'image', - item: img - }); - break; - } - }); - - if (!dontUpdateContextPosition) { - ctx.moveDown(block.height); - } - - return true; -}; - -/** - * Pushes the provided context onto the stack or creates a new one - * - * pushContext(context) - pushes the provided context and makes it current - * pushContext(width, height) - creates and pushes a new context with the specified width and height - * pushContext() - creates a new context for unbreakable blocks (with current availableWidth and full-page-height) - */ -ElementWriter.prototype.pushContext = function (contextOrWidth, height) { - if (contextOrWidth === undefined) { - height = this.context.getCurrentPage().height - this.context.pageMargins.top - this.context.pageMargins.bottom; - contextOrWidth = this.context.availableWidth; - } - - if (isNumber(contextOrWidth)) { - contextOrWidth = new DocumentContext({width: contextOrWidth, height: height}, {left: 0, right: 0, top: 0, bottom: 0}); - } - - this.contextStack.push(this.context); - this.context = contextOrWidth; -}; - -ElementWriter.prototype.popContext = function () { - this.context = this.contextStack.pop(); -}; - -ElementWriter.prototype.getCurrentPositionOnPage = function () { - return (this.contextStack[0] || this.context).getCurrentPosition(); -}; - - -module.exports = ElementWriter; - - -/***/ }), -/* 137 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var ColumnCalculator = __webpack_require__(44); -var isFunction = __webpack_require__(0).isFunction; - -function TableProcessor(tableNode) { - this.tableNode = tableNode; -} - -TableProcessor.prototype.beginTable = function (writer) { - var tableNode; - var availableWidth; - var self = this; - - tableNode = this.tableNode; - this.offsets = tableNode._offsets; - this.layout = tableNode._layout; - - availableWidth = writer.context().availableWidth - this.offsets.total; - ColumnCalculator.buildColumnWidths(tableNode.table.widths, availableWidth); - - this.tableWidth = tableNode._offsets.total + getTableInnerContentWidth(); - this.rowSpanData = prepareRowSpanData(); - this.cleanUpRepeatables = false; - - this.headerRows = tableNode.table.headerRows || 0; - this.rowsWithoutPageBreak = this.headerRows + (tableNode.table.keepWithHeaderRows || 0); - this.dontBreakRows = tableNode.table.dontBreakRows || false; - - if (this.rowsWithoutPageBreak) { - writer.beginUnbreakableBlock(); - } - - // update the border properties of all cells before drawing any lines - prepareCellBorders(this.tableNode.table.body); - - this.drawHorizontalLine(0, writer); - - function getTableInnerContentWidth() { - var width = 0; - - tableNode.table.widths.forEach(function (w) { - width += w._calcWidth; - }); - - return width; - } - - function prepareRowSpanData() { - var rsd = []; - var x = 0; - var lastWidth = 0; - - rsd.push({left: 0, rowSpan: 0}); - - for (var i = 0, l = self.tableNode.table.body[0].length; i < l; i++) { - var paddings = self.layout.paddingLeft(i, self.tableNode) + self.layout.paddingRight(i, self.tableNode); - var lBorder = self.layout.vLineWidth(i, self.tableNode); - lastWidth = paddings + lBorder + self.tableNode.table.widths[i]._calcWidth; - rsd[rsd.length - 1].width = lastWidth; - x += lastWidth; - rsd.push({left: x, rowSpan: 0, width: 0}); - } - - return rsd; - } - - // Iterate through all cells. If the current cell is the start of a - // rowSpan/colSpan, update the border property of the cells on its - // bottom/right accordingly. This is needed since each iteration of the - // line-drawing loops draws lines for a single cell, not for an entire - // rowSpan/colSpan. - function prepareCellBorders(body) { - for (var rowIndex = 0; rowIndex < body.length; rowIndex++) { - var row = body[rowIndex]; - - for (var colIndex = 0; colIndex < row.length; colIndex++) { - var cell = row[colIndex]; - - if (cell.border) { - var rowSpan = cell.rowSpan || 1; - var colSpan = cell.colSpan || 1; - - for (var rowOffset = 0; rowOffset < rowSpan; rowOffset++) { - // set left border - if (cell.border[0] !== undefined && rowOffset > 0) { - setBorder(rowIndex + rowOffset, colIndex, 0, cell.border[0]); - } - - // set right border - if (cell.border[2] !== undefined) { - setBorder(rowIndex + rowOffset, colIndex + colSpan - 1, 2, cell.border[2]); - } - } - - for (var colOffset = 0; colOffset < colSpan; colOffset++) { - // set top border - if (cell.border[1] !== undefined && colOffset > 0) { - setBorder(rowIndex, colIndex + colOffset, 1, cell.border[1]); - } - - // set bottom border - if (cell.border[3] !== undefined) { - setBorder(rowIndex + rowSpan - 1, colIndex + colOffset, 3, cell.border[3]); - } - } - } - } - } - - // helper function to set the border for a given cell - function setBorder(rowIndex, colIndex, borderIndex, borderValue) { - var cell = body[rowIndex][colIndex]; - cell.border = cell.border || {}; - cell.border[borderIndex] = borderValue; - } - } -}; - -TableProcessor.prototype.onRowBreak = function (rowIndex, writer) { - var self = this; - return function () { - var offset = self.rowPaddingTop + (!self.headerRows ? self.topLineWidth : 0); - writer.context().availableHeight -= self.reservedAtBottom; - writer.context().moveDown(offset); - }; -}; - -TableProcessor.prototype.beginRow = function (rowIndex, writer) { - this.topLineWidth = this.layout.hLineWidth(rowIndex, this.tableNode); - this.rowPaddingTop = this.layout.paddingTop(rowIndex, this.tableNode); - this.bottomLineWidth = this.layout.hLineWidth(rowIndex + 1, this.tableNode); - this.rowPaddingBottom = this.layout.paddingBottom(rowIndex, this.tableNode); - - this.rowCallback = this.onRowBreak(rowIndex, writer); - writer.tracker.startTracking('pageChanged', this.rowCallback); - if (this.dontBreakRows) { - writer.beginUnbreakableBlock(); - } - this.rowTopY = writer.context().y; - this.reservedAtBottom = this.bottomLineWidth + this.rowPaddingBottom; - - writer.context().availableHeight -= this.reservedAtBottom; - - writer.context().moveDown(this.rowPaddingTop); -}; - -TableProcessor.prototype.drawHorizontalLine = function (lineIndex, writer, overrideY) { - var lineWidth = this.layout.hLineWidth(lineIndex, this.tableNode); - if (lineWidth) { - var offset = lineWidth / 2; - var currentLine = null; - var body = this.tableNode.table.body; - - for (var i = 0, l = this.rowSpanData.length; i < l; i++) { - var data = this.rowSpanData[i]; - var shouldDrawLine = !data.rowSpan; - - // draw only if the current cell requires a top border or the cell in the - // row above requires a bottom border - if (shouldDrawLine && i < l - 1) { - var topBorder = false, bottomBorder = false; - - // the current cell - if (lineIndex < body.length) { - var cell = body[lineIndex][i]; - topBorder = cell.border ? cell.border[1] : this.layout.defaultBorder; - } - - // the cell in the row above - if (lineIndex > 0) { - var cellAbove = body[lineIndex - 1][i]; - bottomBorder = cellAbove.border ? cellAbove.border[3] : this.layout.defaultBorder; - } - - shouldDrawLine = topBorder || bottomBorder; - } - - if (!currentLine && shouldDrawLine) { - currentLine = {left: data.left, width: 0}; - } - - if (shouldDrawLine) { - currentLine.width += (data.width || 0); - } - - var y = (overrideY || 0) + offset; - - if (!shouldDrawLine || i === l - 1) { - if (currentLine && currentLine.width) { - writer.addVector({ - type: 'line', - x1: currentLine.left, - x2: currentLine.left + currentLine.width, - y1: y, - y2: y, - lineWidth: lineWidth, - lineColor: isFunction(this.layout.hLineColor) ? this.layout.hLineColor(lineIndex, this.tableNode) : this.layout.hLineColor - }, false, overrideY); - currentLine = null; - } - } - } - - writer.context().moveDown(lineWidth); - } -}; - -TableProcessor.prototype.drawVerticalLine = function (x, y0, y1, vLineIndex, writer) { - var width = this.layout.vLineWidth(vLineIndex, this.tableNode); - if (width === 0) { - return; - } - writer.addVector({ - type: 'line', - x1: x + width / 2, - x2: x + width / 2, - y1: y0, - y2: y1, - lineWidth: width, - lineColor: isFunction(this.layout.vLineColor) ? this.layout.vLineColor(vLineIndex, this.tableNode) : this.layout.vLineColor - }, false, true); -}; - -TableProcessor.prototype.endTable = function (writer) { - if (this.cleanUpRepeatables) { - writer.popFromRepeatables(); - this.headerRepeatableHeight = null; - } -}; - -TableProcessor.prototype.endRow = function (rowIndex, writer, pageBreaks) { - var l, i; - var self = this; - writer.tracker.stopTracking('pageChanged', this.rowCallback); - writer.context().moveDown(this.layout.paddingBottom(rowIndex, this.tableNode)); - writer.context().availableHeight += this.reservedAtBottom; - - var endingPage = writer.context().page; - var endingY = writer.context().y; - - var xs = getLineXs(); - - var ys = []; - - var hasBreaks = pageBreaks && pageBreaks.length > 0; - var body = this.tableNode.table.body; - - ys.push({ - y0: this.rowTopY, - page: hasBreaks ? pageBreaks[0].prevPage : endingPage - }); - - if (hasBreaks) { - for (i = 0, l = pageBreaks.length; i < l; i++) { - var pageBreak = pageBreaks[i]; - ys[ys.length - 1].y1 = pageBreak.prevY; - - ys.push({y0: pageBreak.y, page: pageBreak.prevPage + 1}); - - if (this.headerRepeatableHeight) { - ys[ys.length - 1].y0 += this.headerRepeatableHeight; - } - } - } - - ys[ys.length - 1].y1 = endingY; - - var skipOrphanePadding = (ys[0].y1 - ys[0].y0 === this.rowPaddingTop); - for (var yi = (skipOrphanePadding ? 1 : 0), yl = ys.length; yi < yl; yi++) { - var willBreak = yi < ys.length - 1; - var rowBreakWithoutHeader = (yi > 0 && !this.headerRows); - var hzLineOffset = rowBreakWithoutHeader ? 0 : this.topLineWidth; - var y1 = ys[yi].y0; - var y2 = ys[yi].y1; - - if (willBreak) { - y2 = y2 + this.rowPaddingBottom; - } - - if (writer.context().page != ys[yi].page) { - writer.context().page = ys[yi].page; - - //TODO: buggy, availableHeight should be updated on every pageChanged event - // TableProcessor should be pageChanged listener, instead of processRow - this.reservedAtBottom = 0; - } - - for (i = 0, l = xs.length; i < l; i++) { - var leftBorder = false, rightBorder = false; - var colIndex = xs[i].index; - - // the current cell - if (colIndex < body[rowIndex].length) { - var cell = body[rowIndex][colIndex]; - leftBorder = cell.border ? cell.border[0] : this.layout.defaultBorder; - } - - // the cell from before column - if (colIndex > 0) { - var cell = body[rowIndex][colIndex - 1]; - rightBorder = cell.border ? cell.border[2] : this.layout.defaultBorder; - } - - if (leftBorder || rightBorder) { - this.drawVerticalLine(xs[i].x, y1 - hzLineOffset, y2 + this.bottomLineWidth, xs[i].index, writer); - } - - if (i < l - 1) { - var fillColor = body[rowIndex][colIndex].fillColor; - if (!fillColor) { - fillColor = isFunction(this.layout.fillColor) ? this.layout.fillColor(rowIndex, this.tableNode, colIndex) : this.layout.fillColor; - } - if (fillColor) { - var wBorder = (leftBorder || rightBorder) ? this.layout.vLineWidth(colIndex, this.tableNode) : 0; - var xf = xs[i].x + wBorder; - var yf = this.dontBreakRows ? y1 : y1 - hzLineOffset; - writer.addVector({ - type: 'rect', - x: xf, - y: yf, - w: xs[i + 1].x - xf, - h: y2 + this.bottomLineWidth - yf, - lineWidth: 0, - color: fillColor - }, false, true, writer.context().hasBackground ? 1 : 0); - } - } - } - - if (willBreak && this.layout.hLineWhenBroken !== false) { - this.drawHorizontalLine(rowIndex + 1, writer, y2); - } - if (rowBreakWithoutHeader && this.layout.hLineWhenBroken !== false) { - this.drawHorizontalLine(rowIndex, writer, y1); - } - } - - writer.context().page = endingPage; - writer.context().y = endingY; - - var row = this.tableNode.table.body[rowIndex]; - for (i = 0, l = row.length; i < l; i++) { - if (row[i].rowSpan) { - this.rowSpanData[i].rowSpan = row[i].rowSpan; - - // fix colSpans - if (row[i].colSpan && row[i].colSpan > 1) { - for (var j = 1; j < row[i].rowSpan; j++) { - this.tableNode.table.body[rowIndex + j][i]._colSpan = row[i].colSpan; - } - } - } - - if (this.rowSpanData[i].rowSpan > 0) { - this.rowSpanData[i].rowSpan--; - } - } - - this.drawHorizontalLine(rowIndex + 1, writer); - - if (this.headerRows && rowIndex === this.headerRows - 1) { - this.headerRepeatable = writer.currentBlockToRepeatable(); - } - - if (this.dontBreakRows) { - writer.tracker.auto('pageChanged', - function () { - if (!self.headerRows && self.layout.hLineWhenBroken !== false) { - self.drawHorizontalLine(rowIndex, writer); - } - }, - function () { - writer.commitUnbreakableBlock(); - } - ); - } - - if (this.headerRepeatable && (rowIndex === (this.rowsWithoutPageBreak - 1) || rowIndex === this.tableNode.table.body.length - 1)) { - this.headerRepeatableHeight = this.headerRepeatable.height; - writer.commitUnbreakableBlock(); - writer.pushToRepeatables(this.headerRepeatable); - this.cleanUpRepeatables = true; - this.headerRepeatable = null; - } - - function getLineXs() { - var result = []; - var cols = 0; - - for (var i = 0, l = self.tableNode.table.body[rowIndex].length; i < l; i++) { - if (!cols) { - result.push({x: self.rowSpanData[i].left, index: i}); - - var item = self.tableNode.table.body[rowIndex][i]; - cols = (item._colSpan || item.colSpan || 0); - } - if (cols > 0) { - cols--; - } - } - - result.push({x: self.rowSpanData[self.rowSpanData.length - 1].left, index: self.rowSpanData.length - 1}); - - return result; - } -}; - -module.exports = TableProcessor; - - -/***/ }), -/* 138 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(Buffer) {// Generated by CoffeeScript 1.12.6 - -/* -PDFDocument - represents an entire PDF document -By Devon Govett - */ - -(function() { - var PDFDocument, PDFObject, PDFPage, PDFReference, fs, stream, - extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, - hasProp = {}.hasOwnProperty; - - stream = __webpack_require__(15); - - fs = __webpack_require__(8); - - PDFObject = __webpack_require__(26); - - PDFReference = __webpack_require__(87); - - PDFPage = __webpack_require__(161); - - PDFDocument = (function(superClass) { - var mixin; - - extend(PDFDocument, superClass); - - function PDFDocument(options1) { - var key, ref1, ref2, val; - this.options = options1 != null ? options1 : {}; - PDFDocument.__super__.constructor.apply(this, arguments); - this.version = 1.3; - this.compress = (ref1 = this.options.compress) != null ? ref1 : true; - this._pageBuffer = []; - this._pageBufferStart = 0; - this._offsets = []; - this._waiting = 0; - this._ended = false; - this._offset = 0; - this._root = this.ref({ - Type: 'Catalog', - Pages: this.ref({ - Type: 'Pages', - Count: 0, - Kids: [] - }) - }); - this.page = null; - this.initColor(); - this.initVector(); - this.initFonts(); - this.initText(); - this.initImages(); - this.info = { - Producer: 'PDFKit', - Creator: 'PDFKit', - CreationDate: new Date() - }; - if (this.options.info) { - ref2 = this.options.info; - for (key in ref2) { - val = ref2[key]; - this.info[key] = val; - } - } - this._write("%PDF-" + this.version); - this._write("%\xFF\xFF\xFF\xFF"); - if (this.options.autoFirstPage !== false) { - this.addPage(); - } - } - - mixin = function(methods) { - var method, name, results; - results = []; - for (name in methods) { - method = methods[name]; - results.push(PDFDocument.prototype[name] = method); - } - return results; - }; - - mixin(__webpack_require__(162)); - - mixin(__webpack_require__(164)); - - mixin(__webpack_require__(166)); - - mixin(__webpack_require__(295)); - - mixin(__webpack_require__(297)); - - mixin(__webpack_require__(302)); - - PDFDocument.prototype.addPage = function(options) { - var pages; - if (options == null) { - options = this.options; - } - if (!this.options.bufferPages) { - this.flushPages(); - } - this.page = new PDFPage(this, options); - this._pageBuffer.push(this.page); - pages = this._root.data.Pages.data; - pages.Kids.push(this.page.dictionary); - pages.Count++; - this.x = this.page.margins.left; - this.y = this.page.margins.top; - this._ctm = [1, 0, 0, 1, 0, 0]; - this.transform(1, 0, 0, -1, 0, this.page.height); - this.emit('pageAdded'); - return this; - }; - - PDFDocument.prototype.bufferedPageRange = function() { - return { - start: this._pageBufferStart, - count: this._pageBuffer.length - }; - }; - - PDFDocument.prototype.switchToPage = function(n) { - var page; - if (!(page = this._pageBuffer[n - this._pageBufferStart])) { - throw new Error("switchToPage(" + n + ") out of bounds, current buffer covers pages " + this._pageBufferStart + " to " + (this._pageBufferStart + this._pageBuffer.length - 1)); - } - return this.page = page; - }; - - PDFDocument.prototype.flushPages = function() { - var i, len, page, pages; - pages = this._pageBuffer; - this._pageBuffer = []; - this._pageBufferStart += pages.length; - for (i = 0, len = pages.length; i < len; i++) { - page = pages[i]; - page.end(); - } - }; - - PDFDocument.prototype.ref = function(data) { - var ref; - ref = new PDFReference(this, this._offsets.length + 1, data); - this._offsets.push(null); - this._waiting++; - return ref; - }; - - PDFDocument.prototype._read = function() {}; - - PDFDocument.prototype._write = function(data) { - if (!Buffer.isBuffer(data)) { - data = new Buffer(data + '\n', 'binary'); - } - this.push(data); - return this._offset += data.length; - }; - - PDFDocument.prototype.addContent = function(data) { - this.page.write(data); - return this; - }; - - PDFDocument.prototype._refEnd = function(ref) { - this._offsets[ref.id - 1] = ref.offset; - if (--this._waiting === 0 && this._ended) { - this._finalize(); - return this._ended = false; - } - }; - - PDFDocument.prototype.write = function(filename, fn) { - var err; - err = new Error('PDFDocument#write is deprecated, and will be removed in a future version of PDFKit. Please pipe the document into a Node stream.'); - console.warn(err.stack); - this.pipe(fs.createWriteStream(filename)); - this.end(); - return this.once('end', fn); - }; - - PDFDocument.prototype.output = function(fn) { - throw new Error('PDFDocument#output is deprecated, and has been removed from PDFKit. Please pipe the document into a Node stream.'); - }; - - PDFDocument.prototype.end = function() { - var font, key, name, ref1, ref2, val; - this.flushPages(); - this._info = this.ref(); - ref1 = this.info; - for (key in ref1) { - val = ref1[key]; - if (typeof val === 'string') { - val = new String(val); - } - this._info.data[key] = val; - } - this._info.end(); - ref2 = this._fontFamilies; - for (name in ref2) { - font = ref2[name]; - font.finalize(); - } - this._root.end(); - this._root.data.Pages.end(); - if (this._waiting === 0) { - return this._finalize(); - } else { - return this._ended = true; - } - }; - - PDFDocument.prototype._finalize = function(fn) { - var i, len, offset, ref1, xRefOffset; - xRefOffset = this._offset; - this._write("xref"); - this._write("0 " + (this._offsets.length + 1)); - this._write("0000000000 65535 f "); - ref1 = this._offsets; - for (i = 0, len = ref1.length; i < len; i++) { - offset = ref1[i]; - offset = ('0000000000' + offset).slice(-10); - this._write(offset + ' 00000 n '); - } - this._write('trailer'); - this._write(PDFObject.convert({ - Size: this._offsets.length + 1, - Root: this._root, - Info: this._info - })); - this._write('startxref'); - this._write("" + xRefOffset); - this._write('%%EOF'); - return this.push(null); - }; - - PDFDocument.prototype.toString = function() { - return "[object PDFDocument]"; - }; - - return PDFDocument; - - })(stream.Readable); - - module.exports = PDFDocument; - -}).call(this); - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1).Buffer)) - -/***/ }), -/* 139 */ -/***/ (function(module, exports) { - -/* (ignored) */ - -/***/ }), -/* 140 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -var Buffer = __webpack_require__(33).Buffer; -var util = __webpack_require__(141); - -function copyBuffer(src, target, offset) { - src.copy(target, offset); -} - -module.exports = function () { - function BufferList() { - _classCallCheck(this, BufferList); - - this.head = null; - this.tail = null; - this.length = 0; - } - - BufferList.prototype.push = function push(v) { - var entry = { data: v, next: null }; - if (this.length > 0) this.tail.next = entry;else this.head = entry; - this.tail = entry; - ++this.length; - }; - - BufferList.prototype.unshift = function unshift(v) { - var entry = { data: v, next: this.head }; - if (this.length === 0) this.tail = entry; - this.head = entry; - ++this.length; - }; - - BufferList.prototype.shift = function shift() { - if (this.length === 0) return; - var ret = this.head.data; - if (this.length === 1) this.head = this.tail = null;else this.head = this.head.next; - --this.length; - return ret; - }; - - BufferList.prototype.clear = function clear() { - this.head = this.tail = null; - this.length = 0; - }; - - BufferList.prototype.join = function join(s) { - if (this.length === 0) return ''; - var p = this.head; - var ret = '' + p.data; - while (p = p.next) { - ret += s + p.data; - }return ret; - }; - - BufferList.prototype.concat = function concat(n) { - if (this.length === 0) return Buffer.alloc(0); - if (this.length === 1) return this.head.data; - var ret = Buffer.allocUnsafe(n >>> 0); - var p = this.head; - var i = 0; - while (p) { - copyBuffer(p.data, ret, i); - i += p.data.length; - p = p.next; - } - return ret; - }; - - return BufferList; -}(); - -if (util && util.inspect && util.inspect.custom) { - module.exports.prototype[util.inspect.custom] = function () { - var obj = util.inspect({ length: this.length }); - return this.constructor.name + ' ' + obj; - }; -} - -/***/ }), -/* 141 */ -/***/ (function(module, exports) { - -/* (ignored) */ - -/***/ }), -/* 142 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(global) {var apply = Function.prototype.apply; - -// DOM APIs, for completeness - -exports.setTimeout = function() { - return new Timeout(apply.call(setTimeout, window, arguments), clearTimeout); -}; -exports.setInterval = function() { - return new Timeout(apply.call(setInterval, window, arguments), clearInterval); -}; -exports.clearTimeout = -exports.clearInterval = function(timeout) { - if (timeout) { - timeout.close(); - } -}; - -function Timeout(id, clearFn) { - this._id = id; - this._clearFn = clearFn; -} -Timeout.prototype.unref = Timeout.prototype.ref = function() {}; -Timeout.prototype.close = function() { - this._clearFn.call(window, this._id); -}; - -// Does not start the time, just sets up the members needed. -exports.enroll = function(item, msecs) { - clearTimeout(item._idleTimeoutId); - item._idleTimeout = msecs; -}; - -exports.unenroll = function(item) { - clearTimeout(item._idleTimeoutId); - item._idleTimeout = -1; -}; - -exports._unrefActive = exports.active = function(item) { - clearTimeout(item._idleTimeoutId); - - var msecs = item._idleTimeout; - if (msecs >= 0) { - item._idleTimeoutId = setTimeout(function onTimeout() { - if (item._onTimeout) - item._onTimeout(); - }, msecs); - } -}; - -// setimmediate attaches itself to the global object -__webpack_require__(143); -// On some exotic environments, it's not clear which object `setimmeidate` was -// able to install onto. Search each possibility in the same order as the -// `setimmediate` library. -exports.setImmediate = (typeof self !== "undefined" && self.setImmediate) || - (typeof global !== "undefined" && global.setImmediate) || - (this && this.setImmediate); -exports.clearImmediate = (typeof self !== "undefined" && self.clearImmediate) || - (typeof global !== "undefined" && global.clearImmediate) || - (this && this.clearImmediate); - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(7))) - -/***/ }), -/* 143 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(global, process) {(function (global, undefined) { - "use strict"; - - if (global.setImmediate) { - return; - } - - var nextHandle = 1; // Spec says greater than zero - var tasksByHandle = {}; - var currentlyRunningATask = false; - var doc = global.document; - var registerImmediate; - - function setImmediate(callback) { - // Callback can either be a function or a string - if (typeof callback !== "function") { - callback = new Function("" + callback); - } - // Copy function arguments - var args = new Array(arguments.length - 1); - for (var i = 0; i < args.length; i++) { - args[i] = arguments[i + 1]; - } - // Store and register the task - var task = { callback: callback, args: args }; - tasksByHandle[nextHandle] = task; - registerImmediate(nextHandle); - return nextHandle++; - } - - function clearImmediate(handle) { - delete tasksByHandle[handle]; - } - - function run(task) { - var callback = task.callback; - var args = task.args; - switch (args.length) { - case 0: - callback(); - break; - case 1: - callback(args[0]); - break; - case 2: - callback(args[0], args[1]); - break; - case 3: - callback(args[0], args[1], args[2]); - break; - default: - callback.apply(undefined, args); - break; - } - } - - function runIfPresent(handle) { - // From the spec: "Wait until any invocations of this algorithm started before this one have completed." - // So if we're currently running a task, we'll need to delay this invocation. - if (currentlyRunningATask) { - // Delay by doing a setTimeout. setImmediate was tried instead, but in Firefox 7 it generated a - // "too much recursion" error. - setTimeout(runIfPresent, 0, handle); - } else { - var task = tasksByHandle[handle]; - if (task) { - currentlyRunningATask = true; - try { - run(task); - } finally { - clearImmediate(handle); - currentlyRunningATask = false; - } - } - } - } - - function installNextTickImplementation() { - registerImmediate = function(handle) { - process.nextTick(function () { runIfPresent(handle); }); - }; - } - - function canUsePostMessage() { - // The test against `importScripts` prevents this implementation from being installed inside a web worker, - // where `global.postMessage` means something completely different and can't be used for this purpose. - if (global.postMessage && !global.importScripts) { - var postMessageIsAsynchronous = true; - var oldOnMessage = global.onmessage; - global.onmessage = function() { - postMessageIsAsynchronous = false; - }; - global.postMessage("", "*"); - global.onmessage = oldOnMessage; - return postMessageIsAsynchronous; - } - } - - function installPostMessageImplementation() { - // Installs an event handler on `global` for the `message` event: see - // * https://developer.mozilla.org/en/DOM/window.postMessage - // * http://www.whatwg.org/specs/web-apps/current-work/multipage/comms.html#crossDocumentMessages - - var messagePrefix = "setImmediate$" + Math.random() + "$"; - var onGlobalMessage = function(event) { - if (event.source === global && - typeof event.data === "string" && - event.data.indexOf(messagePrefix) === 0) { - runIfPresent(+event.data.slice(messagePrefix.length)); - } - }; - - if (global.addEventListener) { - global.addEventListener("message", onGlobalMessage, false); - } else { - global.attachEvent("onmessage", onGlobalMessage); - } - - registerImmediate = function(handle) { - global.postMessage(messagePrefix + handle, "*"); - }; - } - - function installMessageChannelImplementation() { - var channel = new MessageChannel(); - channel.port1.onmessage = function(event) { - var handle = event.data; - runIfPresent(handle); - }; - - registerImmediate = function(handle) { - channel.port2.postMessage(handle); - }; - } - - function installReadyStateChangeImplementation() { - var html = doc.documentElement; - registerImmediate = function(handle) { - // Create a - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

16.2 Authentication

-

Authentication to the PEcAn API occurs via Basic HTTP Auth. The credentials for using the API are the same as those used to log into PEcAn & BetyDB. Here is how you use basic HTTP auth with curl:

-
$ curl --user '<username>:<password>' <api-endpoint>
-

Authentication also depends on the PEcAn server that the user interacts with. Some servers, at the time of deployment have the AUTH_REQ = FALSE, meaning that such servers do not require user autertication for the usage of the PEcAn APIs. Regardless of the type of server, the endpoints defind under General section can be accessed without any authentication.

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/automation.html b/master/automation.html deleted file mode 100644 index 836c37a88..000000000 --- a/master/automation.html +++ /dev/null @@ -1,879 +0,0 @@ - - - - - - - 17.5 Automation | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

17.5 Automation

-

Below is an example of a script to synchronize PEcAn database instances across the network.

-

db.sync.sh

-
#!/bin/bash 
-## make sure psql is in PATH
-export PATH=/usr/pgsql-9.3/bin/:$PATH 
-## move to export directory
-cd /fs/data3/sync 
-## Dump Data
-MYSITE=1 /home/dietze/pecan/scripts/dump.bety.sh 
-## Load Data from other sites
-MYSITE=1 REMOTESITE=2 /home/dietze/pecan/scripts/load.bety.sh 
-MYSITE=1 REMOTESITE=5 /home/dietze/pecan/scripts/load.bety.sh 
-MYSITE=1 REMOTESITE=0 /home/dietze/pecan/scripts/load.bety.sh 
-## Timestamp sync log
-echo $(date +%c) >> /home/dietze/db.sync.log
-

Typically such a script is set up to run as a cron job. Make sure to schedule this job (crontab -e) as the user that has database privileges (typically postgres). The example below is a cron table that runs the sync every hour at 12 min after the hour.

-
MAILTO=user@yourUniversity.edu
-12 * * * * /home/dietze/db.sync.sh
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/aws-setup.html b/master/aws-setup.html deleted file mode 100644 index 8113628be..000000000 --- a/master/aws-setup.html +++ /dev/null @@ -1,931 +0,0 @@ - - - - - - - 24.2 AWS Setup | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

24.2 AWS Setup

-

***********Mirror of earlier section in installation section?*********************

-

The following are Mike’s rough notes from a first attempt to port the PEcAn VM to the AWS. This was done on a Mac

-

These notes are based on following the instructions here

-
-

24.2.1 Convert PEcAn VM

-

AWS allows upload of files as VMDK but the default PEcAn VM is in OVA format

-
    -
  1. If you haven’t done so already, download the PEcAn VM

  2. -
  3. Split the OVA file into OVF and VMDK files

  4. -
-
tar xf <ovafile>
-
-
-

24.2.2 Set up an account on AWS

-

After you have an account you need to set up a user and save your access key and secret key

-

In my case I created a user named ‘carya’

-

Note: the key that ended up working had to be made at https://console.aws.amazon.com/iam/home#security_credential, not the link above.

-
-
-

24.2.3 Install EC2 command line tools

-
wget http://s3.amazonaws.com/ec2-downloads/ec2-api-tools.zip
-
-sudo mkdir /usr/local/ec2
-
-sudo unzip ec2-api-tools.zip -d /usr/local/ec2
-

If need be, download and install JDK

-
export JAVA_HOME=$(/usr/libexec/java_home)
-
-export EC2_HOME=/usr/local/ec2/ec2-api-tools-<version>
-
-export PATH=$PATH:$EC2_HOME/bin
-

Then set your user credentials as environment variables:

-

export AWS_ACCESS_KEY=xxxxxxxxxxxxxx

-

export AWS_SECRET_KEY=xxxxxxxxxxxxxxxxxxxxxx

-

Note: you may want to add all the variables set in the above EXPORT commands above into your .bashrc or equivalent.

-
-
-

24.2.4 Create an AWS S3 ‘bucket’ to upload VM to

-

Go to https://console.aws.amazon.com/s3 and click “Create Bucket”

-

In my case I named the bucket ‘pecan’

-
-
-

24.2.5 Upload

-

In the code below, make sure to change the PEcAn version, the name of the bucket, and the name of the region. Make sure that the PEcAn version matches the one you downloaded.

-

Also, you may want to choose a considerably larger instance type. The one chosen below is that corresponding to the AWS Free Tier

-
ec2-import-instance PEcAn_1.2.6-disk1.vmdk --instance-type t2.micro --format VMDK --architecture x86_64 --platform Linux --bucket pecan --region us-east-1 --owner-akid $AWS_ACCESS_KEY --owner-sak $AWS_SECRET_KEY
-

Make sure to note the ID of the image since you’ll need it to check the VM status. Once the image is uploaded it will take a while (typically about an hour) for Amazon to convert the image to one it can run. You can check on this progress by running

-
ec2-describe-conversion-tasks <image.ID>
-
-
-

24.2.6 Configuring the VM

-

On the EC2 management webpage, https://console.aws.amazon.com/ec2, if you select Instances on the left hand side (LHS) you should be able to see your new PEcAn image as an option under Launch Instance.

-

Before launching, you will want to update the firewall to open up additional ports that PEcAn needs – specifically port 80 for the webpage. Port 22 (ssh/sftp) should be open by default. Under “Security Groups” select “Inbound” then “Edit” and then add “HTTP”.

-

Select “Elastic IPs” on the LHS, and “Allocate New Address” in order to create a public IP for your VM.

-

Next, select “Network Interfaces” on the LHS and then under Actions select “Associate Addresses” then choose the Elastic IP you just created.

-

See also http://docs.aws.amazon.com/AmazonVPC/latest/GettingStartedGuide/GetStarted.html

-
-
-

24.2.7 Set up multiple instances (optional)

-

For info on setting up multiple instances with load balancing see: http://docs.aws.amazon.com/ElasticLoadBalancing/latest/DeveloperGuide/gs-ec2VPC.html

-

Select “Load Balancers” on the LHS, click on “Create Load Balancer”, follow Wizard keeping defaults.

-

To be able to launch multiple VMs: Under “Instances” convert VM to an Image. When done, select Launch, enable multiple instances, and associate with the previous security group. Once running, go back to “Load Balancers” and add the instances to the load balancer. Each instance can be accessed individually by it’s own public IP, but external users should access the system more generally via the Load Balancers DNS.

-
-
-

24.2.8 Booting the VM

-

Return to “Instances” using the menu on the LHS.

-

To boot the VM select “Actions” then “Instance State” then “Start”. In the future, once you have the VM loaded and configured this last step is the only one you will need to repeat to turn your VM on and off.

-

The menu provided should specify the Public IP where the VM has launched

- -
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/backup-of-bety-database.html b/master/backup-of-bety-database.html deleted file mode 100644 index 65118b097..000000000 --- a/master/backup-of-bety-database.html +++ /dev/null @@ -1,870 +0,0 @@ - - - - - - - 22.2 Backup of BETY database | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

22.2 Backup of BETY database

-

It is good practice to make sure you backup the BETY database. Just creating a copy of the files on disk is not enough to ensure you have a valid backup. Most likely if you do this you will end up with a corrupted backup of the database.

-

To backup the database you can use the pg_dump command, which will make sure the database id backed up in a consistent state. You can run sudo -u postgres pg_dump -d bety -Z 9 -f bety.sql.gz, this will create a compressed file that can be used to resotore the database.

-

In the PEcAn distribution in scripts folder there is a script called backup.bety.sh. This script will create the backup of the database. It will create multiple backups allowing you to restore the database from one of these copies. The database will be backed up to one of the following files: -- bety-d-X, daily backup, where X is the day of the month. -- bety-w-X, weekly backup, where X is the week number in the year -- bety-m-X, montly backup, where X is the month of the year -- bety-y-X, yearly backup, where X is the actual year. -Using this scheme, we can restore the database using any of the files generated.

-

It is recommeneded to run this script using a cronjob at midnight such that you have a daily backup of the database and do not have to remember to create these backups. When running this script (either cron or by hand) make sure to place the backups on a different machine than the machine that holds the database in case of a larger system failure.

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/basic-remote-execute-functions.html b/master/basic-remote-execute-functions.html deleted file mode 100644 index dcc599fcf..000000000 --- a/master/basic-remote-execute-functions.html +++ /dev/null @@ -1,874 +0,0 @@ - - - - - - - 26.5 Basic remote execute functions | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

26.5 Basic remote execute functions

-

The PEcAn.remote::remote.execute.cmd function runs a system command on a remote server (or on the local server, if host$name == "localhost").

-
x <- PEcAn.remote::remote.execute.cmd(host = my_host, cmd = "echo", args = "Hello world")
-x
-

Note that remote.execute.cmd is similar to base R’s system2, in that the base command (in this case, echo) is passed separately from its arguments ("Hello world"). -Note also that the output of the remote command is returned as a character.

-

For R code, there is a special wrapper around remote.execute.cmdPEcAn.remote::remote.execute.R, which runs R code (passed as a string) on a remote and returns the output.

-
code <- "
-    x <- 2:4
-    y <- 3:1
-    x ^ y
-"
-out <- PEcAn.remote::remote.execute.R(code = code, host = my_host)
-

For additional functions related to remote file operations and other stuff, see the PEcAn.remote package documentation.

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/basic-use-of-the-testthat-package.html b/master/basic-use-of-the-testthat-package.html deleted file mode 100644 index 2abfc02da..000000000 --- a/master/basic-use-of-the-testthat-package.html +++ /dev/null @@ -1,885 +0,0 @@ - - - - - - - 32.2 Basic use of the testthat package | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

32.2 Basic use of the testthat package

-

Create a file called <packagename>/tests/testthat.R with the following contents:

-
library(testthat)
-library(mypackage)
-
-test_check("mypackage")
-

Tests should be placed in <packagename>/tests/testthat/test-<sourcefilename>.R, and look like the following:

-
test_that("mathematical operators plus and minus work as expected",{
-  expect_equal(sum(1,1), 2)
-  expect_equal(sum(-1,-1), -2)
-  expect_equal(sum(1,NA), NA)
-  expect_error(sum("cat"))
-  set.seed(0)
-  expect_equal(sum(matrix(1:100)), sum(data.frame(1:100)))
-})
-
-test_that("different testing functions work, giving excuse to demonstrate",{
-  expect_identical(1, 1)
-  expect_identical(numeric(1), integer(1))
-  expect_equivalent(numeric(1), integer(1))
-  expect_warning(mean('1'))
-  expect_that(mean('1'), gives_warning("argument is not numeric or logical: returning NA"))
-  expect_warning(mean('1'), "argument is not numeric or logical: returning NA")
-  expect_message(message("a"), "a")
-})
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/basic-web-workflow.html b/master/basic-web-workflow.html deleted file mode 100644 index 2c0a92523..000000000 --- a/master/basic-web-workflow.html +++ /dev/null @@ -1,870 +0,0 @@ - - - - - - - 6 Basic Web workflow | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

6 Basic Web workflow

-

This chapter describes the major steps of the PEcAn web-based workflow, which are as follows:

- -

We recommend that all new users begin with [PEcAn Hands-On Demo 01: Basic Run]. The documentation below assumes you are already familiar with how to navigate to PEcAn’s interactive web interface for running models.

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/basics-of-ssh.html b/master/basics-of-ssh.html deleted file mode 100644 index bea2c9c5a..000000000 --- a/master/basics-of-ssh.html +++ /dev/null @@ -1,873 +0,0 @@ - - - - - - - 26.1 Basics of SSH | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

26.1 Basics of SSH

-

All of the PEcAn remote infrastructure depends on the system ssh utility, so it’s important to make sure this works before attempting the advanced remote execution functionality in PEcAn.

-

To connect to a remote server interactively, the command is simply:

-
ssh <username>@<hostname>
-

For instance, my connection to the BU shared computing cluster looks like:

-
ssh ashiklom@geo.bu.edu
-

It will prompt me for my BU password, and, if successful, will drop me into a login shell on the remote machine.

-

Alternatively to the login shell, ssh can be used to execute arbitrary code, whose output will be returned exactly as it would if you ran the command locally. -For example, the following:

-
ssh ashiklom@geo.bu.edu pwd
-

will run the pwd command, and return the path to my home directory on the BU SCC. -The more advanced example below will run some simple R code on the BU SCC and return the output as if it was run locally.

-
ssh ashiklom@geo.bu.edu Rscript -e "seq(1, 10)"
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/big-picture-whats-possible-to-do.html b/master/big-picture-whats-possible-to-do.html deleted file mode 100644 index 1f4845eb9..000000000 --- a/master/big-picture-whats-possible-to-do.html +++ /dev/null @@ -1,869 +0,0 @@ - - - - - - - 31.2 Big Picture: What’s possible to do | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

31.2 Big Picture: What’s possible to do

-

To make one PEcAn package use functionality from another R package (including other PEcAn packages), you must do at least one and up to four things in your own package.

-
    -
  • Always, declare which packages your package depends on, so that R can install them as needed when someone installs your package and so that human readers can understand what additional functionality it uses. Declare dependencies by manually adding them to your package’s DESCRIPTION file.
  • -
  • Sometimes, import functions from the dependency package into your package’s namespace, so that your functions know where to find them. This is only sometimes necessary, because you can usually use :: to call functions without importing them. Import functions by writing Roxygen @importFrom statements and do not edit the NAMESPACE file by hand.
  • -
  • Rarely, load dependency code into the R environment, so that the person using your package can use it without loading it separately. This is usually a bad idea, has caused many subtle bugs, and in PEcAn it should only be used when unavoidable. When unavoidable, prefer requireNamespace(... quietly = TRUE) over Depends: or require() or library().
  • -
  • Only if your dependency relies on non-R tools, install any components that R won’t know how to find for itself. These components are often but not always identifiable from a SystemRequirements field in the dependency’s DESCRIPTION file. The exact installation procedure will vary case by case and from one operating system to another, and for PEcAn the key point is that you should skip this step until it proves necessary. When it does prove necessary, edit the documentation for your package to include advice on installing the dependency components, then edit the PEcAn build and testing scripts as needed so that they follow your advice.
  • -
-

The advice below about each step is written specifically for PEcAn, although much of it holds for R packages in general. For more details about working with dependencies, start with Hadley Wickham’s R packages and treat the CRAN team’s Writing R Extensions as the final authority.

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/bookediting.html b/master/bookediting.html deleted file mode 100644 index eba6888f5..000000000 --- a/master/bookediting.html +++ /dev/null @@ -1,909 +0,0 @@ - - - - - - - 3.2 Editing this book | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

3.2 Editing this book

-

The file organization of this documentation can be described simply as follows:

-
    -
  • Each chapter is in its own file (within the corresponding section).
  • -
  • Each group of chapters (i.e. “part” in LaTeX) is in its own directory.
  • -
-

Sections and chapters are rendered (and numbered) in alpha-numerical order of their corresponding file names. -Therefore, each section directory and chapter file name should be prefixed with a two-digit (zero-padded) number. -File and directory names should be as similar as possible to the name of the corresponding chapter or section. -For instance, the file name for this chapter’s source file is 06_reference/10_editing_this_book.Rmd. -This numbering means that if you need to create an additional chapter before an existing one, you will have to renumber all chapters following it.

-

To ensure correct rendering, you should also make sure that each chapter starts with a level 1 heading (# heading). -For instance, this chapter’s source starts with:

-
# Editing this book {#bookediting}
-
-The file organization of this documentation can be described simply as follows:
-...
-

Furthermore, to keep the organization consistent, each chapter should have exactly one level 1 heading (i.e. do not combine multiple chapters into a single file). -In other words, do not spread a single chapter across multiple files, and do not put multiple chapters in the same file.

-

Each section directory has a file starting with 00 that contains only the section (or “Part”) title. -This is used to create the greyed-out section headers in the rendered HTML. -For instance, this section has a file called 00_introduction.Rmd which contains only the following:

-
# (PART) Introduction {-}
-

To cross-reference a different section, use that section’s unique tag (starts with #; appears next to the section heading surrounded in curly braces). -For instance, the following Markdown contains two sections that cross-reference each other:

-
## Introduction {#intro}
-
-Here is the intro. This is a link to the [next section](#section-one).
-
-## First section. {#section-one}
-
-As mentioned in the [previous section](#intro).
-

If no header tag exists for a section you want to cross-reference, you should create one. -We have no strict rules about this, but it’s useful to have tags that give some sense of their parent hierarchy and reference their parent sections (e.g. #models, #models-ed, and #models-ed-xml to refer to a chapter on models, with a subsection on ED and a sub-subsection on ED XML configuration). -If section organization changes, it is fine to move header tags, but avoid altering existing tags as this will break all the links pointing to that tag. -(Note that it is also possible to link to section headings by their exact title. However, this is not recommended because these section titles could change, which would break the links.)

-

When referring to PEcAn packages or specific functions, it is a good idea to link to the rendered package documentation. -For instance, here are links to the models/ed package, the PEcAn.ED2::modify_ed2in function, and the PEcAnRTM package vignette. -If necessary, you can also link directly to specific lines or blocks in the source code on GitHub, like this. -(To get a link to a line, click its line number. To then select a block, shift-click another line number.)

-

To insert figures, use knitr::include_graphics("path/to/figure.png") inside an R code chunk. -For example:

-
```{r}
-knitr::include_graphics("04_advanced_user_guide/images/Input_ID_name.png")
-```
-

Note that image file names are relative to the book_source directory, NOT to the markdown file. -In other words, if myimage.png was in the same directory as this file, I would still have to reference it as 06_reference/myimage.png – I could not just do myimage.png. -The size, caption, and other properties of the rendered image can be controlled via chunk options.

-

For additional information about how bookdown works (including information about its syntax), see the Bookdown free online book.

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/checking-log-files.html b/master/checking-log-files.html deleted file mode 100644 index 72aa1b5b0..000000000 --- a/master/checking-log-files.html +++ /dev/null @@ -1,868 +0,0 @@ - - - - - - - 19.3 Checking Log Files | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

19.3 Checking Log Files

-

To create Log files on the VM, execute the following:

-
sudo -s
-echo "preserve_logs true;" >> /etc/shiny-server/shiny-server.conf
-service shiny-server restart
-

Then within the directory /var/log/shiny-server you will see log files for your specific shiny apps.

- -
- -
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/cm3.html b/master/cm3.html deleted file mode 100644 index 15f059b7b..000000000 --- a/master/cm3.html +++ /dev/null @@ -1,862 +0,0 @@ - - - - - - - 15.16 CM3 | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

15.16 CM3

-

GFDL’s CMIP5 experiments with CM3 included many of the integrations found in the long-term CMIP5 experimental design. The focus of this physical climate model is on the role of aerosols, aerosol-cloud interactions, and atmospheric chemistry in climate variability and climate change.

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/cmip5.html b/master/cmip5.html deleted file mode 100644 index 87b1fc5e2..000000000 --- a/master/cmip5.html +++ /dev/null @@ -1,865 +0,0 @@ - - - - - - - 15.6 CMIP5 | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

15.6 CMIP5

-

Scale: varies by model

-

Resolution: 3 hr

-

Availability: 2006-2100

-

Currently only GFDL available. Different scenerios and ensemble members can be set via Advanced Edit.

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/coding-practices.html b/master/coding-practices.html deleted file mode 100644 index 3ca4bf63e..000000000 --- a/master/coding-practices.html +++ /dev/null @@ -1,900 +0,0 @@ - - - - - - - 8.3 Coding Practices | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

8.3 Coding Practices

- -
-

8.3.1 Coding Style

-

Consistent coding style improves readability and reduces errors in -shared code.

-

Unless otherwise noted, PEcAn follows the Tidyverse style guide, so please familiarize yourself with it before contributing. -In addition, note the following:

-
    -
  • Document all functions using roxygen2. -See Roxygen2 for more details.
  • -
  • Put your name on things. -Any function that you create or make a meaningful contribution to should have your name listed after the author tag in the function documentation. -It is also often a good idea to add your name to extended comments describing particularly complex or strange code.
  • -
  • Write unit tests with testthat. -Tests are a complement to documentation - they define what a function is (and is not) expected to do. -Not all functions necessarily need unit tests, but the more tests we have, the more confident we can be that changes don’t break existing code. -Whenever you discover and fix a bug, it is a good idea to write a unit test that makes sure the same bug won’t happen again. -See Unit_Testing for instructions, and Advanced R: Tests.
  • -
  • Do not use abbreviations. -Always write out TRUE and FALSE (i.e. do not use T or F). -Do not rely on partial argument matching – write out all arguments in full.
  • -
  • Avoid dots in function names. -R’s S3 methods system uses dots to denote object methods (e.g. print.matrix is the print method for objects of class matrix), which can cause confusion. -Use underscores instead (e.g. do_analysis instead of do.analysis). -(NOTE that many old PEcAn functions violate this convention. The plan is to deprecate those in PEcAn 2.0. See GitHub issue #392).
  • -
  • Use informative file names with consistent extensions. -Standard file extensions are .R for R scripts, .rds for individual objects (via saveRDS function), and .RData (note: capital D!) for multiple objects (via the save function). -For function source code, prefer multiple files with fewer functions in each to large files with lots of files (though it may be a good idea to group closely related functions in a single file). -File names should match, or at least closely reflect, their files (e.g. function do_analysis should be defined in a file called do_analysis.R). -Do not use spaces in file names – use dashes (-) or underscores (_).
  • -
  • For using external packages, add the package to Imports: and call the corresponding function with package::function. -Do not use @importFrom package function or, worse yet, @import package. -(The exception is infix operators like magrittr::%>% or ggplot2::%+%, which can be imported via roxygen2 documentation like @importFrom magrittr %>%). -Do not add packages to Depends. -In general, try to avoid adding new dependencies (especially ones that depend on system libraries) unless they are necessary or already widely used in PEcAn (e.g. GDAL, NetCDF, XML, JAGS, dplyr). -For a more thorough and nuanced discussion, see the package dependencies appendix.
  • -
-
-
- -
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/configuration-for-pecan-web-interface.html b/master/configuration-for-pecan-web-interface.html deleted file mode 100644 index 74ff1a5d5..000000000 --- a/master/configuration-for-pecan-web-interface.html +++ /dev/null @@ -1,896 +0,0 @@ - - - - - - - 26.8 Configuration for PEcAn web interface | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

26.8 Configuration for PEcAn web interface

-

The config.php has a few variables that will control where the web -interface can run jobs, and how to run those jobs. It is located in the /web directory and if you have not touched it yet it will -be named as config.example.php. Rename it to ’config.php` and edit by folowing the following directions.

-

These variables are $hostlist, $qsublist, $qsuboptions, and $SSHtunnel. In -the near future $hostlist, $qsublist, $qsuboptions will be -combined into a single list.

-

$SSHtunnel : points to the script that creates an SSH tunnel. -The script is located in the web folder and the default value of -dirname(__FILE__) . DIRECTORY_SEPARATOR . "sshtunnel.sh"; most -likely will work.

-

$hostlist : is an array with by default a single value, only -allowing jobs to run on the local server. Adding any other servers -to this list will show them in the pull down menu when selecting -machines, and will trigger the web page to be show to ask for a -username and password for the remote execution (make sure to use -HTTPS setup when asking for password to prevent it from being send -in the clear).

-

$qsublist : is an array of hosts that require qsub to be used -when running the models. This list can include $fqdn to indicate -that jobs on the local machine should use qsub to run the models.

-

$qsuboptions : is an array that lists options for each machine. -Currently it support the following options (see also -[Run Setup] and look at the tags)

-
array("geo.bu.edu" =>
-    array("qsub"   => "qsub -V -N @NAME@ -o @STDOUT@ -e @STDERR@ -S /bin/bash",
-          "jobid"  => "Your job ([0-9]+) .*",
-          "qstat"  => "qstat -j @JOBID@ || echo DONE",
-          "job.sh" => "module load udunits R/R-3.0.0_gnu-4.4.6",
-          "models" => array("ED2"    => "module load hdf5"))
-

In this list qsub is the actual command line for qsub, jobid -is the text returned from qsub, qstat is the command to check -to see if the job is finished. job.sh and the value in models -are additional entries to add to the job.sh file generated to -run the model. This can be used to make sure modules are loaded -on the HPC cluster before running the actual model.

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/contributor-covenant-code-of-conduct.html b/master/contributor-covenant-code-of-conduct.html deleted file mode 100644 index 84cfd87fd..000000000 --- a/master/contributor-covenant-code-of-conduct.html +++ /dev/null @@ -1,891 +0,0 @@ - - - - - - - 2 Contributor Covenant Code of Conduct | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

2 Contributor Covenant Code of Conduct

-

Our Pledge

-

In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.

-

Our Standards

-

Examples of behavior that contributes to creating a positive environment include:

-
    -
  • Using welcoming and inclusive language
  • -
  • Being respectful of differing viewpoints and experiences
  • -
  • Gracefully accepting constructive criticism
  • -
  • Focusing on what is best for the community
  • -
  • Showing empathy towards other community members
  • -
-

Examples of unacceptable behavior by participants include:

-
    -
  • The use of sexualized language or imagery and unwelcome sexual attention or advances
  • -
  • Trolling, insulting/derogatory comments, and personal or political attacks
  • -
  • Public or private harassment
  • -
  • Publishing others’ private information, such as a physical or electronic address, without explicit permission
  • -
  • Other conduct which could reasonably be considered inappropriate in a professional setting
  • -
-

Our Responsibilities

-

Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.

-

Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.

-

Scope

-

This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.

-

Enforcement

-

Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at pecanproj[at]gmail.com. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.

-

Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project’s leadership.

-

Attribution

-

This Code of Conduct is adapted from the Contributor Covenant version 1.4, available at http://contributor-covenant.org/version/1/4.

- -
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/cookies-and-pecan-web-pages.html b/master/cookies-and-pecan-web-pages.html deleted file mode 100644 index a6d186845..000000000 --- a/master/cookies-and-pecan-web-pages.html +++ /dev/null @@ -1,862 +0,0 @@ - - - - - - - 21.1 Cookies and pecan web pages | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

21.1 Cookies and pecan web pages

-

You may need to disable cookies specifically for the pecan webserver in your browser. This shouldn’t be a problem running from the virtual machine, but your installation of php can include a ‘PHPSESSID’ that is quite long, and this can overflow the params field of the workflows table, depending on how long your hostname, model name, site name, etc are.

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/cruncep.html b/master/cruncep.html deleted file mode 100644 index 93c7660f4..000000000 --- a/master/cruncep.html +++ /dev/null @@ -1,864 +0,0 @@ - - - - - - - 15.5 CRUNCEP | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

15.5 CRUNCEP

-

Scale: global

-

Resolution: 6hr, 0.5 degree

-

Availability: 1901-2010

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/data-assimilation-with-dart.html b/master/data-assimilation-with-dart.html deleted file mode 100644 index a47b285c7..000000000 --- a/master/data-assimilation-with-dart.html +++ /dev/null @@ -1,939 +0,0 @@ - - - - - - - 27 Data assimilation with DART | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

27 Data assimilation with DART

-

In addition to the state assimilation routines found in the assim.sequential module, another approach for state data assimilation in PEcAn is through the DART workflow created by the DARES group in NCAR.

-

This section gives a straight-forward explanation how to implement DART, focused on the technical aspects of the implementation. If there are any questions, feel free to send @Viskari an email (tt.viskari@gmail.com) or contacting DART support as they are quite awesome in helping people with problems. Also, if there are any suggestions on how to improve the wiki, please let me know.

-

Running with current folders in PEcAn

-

Currently the DART folders in PEcAn are that you can simply copy the structure there over a downloaded DART workflow and it should replace/add relevant files and folders. The most important step after that is to check and change the run paths in the following files: -Path_name files in the work folders -T_ED2IN file, as it indicates where the run results be written. -advance_model.csh, as it indicates where to copy files from/to.

-

Second thing is setting the state vector size. This is explained in more detail below, but essentially this is governed by the variable model_size in model_mod.f90. In addition to this, it should be changed in utils/F2R.f90 and R2F.f90 programs, which are responsible for reading and writing state variable information for the different ensembles. This also will be expanded below. Finally, the new state vector size should be updated for any other executable that runs it.

-

Third thing needed are the initial condition and observation sequence files. They will always follow the same format and are explained in more detail below.

-

Finally the ensemble size, which is the easiest to change. In the work subfolder, there is a file named input.nml. Simply changing the ensemble size there will set it for the run itself. Also remember that initial conditions file should have the equal amount of state vectors as there are ensemble members.

-

Adjusting the workflow

-

The central file for the actual workflow is advance_model.csh. It is a script DART calls to determine how the state vector changes between the two observation times and is essentially the only file one needs to change when changing state models or observations operators. The file itself should be commented to give a good idea of the flow, but beneath is a crude order of events. -1. Create a temporary folder to run the model in and copy/link required files in to it. -2. Read in the state vector values and times from DART. Here it is important to note that the values will be in binary format, which need to be read in by a Fortran program. In my system, there is a program called F2R which reads in the binary values and writes out in ascii form the state vector values as well as which ED2 history files it needs to copy based on the time stamps. -3. Run the observation operator, which writes the state vector state in to the history files and adjusts them if necessary. -4. Run the program. -5. Read the new state vector values from output files. -6. Convert the state vector values to the binary. In my system, this is done by the program R2F.

-

Initial conditions file

-

The initial conditions file, commonly named filter_ics although you can set it to something else in input.nml, is relatively simple in structure. It has one sequence repeating over the number of ensemble members. -First line contains two times: Seconds and days. Just use one of them in this situation, but it has to match the starting time given in input.nml. -After that each line should contain a value from the state vector in the order you want to treat them. -R functions filter_ics.R and B_filter_ics.R in the R folder give good examples of how to create these.

-

Observations files

-

The file which contains the observations is commonly known as obs_seq.out, although again the name of the file can be changed in input.nml. The structure of the file is relatively straight-forward and the R function ObsSeq.R in the R subfolder has the write structure for this. Instead of writing it out here, I want to focus on a few really important details in this file. -Each observations will have a time, a value, an uncertainty, a location and a kind. The first four are self-explanatory, but the kind is really important, but also unfortunately really easy to misunderstand. In this file, the kind does not refer to a unit or a type of observation, but which member of the state vector is this observation of. So if the kind was, for example, 5, it would mean that it was of the fifth member of the state vector. However, if the kind value is positive, the system assumes that there is some sort of an operator change in comparing the observation and state vector value which is specified in a subprogram in model_mod.f90.

-

So for an direct identity comparison between the observation and the state vector value, the kind needs to be negative number of the state vector component. Thus, again if the observation is of the fifth state vector value, the kind should be set as -5. Thus it is recommendable that the state vector values have already been altered to be comparable with the observations.

-

As for location, there are many ways to set in DART and the method needs to be chosen when compiling the code by giving the program which of the location mods it is to use. In our examples we used a 1-dimensional location vector with scaled values between 0 and 1. For future it makes sense to switch to a 2 dimensional long- and lat-scale, but for the time being the location does not impact the system a lot. The main impact will be if the covariances will be localized, as that will be decided on their locations.

-

State variable vector in DART

-

Creating/adjusting a state variable vector in DART is relatively straight-forward. Below are listed the steps to specify a state variable vector in DART.

-

I. For each specific model, there should be an own folder within the DART root models folder. In this folder there is a model_mod.f90, which contains the model specific subroutines necessary for a DART run.

-

At the beginning of this file there should be the following line:

-

integer, parameter :: model_size = [number]

-

The number here should be the number of variables in the vector. So for example if there were three state variables, then the line should look like this:

-

integer, parameter :: model_size = 3

-

This number should also be changed to match with any of the other executables called during the run as indicated by the list above.

-
    -
  1. In the DART root, there should be a folder named obs_kind, which contains a file called DEFAULT_obs_kind_mod.F90. It is important to note that all changes should be done to this file instead of obs_kind_mod.f90, as during compilation DART creates obs_kind_mod.f90 from DEFAULT_obs_kind_mod.F90. -This program file contains all the defined observation types used by DART and numbers them for easier reference later. Different types are classified according to observation instrument or relevant observation phenomenon. Adding a new type only requires finding an unused number and starting a new identifying line with the following:
  2. -
-

integer, parameter, public :: & -KIND_…

-

Note that the observation kind should always be easy to understand, so avoid using unnecessary acronyms. For example, when adding an observation type for Leaf Area Index, it would look like below:

-

integer, parameter, public :: & -KIND_LEAF_AREA_INDEX = [number]

-
    -
  1. In the DART root, there should be a folder named obs_def, which contains several files starting with obs_def_. There files contain the different available observation kinds classified either according to observation instrument or observable system. Each file starts with the line
  2. -
-

! BEGIN DART PREPROCESS KIND LIST

-

And end with line

-

! END DART PREPROCESS KIND LIST

-

The lines between these two should contain

-

! The desired observation reference, the observation type, COMMON_CODE.

-

For example, for observations relating to phenology, I have created a file called obs_def_phen_mod.f90. In this file I define the Leaf Area Index observations in the following way.

-

! BEGIN DART PREPROCESS KIND LIST -! LAI, TYPE_LEAF_AREA_INDEX, COMMON_CODE -! END DART PREPROCESS KIND LIST

-

Note that the exclamation marks are necessary for the file.

-
    -
  1. In the model specific folder, in the work subfolder there is a namelist file input.nml. This contains all the run specific information for DART. In it, there is a subtitle &preprocess, under which there is a line
  2. -
-

input_files = ‘….’

-

This input_files sections must be set to refer to the obs_def file created in step III. The input files can contain references to multiple obs_def files if necessary.

-

As an example, the reference to the obs_def_phen_mod.f90 would look like -input_files = ‘../../../obs_def/obs_def_phen_mod.f90’

-

V. Finally, as an optional step, the different values in state vector can be typed. In model_mod, referred to in step I, there is a subroutine get_state_meta_data. In it, there is an input variable index_in, which refers to the vector component. So for instance for the second component of the vector index_in would be 2. If this is done, the variable kind has to be also included at the beginning of the model_mod.f90 file, at the section which begins

-

use obs_kind_mod, only ::

-

The location of the variable can be set, but for a 0-dimensional model we are discussing here, this is not necessary.

-

Here, though, it is possible to set the variable types by including the following line

-

if(index_in .eq. [number]) var_type = [One of the variable kinds set in step II]

-
    -
  1. If the length of the state vector is changed, it is important that the script ran with DART produces a vector of that length. Change appropriately if necessary.
  2. -
-

After these steps, DART should be able to run with the state vector of interest.

- -
- - - -
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/data-for-tests.html b/master/data-for-tests.html deleted file mode 100644 index db976c623..000000000 --- a/master/data-for-tests.html +++ /dev/null @@ -1,866 +0,0 @@ - - - - - - - 32.3 Data for tests | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

32.3 Data for tests

-

Many of PEcAn’s functions require inputs that are provided as data. -These can be in the data or the inst/extdata folders of a package. -Data that are not package specific should be placed in the PEcAn.all (base/all) or -PEcAn.utils (base/utils) packages.

-

Some useful conventions:

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/database-maintentance.html b/master/database-maintentance.html deleted file mode 100644 index 489cd1fd3..000000000 --- a/master/database-maintentance.html +++ /dev/null @@ -1,918 +0,0 @@ - - - - - - - 17.6 Database maintentance | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

17.6 Database maintentance

-

All databases need maintenance performed on them. Depending upon the database type this can happen automatically, or it needs to be run through a scheduler or manually. The BETYdb database is Postgresql and it needs to be reindexed and vacuumed on a regular basis. Reindexing introduces efficiencies back into the database by reorganizing the indexes. Vacuuming the database frees up resources to the database by rearranging and compacting the database. Both of these operations are necessary and safe. As always if there’s a concern, a backup of the database should be made ahead of time. While running the reindexing and vacuuming commands, users will notice a slowdown at times. Therefore it’s better to run these maintenance tasks during off hours.

-
-

17.6.1 Reindexing the database

-

As mentioned above, reindexing allows the database to become more efficient. Over time as data gets updated and deleted, the indexes become less efficient. This has a negative inpact on executed statements. Reindexing makes the indexes efficient again (at least for a while) allowing faster statement execution and reducing the overall load on the database.

-

The reindex.bety.sh script is provided to simplify reindexing the database.

-
reindex.bety.sh -h
-./reindex.bety.sh [-c datalog] [-d database] [-h] [-i table names] [-p psql options] [-q] [-s] [-t tablename]
- -c catalog, database catalog name used to search for tables, default is bety
- -d database, default is bety
- -h this help page
- -i table names, list of space-separated table names to skip over when reindexing
- -p additional psql command line options, default is -U bety
- -q the reindexing should be quiet
- -s reindex the database after reindexing the tables (this should be done sparingly)
- -t tablename, the name of the one table to reindex
-

If the database is small enough it’s reasonable to reindex the entire database at one time. To do this manually run or schedule the REINDEX statement. For example:

-
reindex.bety.sh -s
-

For larger databases it may be desireable to reindex entire tables at a time. An efficient way to do this is to reindex the larger tables and then the entire database. For example:

-
reindex.bety.sh -t traits; reindex.bety.sh -t yields;
-reindex.bety.sh -s
-

For very large databases it may be desirable to reindex one or more individual indexes before reindexing tables and the databases. In this case running specific psql commands to reindex those specific indexes, followed by reindexing the table is a possible approach. For example:

-
psql -U bety -c "REINDEX INDEX index_yields_on_citation_id; REINDEX INDEX index_yields_on_cultivar_id;"
-reindex.bety.sh -t yields;
-

Splitting up the indexing commands over time allows the database to operate efficiently with minimal impact on users. One approach is to schedule the reindexing of large, complex tables at a spcific off-time during the week, followed by a general reindexing and excluding those large tables on a weekend night.

-

Please refere to the Automation section above for information on using cron to schedule reindexing commands.

-
-
-

17.6.2 Vacuuming the database

-

Vacuuming the BETYdb Postgresql database reduces the amount of resources it uses and introduces its own efficiencies.

-

Over time, modified and deleted records leave ‘holes’ in the storage of the database. This is a common feature for most databases. Each database has its own way of handing this, in Postgresql it’s the VACUUM command. The VACUUM command performs two main operations: cleaning up tables to make memory use more efficient, and analyze tables for optimum statement execution. The use of the keyword ANALYZE indicates the second operation should take place.

-

The vacuum.bety.sh script is provided to simplify vacuuming the database.

-
vacuum.bety.db -h
-./vacuum.bety.sh [-c datalog] [-d database] [-f] [-h] [-i table names] [-n] [-p psql options] [-q] [-s] [-t tablename] [-z]
- -c catalog, database catalog name used to search for tables, default is bety
- -d database, default is bety
- -f perform a full vacuum to return resources to the system. Specify rarely, if ever
- -h this help page
- -i table names, list of space-separated table names to skip over when vacuuming
- -n only vacuum the tables and do not analyze, default is to first vacuum and then analyze
- -p additional psql command line options, default is -U bety
- -q the export should be quiet
- -s skip vacuuming the database after vacuuming the tables
- -t tablename, the name of the one table to vacuum
- -z only perform analyze, do not perform a regular vacuum, overrides -n and -f, sets -s
-

For small databases with light loads it may be possible to set aside a time for a complete vacuum. During this time, commands executed against the database might fail (a temporary condition as the database gets cleaned up). The following commands can be used to perform all the vaccum operations in one go.

-
vacuum.bety.sh -f
-

Generally it’s not desireable to have down time. If the system running the database doesn’t need resources that the database is using returned to it, a FULL vacuum can be avoided. This is the default behavior of the script

-
vacuum.bety.sh
-

In larger databases, vacuuming the entire database can take a long time causing a negative impact on users. This means that individual tables need to be vacuumed. How often a vacuum needs to be performed is dependent upon a table’s activity. The more frequently updates and deletes occur on a table, the more frequent the vaccum should be. For large tables it may be desireable to separate the table cleanup from the analysis. An example for completely vacuuming and analyzing a table is:

-
psql -U bety -c "VACUUM traits; VACUUM ANALYZE traits;"
-

Similar to indexes, vacuuming the most active tables followed by general database vacuuming and vacuum analyze may be a desireable approach.

-

Also note that it isn’t necessary to run VACUUM ANALYZE for each vacuum performed. Separating the commands and performing a VACUUM ANALYZE after several regular vacuums may be sufficient, with less load on the database.

-

If the BETYdb database is running on a system with limited resources, or with resources that have become limited, the VACCUM command can return resources to the system from the database. The normal vacuuming process releases resources back to the database for reuse, but not to the system; generally this isn’t a problem. Postgresql has a VACUUM keyword FULL that returns resources back to the system. Requesting a FULL vacuum will lock the table being vacuumed while it is being re-written preventing any statements from being executed against it. If performing VECUUM FULL against the entire database, only the table being actively worked on is locked.

-

To minimize the impact a VACUUM FULL has on users, it’s best to perform a normal vacuum before a FULL vacuum. If this approach is taken, there sould be a minimal time gap between the normal VACUUM and the VACUUM FULL commands. A normal vacuum allows changes to be made thus requiring the full vacuum to handle those changes, extending it’s run time. Reducing the time between the two commands lessens the work VACUUM FULL needs to do.

-
psql -U bety -c "VACUUM yields; VACUUM FULL yields; VACUUM ANALYZE yields;"
-

Give its impact, it’s typically not desireable to perform a VACUUM FULL after every normal vacuum; it should be done on an “as needed” basis or infrequently.

-
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/database-setup.html b/master/database-setup.html deleted file mode 100644 index 7806270f4..000000000 --- a/master/database-setup.html +++ /dev/null @@ -1,863 +0,0 @@ - - - - - - - 22.1 Best practices | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

22.1 Best practices

-

When using the BETY database in non testing mode, it is best not to use the default users. This is accomplished when running the initialize of the database. When the database is initally created the database will be created with some default users (best known is the carya user) as well as the guestuser that can be used in the BETY web application. To disable these users you will either need to disable the users from the web interface, or you can reinitialize the database and remove the -u flag from the command line (the -u flag will create the default users). To disable the guestuser as well you can remove the -g flag from the command line, or disable the account from BETY.

-

The default installation of BETY and PEcAn will assume there is a database called bety with a default username and password. The default installation will setup the database account to not have any superuser abilities. It is also best to limit access to the postgres database from trusted hosts, either by using firewalls, or configuring postgresql to only accept connections from a limited set of hosts.

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/database-sync.html b/master/database-sync.html deleted file mode 100644 index 4d9077cd4..000000000 --- a/master/database-sync.html +++ /dev/null @@ -1,864 +0,0 @@ - - - - - - - 17 Database synchronization | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

17 Database synchronization

-

The database synchronization consists of 2 parts: -- Getting the data from the remote servers to your server -- Sharing your data with everybody else

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/database.html b/master/database.html deleted file mode 100644 index 3a2125e20..000000000 --- a/master/database.html +++ /dev/null @@ -1,862 +0,0 @@ - - - - - - - 22 BETY Database Administration | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

22 BETY Database Administration

-

This section provides additional details about the BETY database used by PEcAn. It will discuss best practices for setting up the BETY database, how to backup the database and how to restore the database.

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/debugging-shiny-apps.html b/master/debugging-shiny-apps.html deleted file mode 100644 index 6b17f8531..000000000 --- a/master/debugging-shiny-apps.html +++ /dev/null @@ -1,866 +0,0 @@ - - - - - - - 19.2 Debugging Shiny Apps | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

19.2 Debugging Shiny Apps

-

When developing shiny apps you can run the application from rstudio and place breakpoints int he code. To do this you will need to do the following steps first (already done on the VM) before starting rstudio: -- echo “options(shiny.port = 6438)” >> ${HOME}/.Rprofile -- echo “options(shiny.launch.browser = ‘FALSE’)” >> ${HOME}/.Rprofile

-

Next you will need to create a tunnel for port 6438 to the VM, which will be used to open the shiny app, the following command will creat this tunnel: ssh -l carya -p 6422 -L 6438:localhost:6438 localhost.

-

Now you can from rstudio run your application using shiny::runApp() and it will show the output from the application in your console. You can now place breakpoints and evaluate the output.

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/debugging.html b/master/debugging.html deleted file mode 100644 index 6cc568060..000000000 --- a/master/debugging.html +++ /dev/null @@ -1,869 +0,0 @@ - - - - - - - 21.4 Debugging | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

21.4 Debugging

-

How to identify the source of a problem.

-
-

21.4.1 Using tests/workflow.R

-

This script, along with model-specific settings files in the tests folder, provide a working example. From inside the tests folder, R CMD --vanilla -- --settings pecan.<model>.xml < workflow.R should work.

-

The next step is to add debugonce(<broken.function.name>) before running the test workflow.

-

This allows you can step through the function and evaluate the different objects as they are created and/or transformed.

-

See tests README for more information.

-
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/declaring-dependencies-depends-suggests-imports.html b/master/declaring-dependencies-depends-suggests-imports.html deleted file mode 100644 index 9c2f40c2a..000000000 --- a/master/declaring-dependencies-depends-suggests-imports.html +++ /dev/null @@ -1,878 +0,0 @@ - - - - - - - 31.3 Declaring Dependencies: Depends, Suggests, Imports | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

31.3 Declaring Dependencies: Depends, Suggests, Imports

-

List all dependencies in the DESCRIPTION file. Every package that is used by your package’s code must appear in exactly one of the sections Depends, Imports, or Suggests.

-

Please list packages in alphabetical order within each section. R doesn’t care about the order, but you will later when you’re trying to check whether this package uses a particular dependency.

-
    -
  • Imports is the correct place to declare most PEcAn dependencies. This ensures that they get installed, but does not automatically import any of their functions – Since PEcAn style prefers to mostly use :: instead of importing, this is what we want.

  • -
  • Depends is, despite the name, usually the wrong place to declare PEcAn dependencies. The only difference between Depends and Imports is that when the user attaches your packages to their own R workspace (e.g. using library("PEcAn.yourpkg")), the packages in Depends are attached as well. Notice that a call like PEcAn.yourpkg::yourfun() will not attach your package or its dependencies, so your code still needs to import or ::-qualify all functions from packages listed in Depends. In short, Depends is not a shortcut, is for user convenience not developer convenience, and makes it easy to create subtle bugs that appear to work during interactive test sessions but fail when run from scripts. As the R extensions manual puts it (emphasis added):

    -
    -

    This [Imports and Depends] scheme was developed before all packages had namespaces (R 2.14.0 in October 2011), and good practice changed once that was in place. Field ‘Depends’ should nowadays be used rarely, only for packages which are intended to be put on the search path to make their facilities available to the end user (and not to the package itself).”

    -
  • -
  • The Suggests field can be used to declare dependencies on packages that make your package more useful but are not completely essential. Again from the R extensions manual:

    -
    -

    The Suggests field uses the same syntax as Depends and lists packages that are not necessarily needed. This includes packages used only in examples, tests or vignettes (see Writing package vignettes), and packages loaded in the body of functions. E.g., suppose an example from package foo uses a dataset from package bar. Then it is not necessary to have bar use foo unless one wants to execute all the examples/tests/vignettes: it is useful to have bar, but not necessary.

    -
    -

    Some of the PEcAn model interface packages push this definition of “not necessarily needed” by declaring their coupled model package in Suggests rather than Imports. For example, the PEcAn.BIOCRO package cannot do anything useful when the BioCro model is not installed, but it lists BioCro in Suggests because PEcAn as a whole can work without it. This is a compromise to simplify installation of PEcAn for users who only plan to use a few models, so that they can avoid the bother of installing BioCro if they only plan to run, say, SIPNET.

    -

    Since the point of Suggests is that they are allowed to be missing, all code that uses a suggested package must behave reasonably when the package is not found. Depending on the situation, “reasonably” could mean checking whether the package is available and throwing an error as needed (PEcAn.BIOCRO uses its .onLoad function to check at load time whether BioCro is installed and will refuse to load if it is not), or providing an alternative behavior (PEcAn.data.atmosphere::get_NARR_thredds checks at call time for either parallel or doParallel and uses whichever one it finds first), or something else, but your code should never just assume that the suggested package is available.

    -

    You are not allowed to import functions from Suggests into your package’s namespace, so always call them in ::-qualified form. By default R will not install suggested packages when your package is installed, but users can change this using the dependencies argument of install.packages. Note that for testing on Travis CI, PEcAn does install all Suggests (because they are required for full package checks), so any of your code that runs when a suggested package is not available will never be exercised by Travis checks.

    -

    It is often tempting to move a dependency from Imports to Suggests because it is a hassle to install (large, hard to compile, no longer available from CRAN, currently broken on GitHub, etc), in the hopes that this will isolate the rest of PEcAn from the troublesome dependency. This helps for some cases, but fails for two very common ones: It does not reduce install time for CI builds, because all suggested packages need to be present when running full package checks (R CMD check or devtools::check or make check). It also does not prevent breakage when updating PEcAn via make install, because devtools::install_deps does not install suggested packages that are missing but does try to upgrade any that are already installed to the newest available version – even if the installed version took ages to compile and would have worked just fine!

  • -
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/defining-new-input-formats.html b/master/defining-new-input-formats.html deleted file mode 100644 index 38b51c08c..000000000 --- a/master/defining-new-input-formats.html +++ /dev/null @@ -1,865 +0,0 @@ - - - - - - - 11.1 Defining new input formats | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

11.1 Defining new input formats

-
    -
  • New formats can be defined on the ‘formats’ page of BETYdb
  • -
  • After creating a new format, the contents should be defined by specifying the BETYdb variable name and the name used in the file/
  • -
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/demo-1.html b/master/demo-1.html deleted file mode 100644 index 5345594db..000000000 --- a/master/demo-1.html +++ /dev/null @@ -1,1025 +0,0 @@ - - - - - - - 5.3 Demo 01: Basic Run PEcAn | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

5.3 Demo 01: Basic Run PEcAn

-
-

5.3.0.1 Objective

-

We will begin by exploring a set of web-based tools that are designed to run single-site model runs. A lot of the detail about what’s going on under the hood, and all the outputs that PEcAn produces, are left to Demo 2. This demo will also demonstrate how to use PEcAn outputs in additional analyses outside of PEcAn.

-
-
-

5.3.0.2 PEcAn URL

-

In the following demo, URL is the web address of a PEcAn server and will refer to one of the following:

-
    -
  • If you are doing a live demo with the PEcAn team, URL was provided
  • -
  • If you are running the PEcAn virtual machine: URL = localhost:6480
  • -
  • If you are running PEcAn using Amazon Web Services (AWS), URL is the Public IP
  • -
  • If you are running PEcAn using Docker, URL is pecan.localhost
  • -
  • If you followed instructions found in Install PEcAn by hand, URL is your server’s IP
  • -
-
-
-

5.3.0.3 Start PEcAn:

-
    -
  1. Enter URL in your web browser
  2. -
  3. Click the link for the PEcAn web interface
  4. -
  5. Click the ‘Next’ button in the sidebar to move to the “Site Selection” page.
  6. -
-

-
-
-

5.3.0.4 Site Selection

-

-
-
-

5.3.0.5 Host

-

Select the local machine “pecan”. Other options exist if you’ve read and followed instructions found in Remote execution with PEcAn.

- -
-
-

5.3.0.6 Model

-

Select SIPNET (r136) from the available models because it is quick & simple. Reference material can be found in Models in PEcAn

-
-
-

5.3.0.7 Site Group

-

To filter sites, you can select a specific group of sites. For this tutorial we will use Ameriflux.

-
-
-

5.3.0.8 Conversion:

-

Select the conversion check box, to show all sites that PEcAn is capable of generating model drivers for automatically. By default (unchecked), PEcAn only displays sites where model drivers already exist in the system database

-
-
-

5.3.0.9 Site:

-

For this tutorial, type US-NR1 in the search box to display the Niwot Ridge Ameriflux site (US-NR1), and then click on the pin icon. When you click on a site’s flag on the map, it will give you the name and location of the site and put that site in the “Site:” box on the left hand site, indicating your current selection.

-

Once you are finished with the above steps, click “Next”.

-
-
-

5.3.0.10 Run Specification

-

-

Next we will specify settings required to run the model. Be aware that the inputs required for any particular model may vary somewhat so there may be addition optional or required input selections available for other models.

-
-
-

5.3.0.11 PFT (Plant Functional Type):

-

Niwot Ridge is temperate coniferous. Available PFTs will vary by model and some models allow multiple competing PFTs to be selected. Also select soil to control the soil parameters

-
-
-

5.3.0.12 Start/End Date:

-

Select 2003/01/01 to 2006/12/31. In general, be careful to select dates for which there is available driver data.

-
-
-

5.3.0.13 Weather Data:

-

For Sipnet.climna select “Use AmerifluxLBL” from the Available Meteorological Drivers.

-
-
-

5.3.0.14 Optional Settings:

-

Leave all blank for demo run

-
    -
  1. Email sends a message when the run is complete.
  2. -
  3. Use Brown Dog will use the Brown Dog web services in order to do input file conversions. (Note: Required if you select Use NARR for Weather Data)
  4. -
  5. Edit pecan.xml allows you to configure advanced settings via the PEcAn settings file
  6. -
  7. Edit model config pauses the workflow after PEcAn has written all model specific settings but before the model runs are called and allows users to configure any additional settings internal to the model.
  8. -
  9. Advanced Setup controls ensemble and sensitivity run settings discussed in Demo 2.
  10. -
-

Finally, click “Next” to start the model run.

-
-
-

5.3.0.15 Data Use Policies

-

The last step before the run starts is to read and agree to AmeriFlux’s data policy and give a valid username. If you don’t already have an Ameriflux username, click “register here” and create one. If you selected a different data source, this step may or may not be needed: you will need to agree to a data policy if your source has one, but if it doesn’t then the run will start immediately.

-
-
-

5.3.0.16 If you get an error in your run

-

If you get an error in your run as part of a live demo or class activity, it is probably simplest to start over and try changing options and re-running (e.g. with a different site or PFT), as time does not permit detailed debugging. If the source of the error is not immediately obvious, you may want to take a look at the workflow.Rout to see the log of the PEcAn workflow or the logfile.txt to see the model execution output log and then refer to the Documentation or the Chat Room for help.

-
-
-

5.3.0.17 Model Run Workflow

-

-
-
-

5.3.0.18 MET Process:

-

First, PEcAn will download meteorological data based on the type of the Weather Data you chose, and process it into the specific format for the chosen model

-
-
-

5.3.0.19 TRAIT / META:

-

PEcAn then estimates model parameters by performing a meta-analysis of the available trait data for a PFT. TRAIT will extract relevant trait data from the database. META performs a hierarchical Bayes meta-analysis of available trait data. The output of this analysis is a probability distribution for each model parameter. PEcAn selects the median value of this parameter as the default, but in Demo 2 we will see how PEcAn can use this parameter uncertainty to make probabilistic forecasts and assess model sensitivity and uncertainty. Errors at this stage usually indicate errors in the trait database or incorrectly specified PFTs (e.g. defining a variable twice).

-
-
-

5.3.0.20 CONFIG:

-

writes model-specific settings and parameter files

-
-
-

5.3.0.21 MODEL:

-

runs model.

-
-
-

5.3.0.22 OUTPUT:

-

All model outputs are converted to standard netCDF format

-
-
-

5.3.0.23 ENSEMBLE & SENSITIVITY:

-

If enabled post-process output for these analyses

-

If at any point a Stage Name has the Status “ERROR” please notify the PEcAn team member that is administering the demo or feel free to do any of the following:

-
    -
  • Refer to the PEcAn Documentation for documentation
  • -
  • Post the end of your workflow log on our Slack Channel chat
  • -
  • Post an issue on Github.
  • -
-

The entire PEcAn team welcomes any questions you may have!

-

If the Finished Stage has a Status of “DONE”, congratulations! If you got this far, you have managed to run an ecosystem model without ever touching a line of code! Now it’s time to look at the results click Finished.

-

FYI, adding a new model to PEcAn does not require modification of the model’s code, just the implementation of a wrapper function.

-
-
-

5.3.0.24 Output and Visualization

-

For now focus on graphs, we will explore all of PEcAn’s outputs in more detail in Demo 02.

-
-
-

5.3.0.25 Graphs

-
    -
  1. Select a Year and Y-axis Variable, and then click ‘Plot run/year/variable’. Initially leave the X-axis as time.
  2. -
  3. Within this figure the points indicate the daily mean for the variable while the envelope encompasses the diurnal variability (max and min).
  4. -
  5. Variable names and units are based on a standard netCDF format.
  6. -
  7. Try looking at a number of different output variables over different years.
  8. -
  9. Try changing the X-axis to look at bivariate plots of how different output variables are related to one another. Be aware that PEcAn currently runs a moving min/mean/max through bivariate plots, just as it does with time series plots. In some cases this makes more sense than others.
  10. -
-
-
-

5.3.0.26 Alternative Visualization: R Shiny

-
    -
  1. Click on Open SHINY, which will open a new browser window. The shiny app will automatically access your run’s output files and allow you to visualize all output variables as a function of time.
  2. -
-

-
    -
  1. Use the pull down menu under Variable Name to choose whichever output variable you wish to plot.
  2. -
-
-
-

5.3.0.27 Model Run Archive

-

Return to the output window and Click on the HISTORY button. Click on any previous run in the “ID” column to go to the current state of that run’s execution – you can always return to old runs and runs in-progress this way. The run you just did should be the more recent entry in the table. For the next analysis, make note of the ID number from your run.

-
-
-

5.3.0.28 Next steps

-
-
5.3.0.28.1 Analyzing model output
-

Follow this tutorial, [Analyze Output] to learn how to open model output in R and compare to observed data

-
-
-
-

5.3.0.29 DEMO 02

-

Demo 02: Sensitivity and Uncertainty Analysis will show how to perform Ensemble & Sensitivity Analyses through the web interface and explore the PEcAn outputs in greater detail, including the trait meta-analysis

- -
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/demo-2.html b/master/demo-2.html deleted file mode 100644 index e5bf32f84..000000000 --- a/master/demo-2.html +++ /dev/null @@ -1,986 +0,0 @@ - - - - - - - 5.4 Demo 02: Sensitivity and Uncertainty Analysis | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

5.4 Demo 02: Sensitivity and Uncertainty Analysis

-

In Demo 2 we will be looking at how PEcAn can use information about parameter uncertainty to perform three automated analyses:

-
    -
  • Ensemble Analysis: Repeat numerous model runs, each sampling from the parameter uncertainty, to generate a probability distribution of model projections. Allows us to put a confidence interval on the model
  • -
  • Sensitivity Analysis: Repeats numerous model runs to assess how changes in model parameters will affect model outputs. Allows us to identify which parameters the model is most sensitive to.
  • -
  • Uncertainty Analysis: Combines information about model sensitivity with information about parameter uncertainty to determine the contribution of each model parameter to the uncertainty in model outputs. Allow us to identify which parameters are driving model uncertainty.
  • -
-
-

5.4.1 Run Specification

-
    -
  1. Return to the main menu for the PEcAn web interface: Click the “Start Over” button or navigate back to URL/pecan/

  2. -
  3. Repeat the steps for site selection and run specification from Demo 01, but also click on “Advanced setup”, then click Next.

  4. -
  5. By clicking Advanced setup, PEcAn will first show an Analysis Menu, where we are going to specify new settings.

  6. -
-
    -
  • For an ensemble analysis, increase the number of runs in the ensemble, in this case set Runs to 50. In practice you would want to use a larger ensemble size (100-5000) than we are using in the demo. The ensemble analysis samples parameters from their posterior distributions to propagate this uncertainty into the model output.

  • -
  • PEcAn’s sensitivity analysis holds all parameters at their median value and then varies each parameter one-at-a-time based on the quantiles of the posterior distribution. PEcAn also includes a handy shortcut, which is the default behavior for the web interface, that converts a specified standard deviation into its Normal quantile equivalent (e.g. 1 and -1 are converted to 0.157 and 0.841). In this example set Sensitivity to -2,-1,1,2 (the median value, 0, occurs by default).

  • -
  • We also can tell PEcAn which variable to run the sensitivity on. Here, set Variables to NEE, so we can compare against flux tower NEE observations.

  • -
-

Click Next

-
-
-

5.4.2 Additional Outputs:

-

The PEcAn workflow will take considerably longer to complete since we have just asked for over a hundred model runs. Once the runs are complete you will return to the output visualization page were there will be a few new outputs to explore, as well as outputs that were present earlier that we’ll explore in greater details:

-
-

5.4.2.1 Run ID:

-

While the sensitivity and ensemble analyses synthesize across runs, you can also select individual runs from the Run ID menu. You can use the Graphs menu to visualize each individual run, or open individual runs in Shiny

-
-
-

5.4.2.2 Inputs:

-

This menu shows the contents of /run which lets you look at and download:

-
    -
  1. A summary file (README.txt) describing each run: location, run ID, model, dates, whether it was in the sensitivity or ensemble analysis, variables modified, etc.
  2. -
  3. The model-specific input files fed into the model
  4. -
  5. The jobs.sh file used to submit the model run
  6. -
-
-
-

5.4.2.3 Outputs:

-

This menu shows the contents of /out. A number of files generated by the underlying ecosystem model are archived and available for download. These include:

-
    -
  1. Output files in the standardized netCDF ([year].nc) that can be downloaded for visualization and analysis (R, Matlab, ncview, panoply, etc)
  2. -
  3. Raw model output in model-specific format (e.g. sipnet.out).
  4. -
  5. Logfile.txt contains job.sh & model error, warning, and informational messages
  6. -
-
-
-

5.4.2.4 PFTs:

-

This menu shows the contents of /pft. There is a wide array of outputs available that are related to the process of estimating the model parameters and running sensitivity/uncertainty analyses for a specific Plant Functional Type.

-
    -
  1. TRAITS: The Rdata files trait.data.Rdata and jagged.data.Rdata are, respectively, the available trait data extracted from the database that was used to estimate the model parameters and that same data cleaned and formatted for the statistical code. The list of variables that are queried is determined by what variables have priors associated with them in the definition of the PFTs. Priors are output into prior.distns.Rdata. Likewise, the list of species that are associated with a PFT determines what subset of data is extracted out of all data matching a given variable name. Demo 3 will demonstrate how a PFT can be created or modified. To look at these files in RStudio click on these files to load them into your workspace. You can further examine them in the Environment window or accessing them at the command line. For example, try typing names(trait.data) as this will tell you what variables were extracted, names(trait.data$Amax) will tell you the names of the columns in the Amax table, and summary(trait.data$Amax) will give you summary data about the Amax values.
  2. -
  3. META-ANALYSIS:
  4. -
-
    -
  • *.bug: The evaluation of the meta-analysis is done using a Bayesian statistical software package called JAGS that is called by the R code. For each trait, the R code will generate a [trait].model.bug file that is the JAGS code for the meta-analysis itself. This code is generated on the fly, with PEcAn adding or subtracting the site, treatment, and greenhouse terms depending upon the presence of these effects in the data itself. If the <random.effects> tag is set to FALSE then all random effects will be turned off even if there are multiple sites.
  • -
  • meta-analysis.log contains a number of diagnostics, including the summary statistics of the model, an assessment of whether the posterior is consistent with the prior, and the status of the Gelman-Brooks-Rubin convergence statistic (which is ideally 1.0 but should be less than 1.1).
  • -
  • ma.summaryplots.*.pdf are collections of diagnostic plots produced in R after the above JAGS code is run that are useful in assessing the statistical model. Open up one of these pdfs to evaluate the shape of the posterior distributions (they should generally be unimodal), the convergence of the MCMC chains (all chains should be mixing well from the same distribution), and the autocorrelation of the samples (should be low).
  • -
  • traits.mcmc.Rdata contains the raw output from the statistical code. This includes samples from all of the parameters in the meta-analysis model, not just those that feed forward to the ecosystem, but also the variances, fixed effects, and random effects.
  • -
  • post.distns.Rdata stores a simple tables of the posterior distributions for all model parameters in terms of the name of the distribution and its parameters.
  • -
  • posteriors.pdf provides graphics showing, for each model parameter, the prior distribution, the data, the smoothed histogram of the posterior distribution (labeled post), and the best-fit analytical approximation to that smoothed histogram (labeled approx). Open posteriors.pdf and compare the posteriors to the priors and data
  • -
-
    -
  1. SENSITIVITY ANALYSIS
  2. -
-
    -
  • sensitivity.analysis.[RunID].[Variable].[StartYear].[EndYear].pdf shows the raw data points from univariate one-at-a-time analyses and spline fits through the points. Open this file to determine which parameters are most and least sensitive
  • -
-
    -
  1. UNCERTAINTY ANALYSIS
  2. -
-
    -
  • variance.decomposition.[RunID].[Variable].[StartYear].[EndYear].pdf, contains three columns, the coefficient of variation (normalized posterior variance), the elasticity (normalized sensitivity), and the partial standard deviation of each model parameter. Open this file for BOTH the soil and conifer PFTS and answer the following questions:
  • -
  • The Variance Decomposition graph is sorted by the variable explaining the largest amount of variability in the model output (right hand column). From this graph identify the top-tier parameters that you would target for future constraint.
    -
  • -
  • A parameter can be important because it is highly sensitive, because it is highly uncertain, or both. Identify parameters in your output that meet each of these criteria. Additionally, identify parameters that are highly uncertain but unimportant (due to low sensitivity) and those that are highly sensitive but unimportant (due to low uncertainty).
  • -
  • Parameter constraints could come from further literature synthesis, from direct measurement of the trait, or from data assimilation. Choose the parameter that you think provides the most efficient means of reducing model uncertainty and propose how you might best reduce uncertainty in this process. In making this choice remember that not all processes in models can be directly observed, and that the cost-per-sample for different measurements can vary tremendously (and thus the parameter you measure next is not always the one contributing the most to model variability). Also consider the role of parameter uncertainty versus model sensitivity in justifying your choice of what parameters to constrain.
  • -
-
-
-

5.4.2.5 PEcAn Files:

-

This menu shows the contents of the root workflow folder that are not in one of the folders indicated above. It mostly contains log files from the PEcAn workflow that are useful if the workflow generates an error, and as metadata & provenance (a detailed record of how data was generated).

-
    -
  1. STATUS gives a summary of the steps of the workflow, the time they took, and whether they were successful
  2. -
  3. pecan.*.xml are PEcAn settings files
  4. -
  5. workflow.R is the workflow script
  6. -
  7. workflow.Rout is the corresponding log file
  8. -
  9. samples.Rdata contains the parameter values used in the runs. This file contains two data objects, sa.samples and ensemble.samples, that are the parameter values for the sensitivity analysis and ensemble runs respectively
  10. -
  11. sensitivity.output.[RunID].[Variable].[StartYear].[EndYear].Rdata contains the object sensitivity.output which is the model outputs corresponding to the parameter values in sa.samples.
  12. -
  13. ENSEMBLE ANALYSIS
  14. -
-
    -
  • ensemble.Rdata contains contains the object ensemble.output, which is the model predictions at the parameter values given in ensemble.samples.
  • -
  • ensemble.analysis.[RunID].[Variable].[StarYear].[EndYear].pdf contains the ensemble prediction as both a histogram and a boxplot.
  • -
  • ensemble.ts.[RunID].[Variable].[StartYear].[EndYear].pdf contains a time-series plot of the ensemble mean, median, and 95% CI
  • -
-
-
-

5.4.2.6 Global Sensitivity: Shiny

-

Navigate to URL/shiny/global-sensitivity.

-

This app uses the output from the ENSEMBLE runs to perform a global Monte Carlo sensitivity analysis. There are three modes controlled by Output type:

-
    -
  1. Pairwise looks at the relationship between a specific parameter (X) and output (Y)
  2. -
  3. All parameters looks at how all parameters affect a specific output (Y)
  4. -
  5. All variables looks at how all outputs are affected by a specific parameter(X)
  6. -
-

In all of these analyses, the app also fits a linear regression to these scatterplots and reports a number of summary statistics. Among these, the slope is an indicator of global sensitivity and the R2 is an indicator of the contribution to global uncertainty

-
-
-

5.4.2.7 Next Steps

-

The next set of tutorials will focus on the process of data assimilation and parameter estimation. The next two steps are in “.Rmd” files which can be viewed online.

-
-
-

5.4.2.8 Assimilation ‘by hand’

-

Explore how model error changes as a function of parameter value (i.e. data assimilation ‘by hand’)

-
-
-

5.4.2.9 MCMC Concepts

-

Explore Bayesian MCMC concepts using the photosynthesis module

-
-
-

5.4.2.10 More info about tools, analyses, and specific tasks…

-

Additional information about specific tasks (adding sites, models, data; software updates; etc.) and analyses (e.g. data assimilation) can be found in the PEcAn documentation

-

If you encounter a problem with PEcAn that’s not covered in the documentation, or if PEcAn is missing functionality you need, please search known bugs and issues, submit a bug report, or ask a question in our chat room. Additional questions can be directed to the project manager

- -
-
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/demo-table.html b/master/demo-table.html deleted file mode 100644 index e850f6a10..000000000 --- a/master/demo-table.html +++ /dev/null @@ -1,965 +0,0 @@ - - - - - - - 5.2 PEcAn Demos | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

5.2 PEcAn Demos

-

The following Tutorials assume you have installed PEcAn. If you have not, please consult the PEcAn Installation Section.

- ------ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TypeTitleWeb LinkSource Rmd
DemoBasic RunhtmlRmd
DemoUncertainty AnalysishtmlRmd
DemoOutput AnalysishtmlRmd
DemoMCMChtmlRmd
DemoParameter AssimilationhtmlRmd
DemoState AssimilationhtmlRmd
DemoSensitivityhtmlRmd
VignetteAllometrieshtmlRmd
VignetteMCMChtmlRmd
VignetteMeteorological DatahtmlRmd
VignetteMeta-AnalysishtmlRmd
VignettePhotosynthetic Response CurveshtmlRmd
VignettePriorshtmlRmd
VignetteLeaf Spectra:PROSPECT inversionhtmlRmd
- -
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/developer-devtools.html b/master/developer-devtools.html deleted file mode 100644 index debeff362..000000000 --- a/master/developer-devtools.html +++ /dev/null @@ -1,898 +0,0 @@ - - - - - - - 33 devtools package | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

33 devtools package

-

Provides functions to simplify development

-

Documentation: -The R devtools package

-
load_all("pkg")
-document("pkg")
-test("pkg")
-install("pkg")
-build("pkg")
-

other tips for devtools (from the documentation):

-
    -
  • Adding the following to your ~/.Rprofile will load devtools when -running R in interactive mode:
  • -
-
# load devtools by default
-if (interactive()) {
-  suppressMessages(require(devtools))
-}
-
    -
  • Adding the following to your .Rpackages will allow devtools to recognize package by folder name, rather than directory path
  • -
-
# in this example, devhome is the pecan trunk directory 
-devhome <- "/home/dlebauer/R-dev/pecandev/"
-list(
-    default = function(x) {
-      file.path(devhome, x, x)
-    }, 
-  "utils" = paste(devhome, "pecandev/utils", sep = "")
-  "common" = paste(devhome, "pecandev/common", sep = "")
-  "all" = paste(devhome, "pecandev/all", sep = "")
-  "ed" = paste(devhome, "pecandev/models/ed", sep = "")
-  "uncertainty" = paste(devhome, "modules/uncertainty", sep = "")
-  "meta.analysis" = paste(devhome, "modules/meta.analysis", sep = "")
-  "db" = paste(devhome, "db", sep = "")
-)
-

Now, devtools can take pkg as an argument instead of /path/to/pkg/, -e.g. so you can use build("pkg") instead of build("/path/to/pkg/")

- -
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/developer-guide.html b/master/developer-guide.html deleted file mode 100644 index e7bae35cb..000000000 --- a/master/developer-guide.html +++ /dev/null @@ -1,868 +0,0 @@ - - - - - - - 8 Developer guide | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
- -
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/developer-testing.html b/master/developer-testing.html deleted file mode 100644 index 64d34b400..000000000 --- a/master/developer-testing.html +++ /dev/null @@ -1,1010 +0,0 @@ - - - - - - - 9.1 Testing | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

9.1 Testing

-

PEcAn uses two different kinds of testing – unit tests and integration tests.

-
-

9.1.1 Unit testing

-

Unit tests are short (<1 minute runtime) tests of functionality of specific functions. -Ideally, every function should have at least one unit test associated with it.

-

A unit test should be written for each of the following situations:

-
    -
  1. Each bug should get a regression test.
  2. -
-
    -
  • The first step in handling a bug is to write code that reproduces the error
  • -
  • This code becomes the test
  • -
  • most important when error could re-appear
  • -
  • essential when error silently produces invalid results
  • -
-
    -
  1. Every time a (non-trivial) function is created or edited
  2. -
-
    -
  • Write tests that indicate how the function should perform -
      -
    • example: expect_equal(sum(1,1), 2) indicates that the sum -function should take the sum of its arguments
    • -
  • -
  • Write tests for cases under which the function should throw an -error
  • -
  • example: expect_error(sum("foo"))
  • -
  • better : expect_error(sum("foo"), "invalid 'type' (character)")
  • -
-
    -
  1. Any functionality that you would like to protect over the long term. Functionality that is not tested is more likely to be lost. -PEcAn uses the testthat package for unit testing. -A general overview of is provided in the “Testing” chapter of Hadley Wickham’s book “R packages”. -Another useful resource is the testthat package documentation website. -See also our testthat appendix. -Below is a lightning introduction to unit testing with testthat.
  2. -
-

Each package’s unit tests live in .R scripts in the folder <package>/tests/testthat. -In addition, a testthat-enabled package has a file called <packagename>/tests/testthat.R with the following contents:

-
library(testthat)
-library(<packagename>)
-
-test_check("<packagename>")
-

Tests should be placed in <packagename>/tests/testthat/test-<sourcefilename>.R, and look like the following:

-
context("Mathematical operators")
-
-test_that("mathematical operators plus and minus work as expected",{
-  sum1 <- sum(1, 1)
-  expect_equal(sum1, 2)
-  sum2 <- sum(-1, -1)
-  expect_equal(sum2, -2)
-  expect_equal(sum(1,NA), NA)
-  expect_error(sum("cat"))
-  set.seed(0)
-  expect_equal(sum(matrix(1:100)), sum(data.frame(1:100)))
-})
-
-test_that("different testing functions work, giving excuse to demonstrate",{
-  expect_identical(1, 1)
-  expect_identical(numeric(1), integer(1))
-  expect_equivalent(numeric(1), integer(1))
-  expect_warning(mean('1'))
-  expect_that(mean('1'), gives_warning("argument is not numeric or logical: returning NA"))
-  expect_warning(mean('1'), "argument is not numeric or logical: returning NA")
-  expect_message(message("a"), "a")
-})
-
-
-

9.1.2 Integration testing

-

Integration tests consist of running the PEcAn workflow in full. -One way to do integration tests is to manually run workflows for a given version of PEcAn, either through the web interface or by manually creating a pecan.xml file. -Such manual tests are an important part of checking PEcAn functionality.

-

Alternatively, the base/workflow/inst/batch_run.R script can be used to quickly run a series of user-specified integration tests without having to create a bunch of XML files. -This script is powered by the PEcAn.workflow::create_execute_test_xml() function, -which takes as input information about the model, meteorology driver, site ID, run dates, and others, -uses these to construct a PEcAn XML file, -and then uses the system() command to run a workflow with that XML.

-

If run without arguments, batch_run.R will try to run the model configurations specified in the base/workflow/inst/default_tests.csv file. -This file contains a CSV table with the following columns:

-
    -
  • model – The name of the model (models.model_name column in BETY)
  • -
  • revision – The version of the model (models.revision column in BETY)
  • -
  • met – The name of the meteorology driver source
  • -
  • site_id – The numeric site ID for the model run (sites.site_id)
  • -
  • pft – The name of the plant functional type to run. If NA, the script will use the first PFT associated with the model.
  • -
  • start_date, end_date – The start and end dates for the model run, respectively. These should be formatted according to ISO standard (YYYY-MM-DD, e.g. 2010-03-16)
  • -
  • sensitivity – Whether or not to run the sensitivity analysis. TRUE means run it, FALSE means do not.
  • -
  • ensemble_size – The number of ensemble members to run. Set this to 1 to do a single run at the trait median.
  • -
  • comment – An string providing some user-friendly information about the run.
  • -
-

The batch_run.R script will run a workflow for every row in the input table, sequentially (for now; eventually, it will try to run them in parallel), -and at the end of each workflow, will perform some basic checks, including whether or not the workflow finished and if the model produced any output. -These results are summarized in a CSV table (by default, a file called test_result_table.csv), with all of the columns as the input test CSV plus the following:

-
    -
  • outdir – Absolute path to the workflow directory.
  • -
  • workflow_complete – Whether or not the PEcAn workflow completed. Note that this is a relatively low bar – PEcAn workflows can complete without having run the model or finished some other steps.
  • -
  • has_jobsh – Whether or not PEcAn was able to write the model’s job.sh script. This is a good indication of whether or not the model’s write.configs step was successful, and may be useful for separating model configuration errors from model execution errors.
  • -
  • model_output_raw – Whether or not the model produced any output files at all. This is just a check to see of the <workflow>/out directory is empty or not. Note that some models may produce logfiles or similar artifacts as soon as they are executed, whether or not they ran even a single timestep, so this is not an indication of model success.
  • -
  • model_output_processed – Whether or not PEcAn was able to post-process any model output. This test just sees if there are any files of the form YYYY.nc (e.g. 1992.nc) in the <workflow>/out directory.
  • -
-

Right now, these checks are not particularly robust or comprehensive, but they should be sufficient for catching common errors. -Development of more, better tests is ongoing.

-

The batch_run.R script can take the following command-line arguments:

-
    -
  • --help – Prints a help message about the script’s arguments
  • -
  • --dbfiles=<path> – The path to the PEcAn dbfiles folder. The default value is ~/output/dbfiles, based on the file structure of the PEcAn VM. Note that for this and all other paths, if a relative path is given, it is assumed to be relative to the current working directory, i.e. the directory from which the script was called.
  • -
  • --table=<path> – Path to an alternate test table. The default is the base/workflow/inst/default_tests.csv file. See preceding paragraph for a description of the format.
  • -
  • --userid=<id> – The numeric user ID for registering the workflow. The default value is 99000000002, corresponding to the guest user on the PEcAn VM.
  • -
  • --outdir=<path> – Path to a directory (which will be created if it doesn’t exist) for storing the PEcAn workflow outputs. Default is batch_test_output (in the current working directory).
  • -
  • --pecandir=<path> – Path to the PEcAn source code root directory. Default is the current working directory.
  • -
  • --outfile=<path> – Full path (including file name) of the CSV file summarizing the results of the runs. Default is test_result_table.csv. The format of the output
  • -
-
-
-

9.1.3 Continuous Integration

-

Every time anyone commits a change to the PEcAn code, the act of pushing to GitHub triggers an automated build and test of the full PEcAn codebase, and all pull requests must report a successful CI build before they will be merged. This will sometimes feel like a burden when the build breaks on an issue that looks trivial, but anything that breaks the build is important enough to fix. It’s much better to find errors early and fix them before they get incorporated into the released PEcAn code.

-

At this writing PEcAn’s CI builds primarily use GitHub Actions and the rest of this section assumes a GitHub Actions.

-

All our GitHub Actions builds run in a containers using different versions of R in parallel. The build will use the latest pecan/depends container for that specific R version. Each night this depends image is rebuild.

-

Each build starts by launching a separate clean virtual machine for each R version and performs roughly the following actions on all of them: -* Compile the source code in the container -- Installs all the R packages that are declared as dependencies in any PEcAn package, as computed by scripts/generate_dependencies.R. -- This will also check to see if any files have been modified during this step -* Run the tests inside the container, and checks to see if they all pass -- This will also check to see if any files have been modified during this step -* Run the doxygen command inside the container -- This will also check to see if any files have been modified during this step -* Run the check command inside the container, and checks if there are any new warnings and/or errors -- Runs package unit tests (the same ones you run locally with make test or devtools::test(pkgname)).
-- As discussed in Unit testing, these tests should run quickly and test individual components in relative isolation. -- Any test that calls the skip_on_ci function will be skipped. This is useful for tests that need to run for a very long time (e.g. large data product downloads) or require resources that aren’t available on Travis (e.g. specific models), but be sure to run these tests locally before pushing your code! -- This will also check to see if any files have been modified during this step -- Any ERROR in the check output will stop the build immediately.
-- If there are no ERRORs, any WARNINGs or NOTEs are compared against a stored historic check result in <package>/tests/Rcheck_reference.log. If the package has no stored reference result, all WARNINGs and NOTEs are considered newly added and reported as build failures. -- If all messages from the current built were also present in the reference result, the check passes. If any messages are newly added, a build failure is reported. -- Each line of the check log is considered a separate message, and the test requires exact matching, so a change from Undocumented arguments in documentation object 'foo': 'x' to Undocumented arguments in documentation object 'foo': 'x', 'y' will be counted as a new warning… and you should fix both of them while you’re at it! -- The idea here is to enforce good coding practice and catch likely errors in all new code while recognizing that we have a lot of legacy code whose warnings need to be fixed as we have time rather than all at once. -- As we fix historic warnings, we will revoke their grandfathered status by removing them from the stored check results, so that they will break the build if they reappear.
-- If your PR reports a failure in pre-existing code that you think ought to be grandfathered, please fix it as part of your PR anyway. It’s frustrating to see tests complain about code you didn’t touch, but the failures all need to be cleaned up eventually and it’s likely easier to fix the error than to figure out how to re-ignore it.
-* Run a simple integration test using SIPNET model -* Create the docker images -- Once your PR is merged, it will push them to DockerHub and github container repository. -* Compiles the PEcAn documentation book (book_source) and the tutorials (documentation/tutorials) and uploads them to the PEcAn website. -- This is only done for commits to the master or develop branch, so changes to in-progress pull requests never change the live documentation until after they are merged.

-

If your build fails and indicates that files have been modified there are a few common causes. It should also list the files that have changes, and what has changed. -* The most common cause is that you forgot to Roxygenize before committing. -* This step will also detect newly added files, e.g. tests improperly writing to the current working directory rather than tempdir() and then failing to clean up after themselves.

-

If any of the actionsreports an error, the build is marked as “failed”. If they all pass, the GitHub actions marks the build as successful and tells the PR that it’s OK to allow your changes to be merged… but the final decision belongs to the human reviewing your code and they might still ask you for other changes!

- -
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/directory-structure.html b/master/directory-structure.html deleted file mode 100644 index 5d3f23def..000000000 --- a/master/directory-structure.html +++ /dev/null @@ -1,918 +0,0 @@ - - - - - - - 9.3 Directory structure | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

9.3 Directory structure

-
-

9.3.1 Overview of PEcAn repository as of PEcAn 1.5.3

- -
pecan/
- +- base/          # Core functions
-    +- all         # Dummy package to load all PEcAn R packages
-    +- db          # Modules for querying the database
-    +- logger      # Report warnings without killing workflows
-    +- qaqc        # Model skill testing and integration testing
-    +- remote      # Communicate with and execute models on local and remote hosts
-    +- settings    # Functions to read and manipulate PEcAn settings files
-    +- utils       # Misc. utility functions
-    +- visualization # Advanced PEcAn visualization module
-    +- workflow    # functions to coordinate analysis steps
- +- book_source/   # Main documentation and developer's guide
- +- CHANGELOG.md   # Running log of changes in each version of PEcAn
- +- docker/        # Experimental replacement for PEcAn virtual machine
- +- documentation  # index_vm.html, references, other misc.
- +- models/        # Wrappers to run models within PEcAn
-    +- ed/         # Wrapper scripts for running ED within PEcAn
-    +- sipnet/     # Wrapper scripts for running SIPNET within PEcAn
-    +- ...         # Wrapper scripts for running [...] within PEcAn
-    +- template/   # Sample wrappers to copy and modify when adding a new model
- +- modules        # Core modules
-    +- allometry
-    +- data.atmosphere
-    +- data.hydrology
-    +- data.land
-    +- meta.analysis
-    +- priors
-    +- rtm
-    +- uncertainty
-    +- ...
- +- scripts        # R and Shell scripts for use with PEcAn
- +- shiny/         # Interactive visualization of model results
- +- tests/         # Settings files for host-specific integration tests
- +- web            # Main PEcAn website files
-
-
-

9.3.2 Generic R package structure:

-

see the R development wiki for more information on writing code and adding data.

-
 +- DESCRIPTION    # short description of the PEcAn library
- +- R/             # location of R source code
- +- man/           # Documentation (automatically compiled by Roxygen)
- +- inst/          # files to be installed with package that aren't R functions
-    +- extdata/    # misc. data files (in misc. formats)
- +- data/          # data used in testing and examples (saved as *.RData or *.rda files)
- +- NAMESPACE      # declaration of package imports and exports (automatically compiled by Roxygen)
- +- tests/         # PEcAn testing scripts
-   +- testthat/    # nearly all tests should use the testthat framework and live here
- -
-
- - - - -
- - -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/docker-build-images.html b/master/docker-build-images.html deleted file mode 100644 index 1d9bae519..000000000 --- a/master/docker-build-images.html +++ /dev/null @@ -1,986 +0,0 @@ - - - - - - - 25.6 Building and modifying images | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

25.6 Building and modifying images

-

The only other section on this page is: -Local development and testing with Docker

-

For general use, it is sufficient to use the pre-built PEcAn images hosted on Docker Hub (see Docker quickstart). -However, there are cases where it makes sense to re-build the Docker images locally. -The following is a list of PEcAn-specific images and reasons why you would want to rebuild them locally:

-
    -
  • pecan/depends – Rebuild if: -
      -
    • You modify the docker/depends/Dockerfile
    • -
    • You introduce new system dependencies (i.e. things that need to be installed with apt-get)
    • -
    • You introduce new R package dependencies, and you want those R package installations to be cached during future builds. For packages with fast build times, it may be fine to let them be installed as part of PEcAn’s standard build process (i.e. make).
    • -
  • -
  • pecan/base – Rebuild if: -
      -
    • You built a new version of pecan/depends (on which pecan/base depends)
    • -
    • You modify the docker/base/Dockerfile
    • -
    • You made changes to the PEcAn R package source code, the Makefile, or web/workflow.R. -
        -
      • NOTE that changes to the web interface code affect pecan/web, not pecan/base
      • -
    • -
  • -
  • pecan/executor – Rebuild if: -
      -
    • You built a new version of pecan/base (on which pecan/executor depends) and/or, pecan/depends (on which pecan/base depends)
    • -
    • You modified the docker/executor/Dockerfile
    • -
    • You modified the RabbitMQ Python script (e.g. docker/receiver.py)
    • -
  • -
  • pecan/web – Rebuild if you modified any of the following: -
      -
    • docker/web/Dockerfile
    • -
    • The PHP/HTML/JavaScript code for the PEcAn web interface in web/ (except web/workflow.R – that goes in pecan/base)
    • -
    • docker/config.docker.php (the config.php file for Docker web instances)
    • -
    • documentation/index_vm.html (the documentation HTML website)
    • -
    • NOTE: Because changes to this code are applied instantly (i.e. do not require compilation or installation), a more effective way to do local development may be to mount the web/ or other relevant folders as a volume onto the pecan/web container.
    • -
  • -
-

The easiest way to quickly re-build all of the images is using the docker.sh script in the PEcAn source code root directory. -This script will build all of the docker images locally on your machine, and tag them as latest. -This will not build the pecan/depends image by default because that takes considerably longer. -However, you can force the script to build pecan/depends as well by setting the DEPEND environment variable to 1 (i.e. DEPEND=1 ./docker.sh). -The following instructions provide details on how to build each image individually.

-

To build an image locally, use the docker build command as described below. -For more details, see docker build --help or the online Docker build documentation.

-

First, in a terminal window, navigate (cd) into the PEcAn source code root directory. -From there, the general syntax for building an image looks like the following:

-
docker build -t pecan/<image name>:<image version> -f docker/base/Dockerfile.<image name> .
-

For instance, to build a local version of the pecan/depends:latest image, you would run:

-
docker build -t pecan/depends:latest -f docker/depends/Dockerfile .
-

The breakdown of this command is as follows:

-
    -
  • docker build – This is the core command. -The standard syntax is docker build [OPTIONS] <PATH>, where <PATH> refers to the directory to be used as the “build context”. -The “build context” is the working directory assumed by the Dockerfiles. -In PEcAn, this is always the PEcAn source code root directory, which allows Dockerfiles to use instructions such as COPY web/workflow.R /work/. -In this example, the <PATH> is set to the current working directory, i.e. . because we are already in the PEcAn root directory. -If you were located in a different directory, you would have to provide a path to the PEcAn source code root directory. -Also, by default, docker build will look for a Dockerfile located at <PATH>/Dockerfile, but this is modified by the -f option described below.

  • -
  • -t pecan/depends:latest – The -t/--tag option specifies how the image will be labeled. -By default, Docker only defines unique image IDs, which are hexidecimal strings that are unintuitive and hard to remember. -Tags are useful for referring to specific images in a human-readable way. -Note that the same unique image can have multiple tags associated with it, so it is possible for, e.g. pecan/depends:latest, pecan/depends:custom, and even mypecan/somethingelse:20.0 to refer to the same exact image. -To see a table of all local images, including their tags and IDs, run docker image ls.

    -
      -
    • NOTE: PEcAn’s docker-compose.yml can be configured via the PECAN environment variable to point at different versions of PEcAn images. -By default, it points to the :latest versions of all images. -However, if you wanted to, for instance, build :local images corresponding to your local source code and then run that version of PEcAn, you would run:
    • -
    -
    PECAN=local docker-compose -p pecan up -d
    -

    This is an effective way to do local development and testing of different PEcAn versions, as described below.

  • -
  • -f docker/depends/Dockerfile – The -f/--file tag is used to provide an alternative location and file name for the Dockerfile.

  • -
-
-

25.6.1 Local development and testing with Docker

-

The following is an example of one possible workflow for developing and testing PEcAn using local Docker images. -The basic idea is to mount a local version of the PEcAn source code onto a running pecan/executor image, and then send a special “rebuild” RabbitMQ message to the container to trigger the rebuild whenever you make changes. -NOTE: All commands assume you are working from the PEcAn source code root directory.

-
    -
  1. In the PEcAn source code directory, create a docker-compose.override.yml file with the following contents.:

    -
    version: "3"
    -services:
    -  executor:
    -    volumes:
    -      - .:/pecan
    -

    This will mount the current directory . to the /pecan directory in the executor container. -The special docker-compose.override.yml file is read automatically by docker-compose and overrides or extends any instructions set in the original docker-compose.yml file. -It provides a convenient way to host server-specific configurations without having to modify the project-wide (and version-controlled) default configuration. -For more details, see the Docker Compose documentation.

  2. -
  3. Update your PEcAn Docker stack with docker-compose up -d. -If the stack is already running, this should only restart your executor instance while leaving the remaining containers running.

  4. -
  5. To update to the latest local code, run ./scripts/docker_rebuild.sh. -Under the hood, this uses curl to post a RabbitMQ message to a running Docker instance. -By default, the scripts assumes that username and password are both guest and that the RabbitMQ URL is http://rabbitmq.pecan.localhost/. -All of these can be customized by setting the environment variables RABBITMQ_USER, RABBITMQ_PASSWORD, and RABBITMQ_URL, respectively (or running the script prefixed with those variables, e.g. RABBITMQ_USER=carya RABBITMQ_PASSWORD=illinois ./scripts/docker_rebuild.sh). -This step can be repeated whenever you want to trigger a rebuild of the local code.

  6. -
-

NOTE: The updates with this workflow are specific to the running container session; restarting the executor container will revert to the previous versions of the installed packages. -To make persistent changes, you should re-build the pecan/base and pecan/executor containers against the current version of the source code.

-

NOTE: The mounted PEcAn source code directory includes everything in your local source directory, including installation artifacts used by make. -This can lead to two common issues: -- Any previous make cache files (stuff in the .install, .docs, etc. directories) persist across container instances, even though the installed packages may not. To ensure a complete build, it’s a good idea to run make clean on the host machine to remove these artifacts. -- Similarly, any installation artifacts from local builds will be carried over to the build. In particular, be wary of packages with compiled code, such as modules/rtm (PEcAnRTM) – the compiled .o, .so, .mod, etc. files from compilation of such packages will carry over into the build, which can cause conflicts if the package was also built locally.

-

The docker-compose.override.yml is useful for some other local modifications. -For instance, the following adds a custom ED2 “develop” model container.

-
services:
-  # ...
-  ed2devel:
-    image: pecan/model-ed2-develop:latest
-    build:
-      context: ../ED2  # Or wherever ED2 source code is found
-    networks:
-      - pecan
-    depends_on:
-      - rabbitmq
-    volumes:
-      - pecan:/data
-    restart: unless-stopped
-

Similarly, this snippet modifies the pecan network to use a custom IP subnet mask. -This is required on the PNNL cluster because its servers’ IP addresses often clash with Docker’s default IP mask.

-
networks:
-  pecan:
-    ipam:
-      config:
-        - subnet: 10.17.1.0/24
- -
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/docker-index.html b/master/docker-index.html deleted file mode 100644 index 99df1d6f6..000000000 --- a/master/docker-index.html +++ /dev/null @@ -1,873 +0,0 @@ - - - - - - - 25 Docker | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

25 Docker

-

This chapter describes the PEcAn Docker container infrastructure. -It contains the following sections:

- - -
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/docker-intro.html b/master/docker-intro.html deleted file mode 100644 index cc8f3a93f..000000000 --- a/master/docker-intro.html +++ /dev/null @@ -1,952 +0,0 @@ - - - - - - - 25.1 Introduction to Docker? | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

25.1 Introduction to Docker?

- -
-

25.1.1 What is Docker?

-

For a quick and accessible introduction to Docker, we suggest this YouTube video: Learn Docker in 12 Minutes.

-

For more comprehensive Docker documentation, we refer you to the Docker documentation website.

-

For a useful analogy for Docker containerization, we refer you to the webcomic xkcd.

-

Docker is a technology for encapsulating software in “containers”, somewhat similarly to virtual machines. -Like virtual machines, Docker containers facilitate software distribution by bundling the software with all of its dependencies in a single location. -Unlike virtual machines, Docker containers are meant to only run a single service or process and are build on top of existing services provided by the host OS (such as disk access, networking, memory management etc.).

-

In Docker, an image refers to a binary snapshot of a piece of software and all of its dependencies. -A container refers to a running instance of a particular image. -A good rule of thumb is that each container should be responsible for no more than one running process. -A software stack refers to a collection of containers, each responsible for its own process, working together to power a particular application. -Docker makes it easy to run multiple software stacks at the same time in parallel on the same machine. -Stacks can be given a unique name, which is passed along as a prefix to all their containers. -Inside these stacks, containers can communicate using generic names not prefixed with the stack name, making it easy to deploy multiple stacks with the same internal configuration. -Containers within the same stack communicate with each other via a common network. -Like virtual machines or system processes, Docker stacks can also be instructed to open specific ports to facilitate communication with the host and other machines.

-

The PEcAn database BETY provides an instructive case-study. -BETY is comprised of two core processes – a PostgreSQL database, and a web-based front-end to that database (Apache web server with Ruby on Rails). -Running BETY as a “Dockerized” application therefore involves two containers – one for the PostgreSQL database, and one for the web server. -We could build these containers ourselves by starting from a container with nothing but the essentials of a particular operating system, but we can save some time and effort by starting with an existing image for PostgreSQL from Docker Hub. -When starting a Dockerized BETY, we start the PostgreSQL container first, then start the BETY container telling it how to communicate with the PostgreSQL container. -To upgrade an existing BETY instance, we stop the BETY container, download the latest version, tell it to upgrade the database, and re-start the BETY container. -There is no need to install new dependencies for BETY since they are all shipped as part of the container.

-

The PEcAn Docker architecture is designed to facilitate installation and maintenance on a variety of systems by eliminating the need to install and maintain complex system dependencies (such as PostgreSQL, Apache web server, and Shiny server). -Furthermore, using separate Docker containers for each ecosystem model helps avoid clashes between different software version requirements of different models (e.g. some models require GCC <5.0, while others may require GCC >=5.0).

-

The full PEcAn Docker stack is described in more detail in the next section.

-
-
-

25.1.2 Working with Docker

-

To run an image, you can use the Docker command line interface. -For example, the following runs a PostgreSQL image based on the pre-existing PostGIS image by mdillon:

-
docker run \
-    --detach \
-    --rm \
-    --name postgresql \
-    --network pecan \
-    --publish 9876:5432 \
-    --volume ${PWD}/postgres:/var/lib/postgresql/data \
-    mdillon/postgis:9.6-alpine
-

This will start the PostgreSQL+PostGIS container. -The following options were used:

-
    -
  • --detach makes the container run in the background.
  • -
  • --rm removes the container when it is finished (make sure to use the volume below).
  • -
  • --name the name of the container, also the hostname of the container which can be used by other docker containers in the same network inside docker.
  • -
  • --network pecan the network that the container should be running in, this leverages of network isolation in docker and allows this container to be connected to by others using the postgresql hostname.
  • -
  • --publish exposes the port to the outside world, this is like ssh, and maps port 9876 to port 5432 in the docker container
  • -
  • --volume maps a folder on your local machine to the machine in the container. This allows you to save data on your local machine.
  • -
  • mdillon/postgis:9.6-alpine is the actual image that will be run, in this case it comes from the group/person mdillon, the container is postgis and the version 9.6-alpine (version 9.6 build on alpine linux).
  • -
-

Other options that might be used:

-
    -
  • --tty allocate a pseudo-TTY to send stdout and stderr back to the console.
  • -
  • --interactive keeps stdin open so the user can interact with the application running.
  • -
  • --env sets environment variables, these are often used to change the behavior of the docker container.
  • -
-

To see a list of all running containers you can use the following command:

-
docker ps
-

To see the log files of this container you use the following command (you can either use their name or id as returned by docker ps). The -f flag will follow the stdout/stderr from the container, use Ctrl-C to stop following the stdout/stderr.

-
docker logs -f postgresql
-

To stop a running container use:

-
docker stop postgresql
-

Containers that are running in the foreground (without the --detach) can be stopped by pressing Ctrl-C. Any containers running in the background (with --detach) will continue running until the machine is restarted or the container is stopped using docker stop.

-
-
-

25.1.3 docker-compose

-

For a quick introduction to docker-compose, we recommend the following YouTube video: Docker Compose in 12 Minutes.

-

The complete docker-compose references can be found on the Docker documentation website.

-

docker-compose provides a convenient way to configure and run a multi-container Docker stack. -Basically, a docker-compose setup consists of a list of containers and their configuration parameters, which are then internally converted into a bunch of docker commands. -To configure BETY as described above, we can use a docker-compose.yml file like the following:

-
version: "3"
-services:
-  postgres:
-    image: mdillon/postgis:9.5
-  bety:
-    image: pecan/bety
-    depends_on:
-      - postgres
-

This simple file allows us to bring up a full BETY application with both database and BETY application. The BETY app will not be brought up until the database container has started.

-

You can now start this application by changing into the same directory as the docker-compose.yml file (cd /path/to/file) and then running:

-
docker-compose up
-

This will start the application, and you will see the log files for the 2 different containers.

- -
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/docker-migrate.html b/master/docker-migrate.html deleted file mode 100644 index 1d1322c6c..000000000 --- a/master/docker-migrate.html +++ /dev/null @@ -1,892 +0,0 @@ - - - - - - - 25.8 Migrating PEcAn from VM to Docker | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

25.8 Migrating PEcAn from VM to Docker

-

This document assumes you have read through the Introduction to Docker as well as Docker quickstart and have docker running on the VM.

-

This document will slowly replace each of the components with the appropriate docker images. At then end of this document you should be able to use the docker-compose command to bring up the full docker stack as if you had started with this origianally.

-
-

25.8.1 Running BETY as a docker container

-

This will replace the BETY application running on the machine with a docker image. This will assume you still have the database running on the local machine and the only thing we replace is the BETY application.

-

If you are running systemd (Ubuntu 16.04 or Centos 7) you can copy the following file to /etc/systemd/system/bety.service (replace LOCAL_SERVER=99 with your actual server). If you have postgres running on another server replace 127.0.0.1 with the actual ip address of the postgres server.

-
[Unit]
-Description=BETY container
-After=docker.service
-
-[Service]
-Restart=always
-ExecStart=/usr/bin/docker run -t --rm --name bety --add-host=postgres:127.0.0.1 --network=host --env RAILS_RELATIVE_URL_ROOT=/bety --env LOCAL_SERVER=99 pecan/bety
-ExecStop=/usr/bin/docker stop -t 2 bety
-
-[Install]
-WantedBy=local.target
-

At this point we can enable the bety service (this only needs to be done once). First we need to tell systemd a new service is available using systemctl daemon-reload. Next we enable the BETY service so it will restart automatically when the machine reboots, using systemctl enable bety. Finally we can start the BETY service using systemctl start bety. At this point BETY is running as a docker container on port 8000. You can see the log messages using journalctl -u bety.

-

Next we need to modify apache configuration files. The file /etc/apache2/conf-enabled/bety.conf will be replaced with the following content:

-
ProxyPass                /bety/ http://pecan.localhost/bety/
-ProxyPassReverse         /bety/ http://pecan.localhost/bety/
-RedirectMatch permanent ^/bety$ /bety/
-

Once this modified we can restart apache using systemctl restart apache2. At this point BETY is running in a container and is accessable trough the webserver at http://server/bety/.

-

To upgrade to a new version of BETY you can now use the docker commands. You can use the following commands to stop BETY, pull the latest image down, migrate the database (you made a backup correct?) and start BETY again.

-
systemctl stop bety
-docker pull pecan/bety:latest
-docker run -ti --rm --add-host=postgres:127.0.0.1 --network=host --env LOCAL_SERVER=99 pecan/bety migrate
-systemctl start bety
-

Once you are satisfied with the migration of BETY you can remove the bety folder as well as any ruby binaries you have installed.

- -
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/docker-quickstart.html b/master/docker-quickstart.html deleted file mode 100644 index 75c834169..000000000 --- a/master/docker-quickstart.html +++ /dev/null @@ -1,888 +0,0 @@ - - - - - - - 25.2 Quick-start docker install | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

25.2 Quick-start docker install

-
git clone git@github.com/pecanproject/pecan
-cd pecan
-
-# start database
-docker-compose -p pecan up -d postgres
-
-# add example data (first time only)
-docker-compose run --rm bety initialize
-docker run -ti --rm --network pecan_pecan --volume pecan_pecan:/data --env FQDN=docker pecan/data:develop
-
-# start PEcAn
-docker-compose -p pecan up -d
-
-# run a model
-curl -v -X POST \
-    -F 'hostname=docker' \
-    -F 'modelid=1000000014' \
-    -F 'sitegroupid=1' \
-    -F 'siteid=772' \
-    -F 'sitename=Niwot Ridge Forest/LTER NWT1 (US-NR1)' \
-    -F 'pft[]=temperate.coniferous' \
-    -F 'start=2004/01/01' \
-    -F 'end=2004/12/31' \
-    -F 'input_met=5000000005' \
-    -F 'email=' \
-    -F 'notes=' \
-    'http://pecan.localhost/pecan/04-runpecan.php'
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/docker-troubleshooting.html b/master/docker-troubleshooting.html deleted file mode 100644 index 75dec906b..000000000 --- a/master/docker-troubleshooting.html +++ /dev/null @@ -1,878 +0,0 @@ - - - - - - - 25.7 Troubleshooting Docker | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

25.7 Troubleshooting Docker

-
-

25.7.1 “Package not available” while building images

-

PROBLEM: Packages fail to install while building pecan/depends and/or pecan/base with an error like the following:

-
Installing package into ‘/usr/local/lib/R/site-library’
-(as ‘lib’ is unspecified)
-Warning: unable to access index for repository <URL>:
- cannot open URL '<URL>'
-Warning message:
-package ‘<PACKAGE>’ is not available (for R version 3.5.1)
-

CAUSE: This can sometimes happen if there are problems with the RStudio Package manager, which is the default repository for the rocker/tidyverse containers. -See GitHub issues rocker-org/rocker-versioned#102 and #58.

-

WORKAROUND: Add the following line to the depends and/or base Dockerfiles before (i.e. above) any commands that install R packages (e.g. Rscript -e "install.packages(...)"):

-
RUN echo "options(repos = c(CRAN = 'https://cran.rstudio.org'))" >> /usr/local/lib/R/etc/Rprofile.site
-

This will set the default repository to the more reliable (albeit, more up-to-date; beware of breaking package changes!) RStudio CRAN mirror. -Then, build the image as usual.

- -
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/download-and-compile-pecan.html b/master/download-and-compile-pecan.html deleted file mode 100644 index 2940b7b61..000000000 --- a/master/download-and-compile-pecan.html +++ /dev/null @@ -1,899 +0,0 @@ - - - - - - - 9.2 Download and Compile PEcAn | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

9.2 Download and Compile PEcAn

-

Set R_LIBS_USER

-

CRAN Reference

-
# point R to personal lib folder
-echo 'export R_LIBS_USER=${HOME}/R/library' >> ~/.profile
-source ~/.profile
-mkdir -p ${R_LIBS_USER}
-
-

9.2.1 Download, compile and install PEcAn from GitHub

-
# download pecan
-cd
-git clone https://github.com/PecanProject/pecan.git
-
-# compile pecan
-cd pecan
-make
-

For more information on the capabilities of the PEcAn Makefile, check out our section on Updating PEcAn.

-

Following will run a small script to setup some hooks to prevent people from using the pecan demo user account to check in any code.

-
# prevent pecan user from checking in code
-./scripts/create-hooks.sh
-
-
-

9.2.2 PEcAn Testrun

-

Do the run, this assumes you have installed the BETY database, sites tar file and SIPNET.

-
# create folder
-cd
-mkdir testrun.pecan
-cd testrun.pecan
-
-# copy example of pecan workflow and configuration file
-cp ../pecan/tests/pecan32.sipnet.xml pecan.xml
-cp ../pecan/scripts/workflow.R workflow.R
-
-# exectute workflow
-rm -rf pecan
-./workflow.R pecan.xml
-

NB: pecan.xml is configured for the virtual machine, you will need to change the field from ‘/home/carya/’ to wherever you installed your ‘sites’, usually $HOME

- -
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/download-gfdl.html b/master/download-gfdl.html deleted file mode 100644 index be6910b81..000000000 --- a/master/download-gfdl.html +++ /dev/null @@ -1,862 +0,0 @@ - - - - - - - 15.15 Download GFDL | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

15.15 Download GFDL

-

The Downlad.GFDL function assimilates 3 hour frequency CMIP5 outputs generated by multiple GFDL models. GFDL developed several distinct modeling streams on the timescale of CMIP5 and AR5. These models include CM3, ESM2M and ESM2G with a spatial resolution of 2 degrees latitude by 2.5 degrees longitude. Each model has future outputs for the AR5 Representative Concentration Pathways ranging from 2006-2100.

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/dplyr.html b/master/dplyr.html deleted file mode 100644 index bb8d251ba..000000000 --- a/master/dplyr.html +++ /dev/null @@ -1,1034 +0,0 @@ - - - - - - - 9 dplyr | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

9 dplyr

-

When running devtools::check() a common warning relating to dplyr code is “no visible binding for global variable ‘x’”

-

In data-masking situations (e.g. mutate(), filter()), you can eliminate this warning by using the .data pronoun. For example, instead of df %>% mutate(newvar = oldvar + 2), use df %>% mutate(newvar = .data$oldvar + 2).

-

In tidy-select situations (e.g. select(), rename()), you can eliminate this warning by using strings instead of naked column names. For example, instead of df %>% select(y) use df %>% select("y"). Using .data inside of select() is deprecated as of tidyselect v1.2.0

- -
-

9.0.1 Logging

-

During development we often add many print statements to check to see how the code is doing, what is happening, what intermediate results there are etc. When done with the development it would be nice to turn this additional code off, but have the ability to quickly turn it back on if we discover a problem. This is where logging comes into play. Logging allows us to use “rules” to say what information should be shown. For example when I am working on the code to create graphs, I do not have to see any debugging information about the SQL command being sent, however trying to figure out what goes wrong during a SQL statement it would be nice to show the SQL statements without adding any additional code.

-

PEcAn provides a set of logger.* functions that should be used in place of base R’s stop, warn, print, and similar functions. The logger functions make it easier to print to a system log file, and to control the level of output produced by PEcAn.

-
    -
  • The file test.logger.R provides descriptive examples
  • -
  • This query provides an current overview of functions that use logging
  • -
  • Logger functions and their corresponding levels (in order of increasing level):
  • -
  • logger.debug ("DEBUG") – Low-level diagnostic messages that are hidden by default. Good examples of this are expanded file paths and raw results from database queries or other analyses.
  • -
  • logger.info ("INFO") – Informational messages that regular users may want to see, but which do not indicate anything unexpected. Good examples of this are progress updates updates for long-running processes, or brief summaries of queries or analyses.
  • -
  • logger.warn ("WARN") – Warning messages about issues that may lead to unexpected but valid results. Good examples of this are interactions between arguments that lead to some arguments being ignored or removal of missing or extreme values.
  • -
  • logger.error ("ERROR") – Error messages from which PEcAn has some capacity to recover. Unless you have a very good reason, we recommend avoiding this in favor of either logger.severe to actually stop execution or logger.warn to more explicitly indicate that the problem is not fatal.
  • -
  • logger.severe – Catastrophic errors that warrant immediate termination of the workflow. This is the only function that actually stops R’s execution (via stop).
  • -
  • The logger.setLevel function sets the level at which a message will be printed. For instance, logger.setLevel("WARN") will suppress logger.info and logger.debug messages, but will print logger.warn and logger.error messages. logger.setLevel("OFF") suppresses all logger messages.
  • -
  • To print all messages to console, use logger.setUseConsole(TRUE)
  • -
- -
-
-

9.0.2 Package Data

-
-

9.0.2.1 Summary:

-

Files with the following extensions will be read by R as data:

-
    -
  • plain R code in .R and .r files are sourced using source()
  • -
  • text tables in .tab, .txt, .csv files are read using read() -** objects in R image files: .RData, .rda are loaded using load()
  • -
  • capitalization matters
  • -
  • all objects in foo.RData are loaded into environment
  • -
  • pro: easiset way to store objects in R format
  • -
  • con: format is application (R) specific
  • -
-

Details are in ?data, which is mostly a copy of Data section of -Writing R -Extensions.

-
-
-

9.0.2.2 Accessing data

-

Data in the [data] directory will be accessed in the following ways,

-
    -
  • efficient way: (especially for large data sets) using the data -function:
  • -
-
data(foo) # accesses data with, e.g. load(foo.RData), read(foo.csv), or source(foo.R) 
-
    -
  • easy way: by adding the following line to the package DESCRIPTION: -note: this should be used with caution or it can cause difficulty as discussed in redmine issue #1118
  • -
-
LazyData: TRUE
-

From the R help page:

-

Currently, a limited number of data formats can be accessed using the data function by placing one of the following filetypes in a packages’ data directory: -* files ending .R or .r are source()d in, with the R working -directory changed temporarily to the directory containing the respective -file. (data ensures that the utils package is attached, in case it -had been run via utils::data.) -* files ending .RData or .rda are load()ed. -* files ending .tab, .txt or .TXT are read using read.table(..., header = TRUE), and hence result in a data frame. -* files ending .csv or .CSV are read using read.table(..., header = TRUE, sep = ';'), and also result in a data frame.

-

If your data does not fall in those 4 categories, or you can use the -system.file function to get access to the data:

-
system.file("data", "ed.trait.dictionary.csv", package="PEcAn.utils")
-[1] "/home/kooper/R/x86_64-pc-linux-gnu-library/2.15/PEcAn.utils/data/ed.trait.dictionary.csv"
-

The arguments are folder, filename(s) and then package. It will return -the fully qualified path name to a file in a package, in this case it -points to the trait data. This is almost the same as the data function, -however we can now use any function to read the file, such as read.csv -instead of read.csv2 which seems to be the default of data. This also -allows us to store arbitrary files in the data folder, such as the the -bug file and load it when we need it.

-
-
9.0.2.2.1 Examples of data in PEcAn packages
-
    -
  • outputs: [/modules/uncertainties/data/output.RData]
  • -
  • parameter samples [/modules/uncertainties/data/samples.RData]
  • -
- -
-
-
-
-

9.0.3 Documenting functions using roxygen2

-

This is the standard method for documenting R functions in PEcAn. -For detailed instructions, see one of the following resources:

- -

Below is a complete template for a Roxygen documentation block. -Note that roxygen lines start with #':

-
#' Function title, in a few words
-#'
-#' Function description, in 2-3 sentences.
-#'
-#' (Optional) Package details.
-#'
-#' @param argument_1 A description of the argument
-#' @param argument_2 Another argument to the function
-#' @return A description of what the function returns.
-#'
-#' @author Your name <your_email@email.com>
-#' @examples
-#' \dontrun{
-#'   # This example will NOT be run by R CMD check.
-#'   # Useful for long-running functions, or functions that
-#'   # depend on files or values that may not be accessible to R CMD check.
-#'   my_function("~/user/my_file")
-#'}
-# # This example WILL be run by R CMD check
-#' my_function(1:10, argument_2 = 5)
-## ^^ A few examples of the function's usage
-#' @export
-# ^^ Whether or not the function will be "exported" (made available) to the user.
-# If omitted, the function can only be used inside the package.
-my_function <- function(argument_1, argument_2) {...}
-

Here is a complete example from the PEcAn.utils::days_in_year() function:

-
#' Number of days in a year
-#'
-#' Calculate number of days in a year based on whether it is a leap year or not.
-#'
-#' @param year Numeric year (can be a vector)
-#' @param leap_year Default = TRUE. If set to FALSE will always return 365
-#'
-#' @author Alexey Shiklomanov
-#' @return integer vector, all either 365 or 366
-#' @export
-#' @examples
-#' days_in_year(2010)  # Not a leap year -- returns 365
-#' days_in_year(2012)  # Leap year -- returns 366
-#' days_in_year(2000:2008)  # Function is vectorized over years
-days_in_year <- function(year, leap_year = TRUE) {...}
-

To update documentation throughout PEcAn, run make document in the PEcAn root directory. -Make sure you do this before opening a pull request – -PEcAn’s automated testing (Travis) will check if any documentation is out of date and will throw an error like the following if it is:

-
These files were changed by the build process:
-{...}
-
-

9.0.3.1 Updating to a new Roxygen version

-

For consistency across packages and machines, all PEcAn developers need to compile documentation with the same version of Roxygen. Roxygen itself will check for this and refuse to rebuild a package that was last touched by a newer version of Roxygen, but the warning it gives is very quiet and easy to miss. We take a louder approach by hardcoding the expected Roxygen version into PEcAn’s Makefile and throwing a build failure if the installed Roxygen is not an exact match.

-

When it is time for everyone to update to a newer Roxygen, follow the same procedure we used when updating from 7.2.3 to 7.3.1, replacing version strings as appropriate:

-
    -
  • Before starting, work with the team to merge/close as many existing PRs as feasible – this process touches a lot of files and is likely to create merge conflicts in other PRs.
  • -
  • Edit the Makefile to change EXPECTED_ROXYGEN_VERSION := 7.2.3 to EXPECTED_ROXYGEN_VERSION := 7.3.1.
  • -
  • Run make clean && make document to be sure Roxygen has been run on all packages.
  • -
  • Check the console output for warnings from Roxygen, and fix them as needed. New versions often get pickier about formatting issues that used to be considered minor.
  • -
  • Run ./scripts/generate_dependencies.R to update the version of Roxygen recorded as a Docker dependency.
  • -
  • Grep the PEcAn folder for the string 7.2.3 to make sure no references were missed. -
      -
    • e.g. this time I found a remaining RoxygenNote: 7.2.3 in models/cable/DESCRIPTION – Make currently skips cable, so I redocumented it manually.
    • -
  • -
  • Review all changes. -
      -
    • The changes should mostly just consist of updated RoxygenNote: lines in all the DESCRIPTION files.
    • -
    • In all cases but extra-double-specially if any NAMESPACE files change, make sure you understand what happened rather than blindly committing the changes. Usually the new version is an improvement, but this is the time to check.
    • -
  • -
  • Once all looks good, commit and push.
  • -
  • Make a loud announcement, e.g. on Slack, to tell all developers to update roxygen2 on their machines as soon as the PR is merged.
  • -
- -
-
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/editing-records.html b/master/editing-records.html deleted file mode 100644 index 8a8dec46f..000000000 --- a/master/editing-records.html +++ /dev/null @@ -1,874 +0,0 @@ - - - - - - - 20.7 Editing records | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

20.7 Editing records

-
    -
  • Models
  • -
  • Species
  • -
  • PFTs
  • -
  • Traits
  • -
  • Inputs
  • -
  • DB files
  • -
  • Variables
  • -
  • Formats
  • -
  • (Link each section to relevant Bety tables)
  • -
- -
- -
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/ensemble-analysis.html b/master/ensemble-analysis.html deleted file mode 100644 index f75d72f2a..000000000 --- a/master/ensemble-analysis.html +++ /dev/null @@ -1,865 +0,0 @@ - - - - - - - 23.8 Ensemble Analysis | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

23.8 Ensemble Analysis

-
-

23.8.1 run.ensemble.analysis()

-

This module makes some simple graphs of the ensemble output. Open ensemble.analysis.pdf to view the ensemble prediction as both a histogram and a boxplot. ensemble.ts.pdf provides a timeseries plot of the ensemble mean, meadian, and 95% CI

-
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/era5.html b/master/era5.html deleted file mode 100644 index 569f1238d..000000000 --- a/master/era5.html +++ /dev/null @@ -1,867 +0,0 @@ - - - - - - - 15.12 ERA5 | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

15.12 ERA5

-

Scale: Global

-

Resolution: 3 hrs and 31 km

-

Availability: 1950-present

-

Notes:

-

It’s important to know that the raw ERA5 tiles needs to be downloaded and registered in the database first. Inside the inst folder in the data.atmosphere package there are R files for downloading and registering files in the BETY. However, it assumes that you have registered and setup your API requirements. Check out how to setup your API [here] (https://confluence.ecmwf.int/display/CKB/How+to+download+ERA5#HowtodownloadERA5-3-DownloadERA5datathroughtheCDSAPI). -In the inst folder you can find two files (ERA5_db_register.R and ERA5_USA_download.R). If you setup your ecmwf account as it’s explained in the link above, ERA5_USA_download.R will help you to download all the tiles with all the variables required for pecan extract.nc.ERA5 function to generate pecan standard met files. Besides installing the required packages for this file, it should work from top to bottom with no problem. After downloading the tiles, there is simple script in ERA5_db_register.R which helps you register your tiles in the bety. met.process later on uses that entery to find the required tiles for extracting met data for your sites. There are important points about this file. 1- Make sure you don’t change the site id in the script (which is the same the ParentSite in ERA5 registeration xml file). 2- Make sure the start and end date in that script matches the downloaded tiles. Set your ERA5.files.path to where you downloaded the tiles and then the rest of the script should be working fine.

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/esm2m-esm2g.html b/master/esm2m-esm2g.html deleted file mode 100644 index 5a7c09631..000000000 --- a/master/esm2m-esm2g.html +++ /dev/null @@ -1,931 +0,0 @@ - - - - - - - 15.17 ESM2M & ESM2G | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

15.17 ESM2M & ESM2G

-

Two new models representing ocean physics with alternative numerical frameworks to explore the implications of some of the fundamental assumptions embedded in these models. Both ESM2M and ESM2G utilize a more advanced land model, LM3, than was available in ESM2.1 including a variety of enhancements (Milly et al., in prep). GFDL’s CMIP5 experiments with Earth System Models included many of the integrations found in the long-term CMIP5 experimental design. The ESMs, by design, close the carbon cycle and are used to study the impact of climate change on ecosystems, ecosystem changes on climate and human activities on ecosystems.

-

For more information please navigate here

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/master/example-met-conversion-wrapper-function.html b/master/example-met-conversion-wrapper-function.html deleted file mode 100644 index 9eab71cc4..000000000 --- a/master/example-met-conversion-wrapper-function.html +++ /dev/null @@ -1,900 +0,0 @@ - - - - - - - 20.2 Example met conversion wrapper function | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

20.2 Example met conversion wrapper function

-

met2model.MODEL <- function(in.path, in.prefix, outfolder, start_date, end_date){ -myMetScript <- system.file(“inst/met2model.MODEL.sh”, “PEcAn.MODEL”) -system(paste(myMetScript, file.path(in.path, in.prefix), outfolder, start_date, end_date)) -}

-

would execute the following at the Linux command line

-

inst/met2model.MODEL.sh in.path/in.prefix outfolder start_date end_date `

-
-

20.2.0.1 DESCRIPTION

-

Within the module folder open the DESCRIPTION file and change the package name to PEcAn.MODEL. Fill out other fields such as Title, Author, Maintainer, and Date.

-
-
-

20.2.0.2 NAMESPACE

-

Open the NAMESPACE file and change all instances of MODEL to the name of your model. If you are not going to implement one of the optional modules (described below) at this time then you will want to comment those out using the pound sign #. For a complete description of R NAMESPACE files see here. If you create additional functions in your R package that you want to be used make sure you include them in the NAMESPACE as well (internal functions don’t need to be declared)

-
-
-

20.2.0.3 Building the package

-

Once the package is defined you will then need to add it to the PEcAn build scripts. From the root of the pecan directory, go into the scripts folder and open the file build.sh. Within the section of code that includes PACKAGES= add model/MODEL to the list of packages to compile. If, in writing your module, you add any other R packages to the system you will want to make sure those are listed in the DESCRIPTION and in the script scripts/install.dependencies.R. Next, from the root pecan directory open all/DESCRIPTION and add your model package to the Suggests: list.

-

At any point, if you want to check if PEcAn can build your MODEL package successfully, just go to the linux command prompt and run scripts/build.sh. You will need to do this before the system can use these packages.

-
-
-

20.2.0.4 write.config.MODEL (required)

-

This module performs two primary tasks. The first is to take the list of parameter values and model input files that it receives as inputs and write those out in whatever format(s) the MODEL reads (e.g. a settings file). The second is to write out a shell script, jobs.sh, which, when run, will start your model run and convert its output to the PEcAn standard (netCDF with metadata currently equivalent to the MsTMIP standard). Within the MODEL directory take a close look at inst/template.job and the example write.config.MODEL to see an example of how this is done. It is important that this script writes or moves outputs to the correct location so that PEcAn can find them. The example function also shows an example of writing a model-specific settings/config file, also by using a template.

-

You are encouraged to read the section above on defining PFTs before writing write.config.MODEL so that you understand what model parameters PEcAn will be passing you, how they will be named, and what units they will be in. Also note that the (optional) PEcAn input/driver processing scripts are called by separate workflows, so the paths to any required inputs (e.g. meteorology) will already be in the model-specific format by the time write.config.MODEL receives that info.

-
-
-

20.2.0.5 Output Conversions

-

The module model2netcdf.MODEL converts model output into the PEcAn standard (netCDF with metadata currently equivalent to the MsTMIP standard). This function was previously required, but now that the conversion is called within jobs.sh it may be easier for you to convert outputs using other approaches (or to just directly write outputs in the standard).

-

Whether you implement this function or convert outputs some other way, please note that PEcAn expects all outputs to be broken up into ANNUAL files with the year number as the file name (i.e. YEAR.nc), though these files may contain any number of scalars, vectors, matrices, or arrays of model outputs, such as time-series of each output variable at the model’s native timestep.

-

Note: PEcAn reads all variable names from the files themselves so it is possible to add additional variables that are not part of the MsTMIP standard. Similarly, there are no REQUIRED output variables, though time is highly encouraged. We are shortly going establish a canonical list of PEcAn variables so that if users add additional output variables they become part of the standard. We don’t want two different models to call the same output with two different names or different units as this would prohibit the multi-model syntheses and comparisons that PEcAn is designed to facilitate.

-
-
-

20.2.0.6 met2model.MODEL

-

met2model.MODEL(in.path, in.prefix, outfolder, start_date, end_date)

-

Converts meteorology input files from the PEcAn standard (netCDF, CF metadata) to the format required by the model. This file is optional if you want to load all of your met files into the Inputs table as described in How to insert new Input data, which is often the easiest way to get up and running quickly. However, this function is required if you want to benefit from PEcAn’s meteorology workflows and model run cloning. You’ll want to take a close look at [Adding-an-Input-Converter] to see the exact variable names and units that PEcAn will be providing. Also note that PEcAn splits all meteorology up into ANNUAL files, with the year number explicitly included in the file name, and thus what PEcAn will actually be providing is in.path, the input path to the folder where multiple met files may stored, and in.prefix, the start of the filename that precedes the year (i.e. an individual file will be named <in.prefix>.YEAR.nc). It is valid for in.prefix to be blank. The additional REQUIRED arguments to met2model.MODEL are outfolder, the output folder where PEcAn wants you to write your meteorology, and start_date and end_date, the time range the user has asked the meteorology to be processed for.

-
-
-

20.2.0.7 Commit changes

-

Once the MODEL modules are written, you should follow the Using-Git instructions on how to commit your changes to your local git repository, verify that PEcAn compiles using scripts/build.sh, push these changes to Github, and submit a pull request so that your model module is added to the PEcAn system. It is important to note that while we encourage users to make their models open, adding the PEcAn interface module to the Github repository in no way requires that the model code itself be made public. It does, however, allow anyone who already has a copy of the model code to use PEcAn so we strongly encourage that any new model modules be committed to Github.

-
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/examples.html b/master/examples.html deleted file mode 100644 index 1ffdad77a..000000000 --- a/master/examples.html +++ /dev/null @@ -1,2068 +0,0 @@ - - - - - - - 16.4 Examples: | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

16.4 Examples:

-
-

16.4.1 Prerequisites to interact with the PEcAn API Server

-
-

16.4.1.1 R Packages

- -
-
-

16.4.1.2 Python Packages

- -
-
-
-

-

Following are some example snippets to call the PEcAn API endpoints:

-
-
-

16.4.2 GET /api/ping

-
-

16.4.2.1 R Snippet

-
res <- httr::GET("http://pecan.localhost/api/ping")
-print(jsonlite::fromJSON(rawToChar(res$content)))
-
## $request
-## [1] "ping"
-
-## $response
-## [1] "pong"
-
-
-

16.4.2.2 Python Snippet

-
response = requests.get("http://pecan.localhost/api/ping")
-print(json.dumps(response.json(), indent=2))
-
## {
-##  "request": "ping",
-##  "response": "pong"
-## }
-
-
-
-

-
-
-

16.4.3 GET /api/status

-
-

16.4.3.1 R Snippet

-
res <- httr::GET("http://pecan.localhost/api/status")
-print(jsonlite::fromJSON(rawToChar(res$content)))
-
## $pecan_details$version
-## [1] "1.7.0"
-
-## $pecan_details$branch
-## [1] "develop"
-
-## $pecan_details$gitsha1
-## [1] "unknown"
-
-## $host_details$hostid
-## [1] 99
-
-## $host_details$hostname
-## [1] ""
-
-## $host_details$start
-## [1] 99000000000
-
-## $host_details$end
-## [1] 99999999999
-
-## $host_details$sync_url
-## [1] ""
-
-## $host_details$sync_contact
-## [1] ""
-
-
-

16.4.3.2 Python Snippet

-
response = requests.get("http://pecan.localhost/api/status")
-print(json.dumps(response.json(), indent=2))
-
## {
-##   "pecan_details": {
-##     "version": "1.7.0",
-##     "branch": "develop",
-##     "gitsha1": "unknown"
-##   },
-##   "host_details": {
-##     "hostid": 99,
-##     "hostname": "",
-##     "start": 99000000000,
-##     "end": 99999999999,
-##     "sync_url": "",
-##     "sync_contact": ""
-##   }
-## }
-
-
-
-

-
-
-

16.4.4 GET /api/models/

-
-

16.4.4.1 R Snippet

-
# Search model(s) with `model_name` containing "sip" & `revision` containing "ssr"
-res <- httr::GET(
-         "http://pecan.localhost/api/models/?model_name=sip&revision=ssr&ignore_case=TRUE",
-         httr::authenticate("carya", "illinois")
-       )
-print(jsonlite::fromJSON(rawToChar(res$content)))
-
## $models
-##     model_id model_name revision
-## 1 1000000022     SIPNET      ssr
-
-## $count
-## [1] 1
-
-
-

16.4.4.2 Python Snippet

-
# Search model(s) with `model_name` containing "sip" & `revision` containing "ssr"
-response = requests.get(
-             "http://pecan.localhost/api/models/?model_name=sip&revision=ssr&ignore_case=TRUE",
-             auth=HTTPBasicAuth('carya', 'illinois')
-           )
-print(json.dumps(response.json(), indent=2))
-
## {
-##   "models": [
-##     {
-##       "model_id": "1000000022",
-##       "model_name": "SIPNET",
-##       "revision": "ssr"
-##     }
-##   ],
-##   "count": 1
-## }
-
-
-
-

-
-
-

16.4.5 GET /api/models/{model_id}

-
-

16.4.5.1 R Snippet

-
# Fetch the details of PEcAn model with id = 1000000022
-res <- httr::GET(
-         "http://pecan.localhost/api/models/1000000022",
-         httr::authenticate("carya", "illinois")
-       )
-print(jsonlite::fromJSON(rawToChar(res$content)))
-
## $modeltype_id
-## [1] 3
-
-## $model_type
-## [1] "SIPNET"
-
-## $model_id
-## [1] 1000000022
-
-## $model_name
-## [1] "SIPNET"
-
-## $revision
-## [1] "ssr"
-
-## $inputs
-##          input required
-## 1          met     TRUE
-## 2 poolinitcond    FALSE
-
-
-

16.4.5.2 Python Snippet

-
# Fetch the details of PEcAn model with id = 1000000022
-response = requests.get(
-             "http://pecan.localhost/api/models/1000000022",
-             auth=HTTPBasicAuth('carya', 'illinois')
-           )
-print(json.dumps(response.json(), indent=2))
-
## {
-##   "model_id": "1000000022",
-##   "model_name": "SIPNET",
-##   "revision": "ssr",
-##   "modeltype_id": 3,
-##   "model_type": "SIPNET"
-##   "inputs": [
-##     {
-##       "input": "met",
-##       "required": TRUE
-##     },
-##     {
-##       "input": "poolinitcond",
-##       "required": FALSE
-##     }
-##   ]
-## }
-
-
-
-

-
-
-

16.4.6 GET /api/sites/

-
-

16.4.6.1 R Snippet

-
# Search site(s) with `site_name` containing "willow"
-res <- httr::GET(
-         "http://pecan.localhost/api/sites/?sitename=willow&ignore_case=TRUE",
-         httr::authenticate("carya", "illinois")
-       )
-print(jsonlite::fromJSON(rawToChar(res$content)))
-
## $sites
-##           id                                      sitename
-## 1        676                         Willow Creek (US-WCr)
-## 2       1108 Willow Creek (WC)-Chequamegon National Forest
-## 3       1202                                  Tully_willow
-## 4       1223                   Saare SRF willow plantation
-## 5 1000005151                         Willow Creek (US-WCr)
-
-## $count
-## [1] 5
-
-
-

16.4.6.2 Python Snippet

-
# Search site(s) with `site_name` containing "willow"
-response = requests.get(
-             "http://pecan.localhost/api/models/?sitename=willow&ignore_case=TRUE",
-             auth=HTTPBasicAuth('carya', 'illinois')
-           )
-print(json.dumps(response.json(), indent=2))
-
## {
-##   "sites": [
-##     {
-##       "id": 676,
-##       "sitename": "Willow Creek (US-WCr)"
-##     },
-##     {
-##       "id": 1108,
-##       "sitename": "Willow Creek (WC)-Chequamegon National Forest"
-##     },
-##     {
-##       "id": 1202,
-##       "sitename": "Tully_willow"
-##     },
-##     {
-##       "id": 1223,
-##       "sitename": "Saare SRF willow plantation"
-##     },
-##     {
-##       "id": 1000005151,
-##       "sitename": "Willow Creek (US-WCr)"
-##     }
-##   ],
-##   "count": 5
-## }
-
-
-
-

-
-
-

16.4.7 GET /api/sites/{site_id}

-
-

16.4.7.1 R Snippet

-
# Fetch the details of PEcAn site with id = 676
-res <- httr::GET(
-         "http://pecan.localhost/api/sites/676",
-         httr::authenticate("carya", "illinois")
-       )
-print(jsonlite::fromJSON(rawToChar(res$content)))
-
## $id
-## [1] 676
-
-## $city
-## [1] "Park Falls Ranger District"
-
-## $state
-## [1] "Wisconsin"
-
-## $country
-## [1] "US"
-
-## $mat
-## [1] 4
-
-## $map
-## [1] 815
-
-## $soil
-## [1] ""
-
-## $som
-## [1] "NA"
-
-## $notes
-## [1] "MF"
-
-## $soilnotes
-## [1] ""
-
-## $sitename
-## [1] "Willow Creek (US-WCr)"
-
-## $greenhouse
-[1] FALSE
-
-## $sand_pct
-## [1] 42.52
-
-## $clay_pct
-## [1] 20.17
-
-## $time_zone
-## [1] "America/Chicago"
-
-
-

16.4.7.2 Python Snippet

-
# Fetch the details of PEcAn site with id = 676
-response = requests.get(
-             "http://pecan.localhost/api/sites/676",
-             auth=HTTPBasicAuth('carya', 'illinois')
-           )
-print(json.dumps(response.json(), indent=2))
-
## {
-##   "id": 676,
-##   "city": "Park Falls Ranger District",
-##   "state": "Wisconsin",
-##   "country": "US",
-##   "mat": 4,
-##   "map": 815,
-##   "soil": "",
-##   "notes": "MF",
-##   "soilnotes": "",
-##   "sitename": "Willow Creek (US-WCr)",
-##   "greenhouse": false,
-##   "sand_pct": 42.52,
-##   "clay_pct": 20.17,
-##   "time_zone": "America/Chicago"
-##  }
-
-
-
-

-
-
-

16.4.8 GET /api/pfts/

-
-

16.4.8.1 R Snippet

-
# Search pft(s) of "plant" type with `pft_name` containing "temperate" & belonging to `model_type` "SIPNET"
-res <- httr::GET(
-         "http://pecan.localhost/api/pfts/?pft_name=temperate&pft_type=plant&model_type=sipnet&ignore_case=TRUE",
-         httr::authenticate("carya", "illinois")
-       )
-print(jsonlite::fromJSON(rawToChar(res$content)))
-
## $pfts
-##   model_type  pft_id          pft_name                       pft_type
-##   <chr>       <S3: integer64> <chr>                          <chr>   
-## 1 SIPNET              41      temperate.deciduous            plant   
-## 2 SIPNET      1000000105      temperate.deciduous.IF         plant   
-## 3 SIPNET      1000000107      temperate.deciduous_SDA        plant   
-## 4 SIPNET      1000000115      temperate.deciduous.ALL        plant   
-## 5 SIPNET      1000000118      temperate.deciduous.ALL.NORMAL plant   
-## 6 SIPNET      2000000017      tundra.deciduous.NGEE_Arctic   plant   
-## 7 SIPNET      2000000045      temperate.broadleaf.deciduous  plant
-
-## $count
-## [1] 7
-
-
-

16.4.8.2 Python Snippet

-
# Search pft(s) of "plant" type with `pft_name` containing "temperate" & belonging to `model_type` "SIPNET"
-response = requests.get(
-             "http://pecan.localhost/api/pfts/?pft_name=temperate&pft_type=plant&model_type=sipnet&ignore_case=TRUE",
-             auth=HTTPBasicAuth('carya', 'illinois')
-           )
-print(json.dumps(response.json(), indent=2))
-
## {
-##   "pfts": [
-##     {
-##       "model_type": "SIPNET",
-##       "pft_id": 41,
-##       "pft_name": "temperate.deciduous",
-##       "pft_type": "plant"
-##     },
-##     ...
-##   ],
-##   "count": 7
-## }
-
-
-
-

-
-
-

16.4.9 GET /api/pfts/{pft_id}

-
-

16.4.9.1 R Snippet

-
# Fetch the details of PEcAn PFT with id = 2000000045
-res <- httr::GET(
-         "http://pecan.localhost/api/pfts/2000000045",
-         httr::authenticate("carya", "illinois")
-       )
-print(jsonlite::fromJSON(rawToChar(res$content)))
-
## $model_type
-## [1] "SIPNET"
-
-## $pft_id
-## [1] 2000000045
-
-## $pft_name
-## [1] "temperate.broadleaf.deciduous"
-
-## $definition
-## [1] "SIPNET Temperate Deciduous PFT with priors on all parameters"
-
-## $pft_type
-## [1] "plant" 
-
-
-

16.4.9.2 Python Snippet

-
# Fetch the details of PEcAn PFT with id = 2000000045
-response = requests.get(
-             "http://pecan.localhost/api/pfts/2000000045",
-             auth=HTTPBasicAuth('carya', 'illinois')
-           )
-print(json.dumps(response.json(), indent=2))
-
## {
-##   "model_type": "SIPNET",
-##   "pft_id": 2000000045,
-##   "pft_name": "temperate.broadleaf.deciduous",
-##   "definition": "SIPNET Temperate Deciduous PFT with priors on all parameters",
-##   "pft_type": "plant"
-## }
-
-
-
-

-
-
-

16.4.10 GET /api/formats/

-
-

16.4.10.1 R Snippet

-
# Search format(s) with name containing 'ameriflux' & mime type containing 'csv'
-res <- httr::GET(
-         "http://pecan.localhost/api/formats/?format_name=ameriflux&mimetype=csv&ignore_case=TRUE",
-         httr::authenticate("carya", "illinois")
-       )
-print(jsonlite::fromJSON(rawToChar(res$content)))
-
## $formats
-##   mimetype format_id        format_name
-## 1 text/csv        19 AmeriFlux.level4.h
-## 2 text/csv        20 AmeriFlux.level4.d
-## 3 text/csv        21 AmeriFlux.level4.w
-## 4 text/csv        22 AmeriFlux.level4.m
-## 5 text/csv        35 AmeriFlux.level2.h
-## 6 text/csv        36 AmeriFlux.level3.h
-
-## $count
-## [1] 6
-
-
-

16.4.10.2 Python Snippet

-
# # Search format(s) with name containing 'ameriflux' & mime type containing 'csv'
-response = requests.get(
-             "http://pecan.localhost/api/formats/?format_name=ameriflux&mimetype=csv&ignore_case=TRUE",
-             auth=HTTPBasicAuth('carya', 'illinois')
-           )
-print(json.dumps(response.json(), indent=2))
-
## {
-##   "formats": [
-##     {
-##       "mimetype": "text/csv",
-##       "format_id": 19,
-##       "format_name": "AmeriFlux.level4.h"
-##     },
-##     {
-##       "mimetype": "text/csv",
-##       "format_id": 20,
-##       "format_name": "AmeriFlux.level4.d"
-##     },
-##     ...
-##   ],
-##   "count": 6
-## }
-  
-
-
-
-

-
-
-

16.4.11 GET /api/formats/{format_id}

-
-

16.4.11.1 R Snippet

-
# Fetch the details of PEcAn format with id = 19
-res <- httr::GET(
-         "http://pecan.localhost/api/formats/19",
-         httr::authenticate("carya", "illinois")
-       )
-print(jsonlite::fromJSON(rawToChar(res$content)))
-
## $mimetype
-## [1] "text/csv"
-
-## $format_id
-## [1] 19
-
-## $name
-## [1] "AmeriFlux.level4.h"
-
-## $notes
-## [1] "Half-hourly AmeriFlux level 4 gap filled, partitioned, and flagged flux tower data. Variables description:  Level 4 data are obtained from the level 3 products, data are ustar filtered, gap-filled using different methods (ANN and MDS) and partitioned (i.e. NEE, GPP, and Re). Flags with information regarding quality of the original and gapfilled data are added.  Missing values: -9999."
-
-## $header
-## [1] ""
-
-## $format_variables
-##                                                   description        name             unit
-## 1                                            Latent heat flux        LE_f            W m-2
-## 2                                          Sensible heat flux         H_f            W m-2
-## 3                                             air temperature        Ta_f        degrees C
-## 4                                      Vapor Pressure Deficit       VPD_f               Pa
-## 5 Cumulative ecosystem respiration over a specified time step        Reco umol C02 m-2 s-1
-## 6                                      Net ecosystem exchange NEE_st_fMDS   umol C m-2 s-1
-
-
-

16.4.11.2 Python Snippet

-
# Fetch the details of PEcAn format with id = 19
-response = requests.get(
-             "http://pecan.localhost/api/formats/19",
-             auth=HTTPBasicAuth('carya', 'illinois')
-           )
-print(json.dumps(response.json(), indent=2))
-
## {
-##   "mimetype": "text/csv",
-##   "format_id": 19,
-##   "name": "AmeriFlux.level4.h",
-##   "notes": "Half-hourly AmeriFlux level 4 gap filled, partitioned, and flagged flux tower data. Variables description:  ## Level 4 data are obtained from the level 3 products, data are ustar filtered, gap-filled using different methods (ANN and ## MDS) and partitioned (i.e. NEE, GPP, and Re). Flags with information regarding quality of the original and gapfilled data ## are added.  Missing values: -9999.",
-##   "header": "",
-##   "format_variables": [
-##     {
-##       "description": "Latent heat flux",
-##       "name": "LE_f",
-##       "unit": "W m-2"
-##     },
-##     ...
-##   ]
-## }
-
-
-
-

-
-
-

16.4.12 GET /api/inputs/

-
-

16.4.12.1 R Snippet

-
# Get the inputs needed for a workflow with model_id = 1000000022 & site_id = 676
-res <- httr::GET(
-         "http://pecan.localhost/api/inputs/?model_id=1000000022&site_id=676",
-         httr::authenticate("carya", "illinois")
-       )
-print(jsonlite::fromJSON(rawToChar(res$content)))
-
## $inputs
-##                sitename model_name revision tag                      hostname file_name   format_name mimetype
-## 1 Willow Creek (US-WCr)     SIPNET      ssr met ebi-forecast.igb.illinois.edu  wcr.clim Sipnet.climna text/csv
-## 2 Willow Creek (US-WCr)     SIPNET      ssr met                        docker  wcr.clim Sipnet.climna text/csv
-##                   file_path         id input_name          start_date            end_date
-## 1 /home/share/data/dbfiles/        235            2000-01-01 06:00:00 2007-01-01 05:59:00
-## 2        /data/sites/willow 2000000001            1998-01-01 00:00:00 2006-12-31 00:00:00
-
-## $count
-## [1] 2
-
# Get the inputs needed for a workflow with format_id = 5000000002 (AMERIFLUX_BASE_HH) & host_id = 99000000001 (docker)
-res <- httr::GET(
-         "http://pecan.localhost/api/inputs/?format_id=5000000002&host_id=99000000001",
-         httr::authenticate("carya", "illinois")
-       )
-print(jsonlite::fromJSON(rawToChar(res$content)))
-
## $inputs
-##                                sitename mimetype       format_name hostname               file_name
-## 1 Niwot Ridge Forest/LTER NWT1 (US-NR1) text/csv AMERIFLUX_BASE_HH   docker AMF_US-NR1_BASE_HH_15-5
-##                               file_path         id              input_name start_date   end_date
-## 1 /data/dbfiles/AmerifluxLBL_site_0-772 1000011238 AmerifluxLBL_site_0-772 1998-01-01 2016-12-31
-
-## $count
-## [1] 1
-
-
-

16.4.12.2 Python Snippet

-
# Get the inputs needed for a workflow with model_id = 1000000022 & site_id = 676
-response = requests.get(
-             "http://pecan.localhost/api/inputs/?model_id=1000000022&site_id=676",
-             auth=HTTPBasicAuth('carya', 'illinois')
-           )
-print(json.dumps(response.json(), indent=2))
-
## {
-##   "inputs": [
-##     {
-##       "sitename": "Willow Creek (US-WCr)",
-##       "model_name": "SIPNET",
-##       "revision": "ssr",
-##       "tag": "met",
-##       "hostname": "ebi-forecast.igb.illinois.edu",
-##       "file_name": "wcr.clim",
-##       "format_name": "Sipnet.climna",
-##       "mimetype": "text/csv",
-##       "file_path": "/home/share/data/dbfiles/",
-##       "id": 235,
-##       "input_name": "",
-##       "start_date": "2000-01-01 06:00:00",
-##       "end_date": "2007-01-01 05:59:00"
-##     },
-##     ...
-##   ],
-##   "count": 2
-## }
-
# Get the inputs needed for a workflow with format_id = 5000000002 (AMERIFLUX_BASE_HH) & host_id = 99000000001 (docker)
-response = requests.get(
-             "http://pecan.localhost/api/inputs/?format_id=5000000002&host_id=99000000001",
-             auth=HTTPBasicAuth('carya', 'illinois')
-           )
-print(json.dumps(response.json(), indent=2))
-
## {
-##   "inputs": [
-##     {
-##       "sitename": "Niwot Ridge Forest/LTER NWT1 (US-NR1)",
-##       "hostname": "docker",
-##       "file_name": "AMF_US-NR1_BASE_HH_15-5",
-##       "format_name": "AMERIFLUX_BASE_HH",
-##       "mimetype": "text/csv",
-##       "file_path": "/data/dbfiles/AmerifluxLBL_site_0-772",
-##       "id": 1000011238,
-##       "input_name": "AmerifluxLBL_site_0-772",
-##       "start_date": "1998-01-01",
-##       "end_date": "2016-12-31"
-##     }
-##   ],
-##   "count": 1,
-## }
-
-
-
-

-
-
-

16.4.13 GET /api/inputs/{input_id}

-
-

16.4.13.1 R Snippet

-
# Download the input file with id = 99000000003
-res <- httr::GET(
-         "http://pecan.localhost/api/inputs/99000000003",
-         httr::authenticate("carya", "illinois")
-       )
-writeBin(res$content, "test.2002.nc")
-
-# Download the file 'fraction.plantation' from the input directory with id = 295
-res <- httr::GET(
-         "http://pecan.localhost/api/inputs/295?filename=fraction.plantation",
-         httr::authenticate("carya", "illinois")
-       )
-writeBin(res$content, "test.fraction.plantation")
-
-
-

16.4.13.2 Python Snippet

-
# Download the input file for with id = 99000000003
-response = requests.get(
-             "http://pecan.localhost/api/inputs/99000000003",
-             auth=HTTPBasicAuth('carya', 'illinois')
-           )
-with open("test.2002.nc", "wb") as file:
-  file.write(response.content)
-  
-# Download the file 'fraction.plantation' from the input directory with id = 295
-response = requests.get(
-             "http://pecan.localhost/api/inputs/295?filename=fraction.plantation",
-             auth=HTTPBasicAuth('carya', 'illinois')
-           )
-with open("test.2002.nc", "wb") as file:
-  file.write(response.content)
-
-
-
-

-
-
-

16.4.14 GET /api/workflows/

-
-

16.4.14.1 R Snippet

-
# Get workflow(s) that use `model_id` = 1000000022 [SIPNET] & `site_id` = 676 [Willow Creek (US-WCr)]
-res <- httr::GET(
-         "http://pecan.localhost/api/workflows/?model_id=1000000022&site_id=676",
-         httr::authenticate("carya", "illinois")
-       )
-print(jsonlite::fromJSON(rawToChar(res$content)))
-
## $workflows
-##           id                             folder          started_at site_id   model_id          hostname start_date   end_date
-## 1 1000009900 /fs/data2/output//PEcAn_1000009900 2018-11-09 08:56:37     676 1000000022        geo.bu.edu 2004-01-01 2004-12-31
-## 2 1000009172 /fs/data2/output//PEcAn_1000009172 2018-04-11 18:14:52     676 1000000022 test-pecan.bu.edu 2004-01-01 2004-12-31
-## ...
-
-## $count
-## [1] 5
-
-
-

16.4.14.2 Python Snippet

-
# Get workflow(s) that use `model_id` = 1000000022 [SIPNET] & `site_id` = 676 [Willow Creek (US-WCr)]
-response = requests.get(
-             "http://pecan.localhost/api/workflows/?model_id=1000000022&site_id=676",
-             auth=HTTPBasicAuth('carya', 'illinois')
-           )
-print(json.dumps(response.json(), indent=2))
-
## {
-##   "workflows": [
-##     {
-##       "id": 1000009172,
-##       "folder": "/fs/data2/output//PEcAn_1000009900",
-##       "started_at": "2018-11-09 08:56:37",
-##       "site_id": 676,
-##       "model_id": 1000000022,
-##       "hostname": "geo.bu.edu",
-##       "start_date": "2004-01-01",
-##       "end_date": "2004-12-31"
-##     },
-##     ...
-##   ],
-##   "count": 5
-## }
-
-
-
-

-
-
-

16.4.15 POST /api/workflows/

-
-

16.4.15.1 R Snippet

-
# Submit a workflow in XML format for execution
-xmlFile <- "pecan/tests/api.sipnet.xml"
-xml_string <- paste0(xml2::read_xml(xmlFile))
-res <- httr::POST(
-         "http://pecan.localhost/api/workflows/",
-         httr::authenticate("carya", "illinois"),
-         httr::content_type("application/xml"),
-         body = xml_string
-       )
-print(jsonlite::fromJSON(rawToChar(res$content)))
-
## $workflow_id
-## [1] 99000000001
-
-## $status
-## [1] "Submitted successfully"
-
-
-

16.4.15.2 Python Snippet

-
# Submit a workflow in XML format for execution
-xml_file = "pecan/tests/api.sipnet.xml"
-root = xml.etree.ElementTree.parse(xml_file).getroot()
-response = requests.post(
-             "http://pecan.localhost/api/workflows/",
-             auth=HTTPBasicAuth('carya', 'illinois'),
-             headers = {'Content-Type': 'application/xml'},
-             data = xml.etree.ElementTree.tostring(root, encoding='unicode', method='xml')
-           )
-print(json.dumps(response.json(), indent=2))
-
## {
-##   "workflow_id": "99000000001",
-##   "status": "Submitted successfully"
-## }
-
-
-
-

-
-
-

16.4.16 GET /api/workflows/{id}

-
-

16.4.16.1 R Snippet

-
# Get details of workflow with `id` = '1000009172'
-res <- httr::GET(
-         "http://pecan.localhost/api/workflows/1000009172",
-         httr::authenticate("carya", "illinois")
-       )
-print(jsonlite::fromJSON(rawToChar(res$content)))
-
## $id
-## [1] "1000009172"
-
-## $folder
-## [1] "/fs/data2/output//PEcAn_1000009172"
-
-## $hostname
-## [1] "test-pecan.bu.edu"
-
-## $user_id
-## [1] "NA"
-
-## $properties
-## $properties$end
-## [1] "2004/12/31"
-
-## $properties$pft
-## $properties$pft[[1]]
-## [1] "soil.IF"
-
-## $properties$pft[[2]]
-## [1] "temperate.deciduous.IF"
-
-
-## $properties$email
-## [1] ""
-
-## $properties$notes
-## [1] ""
-
-## $properties$start
-## [1] "2004/01/01"
-
-## $properties$siteid
-## [1] "676"
-
-## $properties$modelid
-## [1] "1000000022"
-
-## $properties$hostname
-## [1] "test-pecan.bu.edu"
-
-## $properties$sitename
-## [1] "WillowCreek(US-WCr)"
-
-## $properties$input_met
-## [1] "AmerifluxLBL.SIPNET"
-
-## $properties$pecan_edit
-## [1] "on"
-
-## $properties$sitegroupid
-## [1] "1000000022"
-
-## $properties$fluxusername
-## [1] "pecan"
-
-## $properties$input_poolinitcond
-## [1] "-1"
-
-
-

16.4.16.2 Python Snippet

-
# Get details of workflow with `id` = '1000009172'
-response = requests.get(
-             "http://pecan.localhost/api/workflows/1000009172",
-             auth=HTTPBasicAuth('carya', 'illinois')
-           )
-print(json.dumps(response.json(), indent=2))
-
## {
-##   "id": "1000009172",
-##   "folder": "/fs/data2/output//PEcAn_1000009172",
-##   "hostname": "test-pecan.bu.edu",
-##   "user_id": "NA",
-##   "properties": {
-##     "end": "2004/12/31",
-##     "pft": [
-##       "soil.IF",
-##       "temperate.deciduous.IF"
-##     ],
-##     "email": "",
-##     "notes": "",
-##     "start": "2004/01/01",
-##     "siteid": "676",
-##     "modelid": "1000000022",
-##     "hostname": "test-pecan.bu.edu",
-##     "sitename": "WillowCreek(US-WCr)",
-##     "input_met": "AmerifluxLBL.SIPNET",
-##     "pecan_edit": "on",
-##     "sitegroupid": "1000000022",
-##     "fluxusername": "pecan",
-##     "input_poolinitcond": "-1"
-##   }
-## }
-
-
-
-

-
-
-

16.4.17 GET /api/workflows/{id}/status

-
-

16.4.17.1 R Snippet

-
# Get list of run belonging to the workflow with `workflow_id` = '99000000001'
-res <- httr::GET(
-         "http://pecan.localhost/api/workflows/99000000001/status",
-         httr::authenticate("carya", "illinois")
-       )
-print(jsonlite::fromJSON(rawToChar(res$content)))
-
## $workflow_id
-## [1] "99000000001"
-
-## $status
-## [1] "TRAIT  2020-07-22 07:02:33  2020-07-22 07:02:35  DONE  "      
-## [2] "META  2020-07-22 07:02:35  2020-07-22 07:02:38  DONE  "       
-## [3] "CONFIG  2020-07-22 07:02:38  2020-07-22 07:02:40  DONE  "     
-## [4] "MODEL  2020-07-22 07:02:40  2020-07-22 07:04:07  DONE  "      
-## [5] "OUTPUT  2020-07-22 07:04:07  2020-07-22 07:04:08  DONE  "     
-## [6] "ENSEMBLE  2020-07-22 07:04:08  2020-07-22 07:04:09  DONE  "   
-## [7] "SENSITIVITY  2020-07-22 07:04:09  2020-07-22 07:04:16  DONE  "
-## [8] "FINISHED  2020-07-22 07:04:16  2020-07-22 07:04:16  DONE  "
-
-
-

16.4.17.2 Python Snippet

-
# Get list of run belonging to the workflow with `workflow_id` = '99000000001'
-response = requests.get(
-             "http://pecan.localhost/api/workflows/99000000001/status",
-             auth=HTTPBasicAuth('carya', 'illinois')
-           )
-print(json.dumps(response.json(), indent=2))
-
## {
-##   "workflow_id": "99000000001",
-##   "status": [
-##     "TRAIT  2020-07-22 07:02:33  2020-07-22 07:02:35  DONE  ",
-##     "META  2020-07-22 07:02:35  2020-07-22 07:02:38  DONE  ",
-##     "CONFIG  2020-07-22 07:02:38  2020-07-22 07:02:40  DONE  ",
-##     "MODEL  2020-07-22 07:02:40  2020-07-22 07:04:07  DONE  ",
-##     "OUTPUT  2020-07-22 07:04:07  2020-07-22 07:04:08  DONE  ",
-##     "ENSEMBLE  2020-07-22 07:04:08  2020-07-22 07:04:09  DONE  ",
-##     "SENSITIVITY  2020-07-22 07:04:09  2020-07-22 07:04:16  DONE  ",
-##     "FINISHED  2020-07-22 07:04:16  2020-07-22 07:04:16  DONE  "
-##   ]
-## }
-
-
-
-

-
-
-

16.4.18 GET /api/workflows/{id}/file/{filename}

-
-

16.4.18.1 R Snippet

-
# Download the 'ensemble.ts.99000000017.NPP.2002.2002.Rdata' output file for the workflow with id = 99000000031
-res <- httr::GET(
-         "http://pecan.localhost/api/workflows/99000000031/file/ensemble.ts.99000000017.NPP.2002.2002.Rdata",
-         httr::authenticate("carya", "illinois")
-       )
-writeBin(res$content, "test.ensemble.ts.99000000017.NPP.2002.2002.Rdata")
-
-
-

16.4.18.2 Python Snippet

-
# Download the 'ensemble.ts.99000000017.NPP.2002.2002.Rdata' output file for the workflow with id = 99000000031
-response = requests.get(
-             "http://pecan.localhost/api/workflows/99000000031/file/ensemble.ts.99000000017.NPP.2002.2002.Rdata",
-             auth=HTTPBasicAuth('carya', 'illinois')
-           )
-with open("test.ensemble.ts.99000000017.NPP.2002.2002.Rdata", "wb") as file:
-  file.write(response.content)
-
-
-
-

-
-
-

16.4.19 GET /api/runs/

-
-

16.4.19.1 R Snippet

-
# Get list of run belonging to the workflow with `workflow_id` = '1000009172'
-res <- httr::GET(
-         "http://pecan.localhost/api/runs/?workflow_id=1000009172",
-         httr::authenticate("carya", "illinois")
-       )
-print(jsonlite::fromJSON(rawToChar(res$content)))
-
## $runs
-##    runtype  ensemble_id    workflow_id    id            model_id     site_id      parameter_list start_time        
-## finish_time    
-##  1 ensemble 1000017624     1000009172     1002042201    1000000022   796          ensemble=1     2005-01-01 
-## 00:00:00 2011-12-31 00:00:00
-##  ...
-
-## $count
-## [1] 50
-
-
-

16.4.19.2 Python Snippet

-
# Get list of run belonging to the workflow with `workflow_id` = '1000009172'
-response = requests.get(
-             "http://pecan.localhost/api/runs/?workflow_id=1000009172",
-             auth=HTTPBasicAuth('carya', 'illinois')
-           )
-print(json.dumps(response.json(), indent=2))
-
## {
-##   "runs": [
-##     {
-##       "runtype": "ensemble",
-##       "ensemble_id": 1000017624,
-##       "workflow_id": 1000009172,
-##       "id": 1002042201,
-##       "model_id": 1000000022,
-##       "site_id": 796,
-##       "parameter_list": "ensemble=1",
-##       "start_time": "2005-01-01",
-##       "finish_time": "2011-12-31"
-##     },
-##     ...
-##   ]
-##   "count": 50,
-##   "next_page": "http://pecan.localhost/api/workflows/?workflow_id=1000009172&offset=50&limit=50"
-## }
-
-
-
-

-
-
-

16.4.20 GET /api/runs/{run_id}

-
-

16.4.20.1 R Snippet

-
# Get details of run belonging with `id` = '99000000282'
-res <- httr::GET(
-         "http://pecan.localhost/api/runs/99000000282",
-         httr::authenticate("carya", "illinois")
-       )
-print(jsonlite::fromJSON(rawToChar(res$content)))
-
## $runtype
-## [1] "sensitivity analysis"
-
-## $ensemble_id
-## [1] 99000000016
-
-## $workflow_id
-## [1] 99000000031
-
-## $id
-## [1] 99000000282
-
-## $model_id
-## [1] 1000000014
-
-## $site_id
-## [1] 772
-
-## $start_time
-## [1] "2002-01-01"
-
-## $finish_time
-## [1] "2002-12-31"
-
-## $parameter_list
-## [1] "quantile=MEDIAN,trait=all,pft=temperate.coniferous"
-
-## $started_at
-## [1] "2020-07-22 07:02:40"
-
-## $finished_at
-## [1] "2020-07-22 07:02:57"
-
-## $inputs
-## $inputs$info
-## [1] "README.txt"
-
-## $inputs$others
-## [1] "sipnet.clim"          "sipnet.in"            "sipnet.param"         "sipnet.param-spatial"
-
-## $outputs
-## $outputs$logfile
-## [1] "logfile.txt"
-
-## $outputs$info
-## [1] "README.txt"
-
-## $outputs$years
-## $outputs$years$`2002`
-## $outputs$years$`2002`$data
-## [1] "2002.nc"
-
-## $outputs$years$`2002`$variables
-## $outputs$years$`2002`$variables$GPP
-## [1] "Gross Primary Productivity"
-
-## $outputs$years$`2002`$variables$NPP
-## [1] "Net Primary Productivity"
-
-## ...
-
-
-

16.4.20.2 Python Snippet

-
# Get details of run with `id` = '1002042201'
-response = requests.get(
-             "http://pecan.localhost/api/runs/1002042201",
-             auth=HTTPBasicAuth('carya', 'illinois')
-           )
-print(json.dumps(response.json(), indent=2))
-
## {
-##   "runtype": "ensemble",
-##   "ensemble_id": 1000017624,
-##   "workflow_id": 1000009172,
-##   "id": 1002042201,
-##   "model_id": 1000000022,
-##   "site_id": 796,
-##   "parameter_list": "ensemble=1",
-##   "start_time": "2005-01-01",
-##   "finish_time": "2011-12-31",
-##   "inputs": {
-##     "info": "README.txt",
-##     "others": [
-##       "sipnet.clim",
-##       "sipnet.in",
-##       "sipnet.param",
-##       "sipnet.param-spatial"
-##     ]
-##   }
-##   "outputs": {
-##     "logfile": "logfile.txt",
-##     "info": "README.txt",
-##     "years": {
-##       "2002": {
-##         "data": "2002.nc",
-##         "variables": {
-##           "GPP": "Gross Primary Productivity",
-##           "NPP": "Net Primary Productivity",
-##           ...
-##         }
-##       }
-##     }
-##   }
-## }
-
-
-
-

-
-
-

16.4.21 GET /api/runs/{run_id}/input/{filename}

-
-

16.4.21.1 R Snippet

-
# Download the 'sipnet.in' input file for the run with id = 99000000282
-res <- httr::GET(
-         "http://pecan.localhost/api/runs/99000000282/input/sipnet.in",
-         httr::authenticate("carya", "illinois")
-       )
-writeBin(res$content, "test.sipnet.in")
-
-
-

16.4.21.2 Python Snippet

-
# Download the 'sipnet.in' input file for the run with id = 99000000282
-response = requests.get(
-             "http://pecan.localhost/api/runs/99000000282/input/sipnet.in",
-             auth=HTTPBasicAuth('carya', 'illinois')
-           )
-with open("test.sipnet.in", "wb") as file:
-  file.write(response.content)
-
-
-
-

-
-
-

16.4.22 GET /api/runs/{run_id}/output/{filename}

-
-

16.4.22.1 R Snippet

-
# Download the '2002.nc' output file for the run with id = 99000000282
-res <- httr::GET(
-         "http://pecan.localhost/api/runs/99000000282/output/2002.nc",
-         httr::authenticate("carya", "illinois")
-       )
-writeBin(res$content, "test.2002.nc")
-
-
-

16.4.22.2 Python Snippet

-
# Download the '2002.nc' output file for the run with id = 99000000282
-response = requests.get(
-             "http://pecan.localhost/api/runs/99000000282/output/2002.nc",
-             auth=HTTPBasicAuth('carya', 'illinois')
-           )
-with open("test.2002.nc", "wb") as file:
-  file.write(response.content)
-
-
-
-

-
-
-

16.4.23 GET /api/runs/{run_id}/graph/{year}/{y_var}

-
-

16.4.23.1 R Snippet

-
# Plot the Gross Primary Productivity vs Time for the run with ID `99000000282` for the year 2002
-res <- httr::GET(
-         "http://pecan.localhost/api/runs/99000000282/graph/2002/GPP",
-         httr::authenticate("carya", "illinois")
-       )
-writeBin(res$content, "test.png")
-

-
-
-

16.4.23.2 Python Snippet

-
# Plot the Gross Primary Productivity vs Time for the run with ID `99000000282` for the year 2002
-response = requests.get(
-             "http://pecan.localhost/api/runs/99000000282/graph/2002/GPP",
-             auth=HTTPBasicAuth('carya', 'illinois')
-           )
-with open("test.png", "wb") as file:
-  file.write(response.content)
-

-
-
-
-

- -
-
- -
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/executive-summary-what-to-usually-do.html b/master/executive-summary-what-to-usually-do.html deleted file mode 100644 index b3dd1f018..000000000 --- a/master/executive-summary-what-to-usually-do.html +++ /dev/null @@ -1,862 +0,0 @@ - - - - - - - 31.1 Executive Summary: What to usually do | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

31.1 Executive Summary: What to usually do

-

When you’re editing one PEcAn package and want to use a function from any other R package (including other PEcAn packages), the standard method is to add the other package to the Imports: field of your DESCRIPTION file, spell the function in fully namespaced form (pkg::function()) everywhere you call it, and be done. There are a few cases where this isn’t enough, but they’re rarer than you think. The rest of this section mostly deals with the exceptions to this rule and why not to use them when they can be avoided.

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/extfiles/execstatus.jpg b/master/extfiles/execstatus.jpg deleted file mode 100644 index ebf7c2e67..000000000 Binary files a/master/extfiles/execstatus.jpg and /dev/null differ diff --git a/master/extfiles/mapmodel.png b/master/extfiles/mapmodel.png deleted file mode 100755 index 99ce2a418..000000000 Binary files a/master/extfiles/mapmodel.png and /dev/null differ diff --git a/master/extfiles/runspec.png b/master/extfiles/runspec.png deleted file mode 100755 index 32f8ce87e..000000000 Binary files a/master/extfiles/runspec.png and /dev/null differ diff --git a/master/extfiles/startpecan.jpg b/master/extfiles/startpecan.jpg deleted file mode 100644 index 6428f668e..000000000 Binary files a/master/extfiles/startpecan.jpg and /dev/null differ diff --git a/master/extfiles/workflowshiny.png b/master/extfiles/workflowshiny.png deleted file mode 100644 index f591a69b9..000000000 Binary files a/master/extfiles/workflowshiny.png and /dev/null differ diff --git a/master/faq.html b/master/faq.html deleted file mode 100644 index 2aad77fcf..000000000 --- a/master/faq.html +++ /dev/null @@ -1,862 +0,0 @@ - - - - - - - 29 FAQ | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

29 FAQ

- -
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/fetch-latest-data.html b/master/fetch-latest-data.html deleted file mode 100644 index 1ddacd021..000000000 --- a/master/fetch-latest-data.html +++ /dev/null @@ -1,894 +0,0 @@ - - - - - - - 17.3 Fetch latest data | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

17.3 Fetch latest data

-

When logged into the machine you can fetch the latest data using the load.bety.sh script. The script will check what site you want to get the data for and will remove all data in the database associated with that id. It will then reinsert all the data from the remote database.

-

The script is configured using environment variables. The following variables are recognized: -- DATABASE: the database where the script should write the results. The default is bety. -- OWNER: the owner of the database (if it is to be created). The default is bety. -- PG_OPT: additional options to be added to psql (default is nothing). -- MYSITE: the (numerical) ID of your site. If you have not requested an ID, use 99; this is used for all sites that do not want to share their data (i.e. VM). 99 is in fact the default. -- REMOTESITE: the ID of the site you want to fetch the data from. The default is 0 (EBI). -- CREATE: If ‘YES’, this indicates that the existing database (bety, or the one specified by DATABASE) should be removed. Set to YES (in caps) to remove the database. THIS WILL REMOVE ALL DATA in DATABASE. The default is NO. -- KEEPTMP: indicates whether the downloaded file should be preserved. Set to YES (in caps) to keep downloaded files; the default is NO. -- USERS: determines if default users should be created. Set to YES (in caps) to create default users with default passwords. The default is NO.

-

All of these variables can be specified as command line arguments as well, to see the options use -h.

-
load.bety.sh -h
-./scripts/load.bety.sh [-c YES|NO] [-d database] [-h] [-m my siteid] [-o owner] [-p psql options] [-r remote siteid] [-t YES|NO] [-u YES|NO]
- -c create database, THIS WILL ERASE THE CURRENT DATABASE, default is NO
- -d database, default is bety
- -h this help page
- -m site id, default is 99 (VM)
- -o owner of the database, default is bety
- -p additional psql command line options, default is empty
- -r remote site id, default is 0 (EBI)
- -t keep temp folder, default is NO
- -u create carya users, this will create some default users
-
-dump.bety.sh -h
-./scripts/dump.bety.sh [-a YES|NO] [-d database] [-h] [-l 0,1,2,3,4] [-m my siteid] [-o folder] [-p psql options] [-u YES|NO]
- -a use anonymous user, default is YES
- -d database, default is bety
- -h this help page
- -l level of data that can be dumped, default is 3
- -m site id, default is 99 (VM)
- -o output folder where dumped data is written, default is dump
- -p additional psql command line options, default is -U bety
- -u should unchecked data be dumped, default is NO
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/figures/PEcAn_Components.jpeg b/master/figures/PEcAn_Components.jpeg deleted file mode 100644 index 9acd5da3b..000000000 Binary files a/master/figures/PEcAn_Components.jpeg and /dev/null differ diff --git a/master/figures/PecanLogo.png b/master/figures/PecanLogo.png deleted file mode 100755 index 1af8c7fa6..000000000 Binary files a/master/figures/PecanLogo.png and /dev/null differ diff --git a/master/figures/pic1.jpg b/master/figures/pic1.jpg deleted file mode 100755 index 187131c1d..000000000 Binary files a/master/figures/pic1.jpg and /dev/null differ diff --git a/master/figures/pic1v2.png b/master/figures/pic1v2.png deleted file mode 100644 index 05e3e35fb..000000000 Binary files a/master/figures/pic1v2.png and /dev/null differ diff --git a/master/figures/pic2.jpg b/master/figures/pic2.jpg deleted file mode 100755 index 998018586..000000000 Binary files a/master/figures/pic2.jpg and /dev/null differ diff --git a/master/figures/pic3.jpg b/master/figures/pic3.jpg deleted file mode 100755 index 07c501b90..000000000 Binary files a/master/figures/pic3.jpg and /dev/null differ diff --git a/master/figures/run_output_plot.png b/master/figures/run_output_plot.png deleted file mode 100644 index d8179f297..000000000 Binary files a/master/figures/run_output_plot.png and /dev/null differ diff --git a/master/fluxnet2015.html b/master/fluxnet2015.html deleted file mode 100644 index 093e20d80..000000000 --- a/master/fluxnet2015.html +++ /dev/null @@ -1,865 +0,0 @@ - - - - - - - 15.3 Fluxnet2015 | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

15.3 Fluxnet2015

-

Scale: site

-

Resolution: 30 or 60 min

-

Availability: varies by site http://fluxnet.fluxdata.org/sites/site-list-and-pages

-

Notes: Fluxnet 2015 synthesis product. Does not cover all FLUXNET sites

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/fluxnetlathuile.html b/master/fluxnetlathuile.html deleted file mode 100644 index 1443ddad8..000000000 --- a/master/fluxnetlathuile.html +++ /dev/null @@ -1,865 +0,0 @@ - - - - - - - 15.10 FluxnetLaThuile | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

15.10 FluxnetLaThuile

-

Scale: site

-

Resolution: 30 or 60 min

-

Availability: varies by site http:\/\/www.fluxdata.org\/DataInfo\/Dataset%20Doc%20Lib\/SynthDataSummary.aspx

-

Notes: 2007 synthesis. Fluxnet2015 supercedes this for sites that have been updated

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/general-feedbackcommentssuggestions.html b/master/general-feedbackcommentssuggestions.html deleted file mode 100644 index 3ed819008..000000000 --- a/master/general-feedbackcommentssuggestions.html +++ /dev/null @@ -1,873 +0,0 @@ - - - - - - - 3.1 General Feedback/Comments/Suggestions | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

3.1 General Feedback/Comments/Suggestions

-

We want your ideas, thoughts, comments, and suggestions! As a community we are committed to creating an inclusive and supportive atmosphere so we all to reach out to us in the following ways:

-

Github: https://github.com/PecanProject/pecan -This is the main hub of communication surrounding PEcAn development. Check out the issues section to see known bugs, upcoming features, and ideas for future development. Feel free to comment on existing issues or open new ones with questions, bug reports, feature requests, and/or ideas.

-

Slack: https://pecanproject.slack.com/ -Slack serves as our day to day mode of communication. To join us in slack you will need to create an account first. This is done in 3 steps:

-
    -
  1. Request an inivitation to join Slack, this will be send by email to address you provided.
  2. -
  3. Check your inbox for an email from Slack with subject “Rob Kooper has invited you to join a Slack workspace”. This email should have a link that you can click to join slack.
  4. -
  5. When you click a webpage will open up that asks you to create an account, once that is done you can login into the slack chatrooms.
  6. -
-

Email: pecanproj[at]gmail.com -If you do not wish your communication with the team to be public, send us an email at the address above and we will get back to you as soon as possible.

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/geostreams.html b/master/geostreams.html deleted file mode 100644 index ef47c75e5..000000000 --- a/master/geostreams.html +++ /dev/null @@ -1,865 +0,0 @@ - - - - - - - 15.11 Geostreams | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

15.11 Geostreams

-

Scale: site

-

Resolution: varies

-

Availability: varies by site

-

Notes: This is a protocol, not a single archive. The PEcAn functions currently default to querying [https://terraref.ncsa.illinois.edu/clowder/api/geostreams], which requires login and contains data from only two sites (Urbana IL and Maricopa AZ). However the interface can be used with any server that supports the Geostreams API.

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/get-model-output.html b/master/get-model-output.html deleted file mode 100644 index f1d4bf949..000000000 --- a/master/get-model-output.html +++ /dev/null @@ -1,865 +0,0 @@ - - - - - - - 23.7 Get Model Output | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

23.7 Get Model Output

-
-

23.7.1 get.model.output(model)

-

This code first uses a model-specific model2netcdf.model function to convert the model output into a standard output format (MsTMIP). Then it extracts the data for requested variables specified in the settings file as settings$ensemble$variable, averages over the time-period specified as start.date and end.date, and stores the output in a file output.Rdata. The output.Rdata file contains two objects, sensitivity.output and ensemble.output, that is the model prediction for the parameter sets specified in sa.samples and ensemble.samples. In order to save bandwidth, if the model output is stored on a remote system PEcAn will perform these operations on the remote host and only return the output.Rdata object.

-
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/gldas.html b/master/gldas.html deleted file mode 100644 index 9dc34d918..000000000 --- a/master/gldas.html +++ /dev/null @@ -1,864 +0,0 @@ - - - - - - - 15.8 GLDAS | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

15.8 GLDAS

-

Scale: Global

-

Resolution: 3hr, 1 degree

-

Availability: 1948-2010

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/glossary.html b/master/glossary.html deleted file mode 100644 index 1131dc798..000000000 --- a/master/glossary.html +++ /dev/null @@ -1,868 +0,0 @@ - - - - - - - 23.10 Glossary | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

23.10 Glossary

-
    -
  • Inputs: data sets that are used, and file paths leading to them
  • -
  • Parameters: e.g. info set in settings file
  • -
  • Outputs: data sets that are dropped, and the file paths leading to them
  • -
- -
- -
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/helper-functions-for-unit-tests.html b/master/helper-functions-for-unit-tests.html deleted file mode 100644 index ca6c4ac0d..000000000 --- a/master/helper-functions-for-unit-tests.html +++ /dev/null @@ -1,868 +0,0 @@ - - - - - - - 32.5 Helper functions for unit tests | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

32.5 Helper functions for unit tests

-
    -
  • PEcAn.utils::tryl returns FALSE if function gives error
  • -
  • PEcAn.utils::temp.settings creates temporary settings file
  • -
  • PEcAn.DB::db.exists returns TRUE if connection to database is available
  • -
- -
- -
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/how-does-it-work.html b/master/how-does-it-work.html deleted file mode 100644 index 12ff94755..000000000 --- a/master/how-does-it-work.html +++ /dev/null @@ -1,863 +0,0 @@ - - - - - - - 17.1 How does it work? | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

17.1 How does it work?

-

Each server that runs the BETY database will have a unique machine_id and a sequence of ID’s associated. Whenever the user creates a new row in BETY it will receive an ID in the sequence. This allows us to uniquely identify where a row came from. This is information is crucial for the code that works with the synchronization since we can now copy those rows that have an ID in the sequence specified. If you have not asked for a unique ID your ID will be 99.

-

The synchronization code itself is split into two parts, loading data with the load.bety.sh script and exporting data using dump.bety.sh. If you do not plan to share data, you only need to use load.bety.sh to update your database.

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/how-to-create-your-own-version-of-documentation.html b/master/how-to-create-your-own-version-of-documentation.html deleted file mode 100644 index 752545432..000000000 --- a/master/how-to-create-your-own-version-of-documentation.html +++ /dev/null @@ -1,875 +0,0 @@ - - - - - - - 3.3 How to create your own version of Documentation | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

3.3 How to create your own version of Documentation

-

To create your own version of documentation you’ll need to follow these steps: -These procedures assume you have an github account, you forked pecan, you have cloned pecan locally, and have a TRAVIS account. -1. Create a repository under your github account with the name “pecan-documentation”. Clear it of any files. Set up the repository with Github Pages by going to the settings tab for that repository. -2. Create a personal access token for github: https://help.github.com/en/articles/creating-a-personal-access-token-for-the-command-line and copy it. -3. Create a TRAVIS environment variable called GITHUB_PAT and save the access token you made as a secret variable. -4. Create a branch from your local pecan repository with a name that starts with release/. (ie. Release/vtonydoc) -5. Make whichever changes you would like to the documentation and push it up to your fork.

-

From here TRAVIS will build your documentation. The web version of your documentation will be rendered with the url following the structure: username.github.io/pecan-documentation/pattern_after_release/

- -
- - - - -
- - -
-
-
- - -
- - - - - - - - - - - - - - - - diff --git a/master/icos-drought-2018.html b/master/icos-drought-2018.html deleted file mode 100644 index 1eb4e3ca0..000000000 --- a/master/icos-drought-2018.html +++ /dev/null @@ -1,865 +0,0 @@ - - - - - - - 15.13 ICOS Drought 2018 | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

15.13 ICOS Drought 2018

-

Scale: site

-

Resolution: 30 min

-

Availability: Varies by site

-

Notes: To use this option, set source as ICOS and a product tag containing drought2018 in pecan.xml

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/icos-ecosystem-archive.html b/master/icos-ecosystem-archive.html deleted file mode 100644 index df0e9f93d..000000000 --- a/master/icos-ecosystem-archive.html +++ /dev/null @@ -1,866 +0,0 @@ - - - - - - - 15.14 ICOS Ecosystem Archive | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

15.14 ICOS Ecosystem Archive

-

Scale: site

-

Resolution: 30 min

-

Availability: Varies by site

-

Notes: To use this option, set source as ICOS and a product tag containing etc in pecan.xml

- -
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/importing-functions-use-roxygen.html b/master/importing-functions-use-roxygen.html deleted file mode 100644 index e5303bb7c..000000000 --- a/master/importing-functions-use-roxygen.html +++ /dev/null @@ -1,875 +0,0 @@ - - - - - - - 31.4 Importing Functions: Use Roxygen | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

31.4 Importing Functions: Use Roxygen

-

PEcAn style is to import very few functions and instead use fully namespaced function calls (pkg::fn()) everywhere it’s practical to do so. In cases where double-colon notation would be especially burdensome, such as when importing custom binary operators like %>%, it’s acceptable to import specific functions into the package namespace. Do this by using Roxygen comments of the form #' @importFrom pkg function, not by hand-editing the NAMESPACE file.

-

If the import is only used in one or a few functions, use an @importFrom in the documentation for each function that uses it. If it is used all over the package, use a single @importFrom in the Roxygen documentation block for the whole package, which probably lives in a file called either zzz.R or <your_package_name>-package.R:

-
#' What your package does
-#'
-#' Longer description of the package goes here.
-#' Probably with links to other resources about it, citations, etc.
-#'
-#' @docType package
-#' @name PEcAn.yourpkg
-#' @importFrom magrittr %>%
-NULL
-

Roxygen will make sure there’s only one NAMESPACE entry per imported function no matter how many importFrom statements there are, but please pick a scheme (either import on every usage or once for the whole package), stick with it, and do not make function x() rely on an importFrom in the comments above function y().

-

Please do not import entire package namespaces (#' @import pkg); it increases the chance of function name collisions and makes it much harder to understand which package a given function was called from.

-

A special note about importing functions from the tidyverse: Be sure to import from the package(s) that actually contain the functions you want to use, e.g. Imports: dplyr, magrittr, purrr / @importFrom magrittr %>% / purrr::map(...), not Imports: tidyverse / @importFrom tidyverse %>% / tidyverse::map(...). The package named tidyverse is just a interactive shortcut that loads the whole collection of constituent packages; it doesn’t export any functions in its own namespace and therefore importing it into your package doesn’t make them available.

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/index.html b/master/index.html deleted file mode 100644 index 77e9e8a29..000000000 --- a/master/index.html +++ /dev/null @@ -1,885 +0,0 @@ - - - - - - - The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
- -
-

Welcome

-

Ecosystem science, policy, and management informed by the best available data and models

-

-

Our Mission:

-

Develop and promote accessible tools for reproducible ecosystem modeling and forecasting

-

PEcAn Website

-

Public Chat Room

-

Github Repository

- - - - - - -
- - - -
- - -
-
-
- - -
- - - - - - - - - - - - - - - - diff --git a/master/install-docker.html b/master/install-docker.html deleted file mode 100644 index f557397b0..000000000 --- a/master/install-docker.html +++ /dev/null @@ -1,924 +0,0 @@ - - - - - - - 4.2 Docker | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

4.2 Docker

-

This is a short documentation on how to start with Docker and PEcAn. -This will not go into much detail about about how to use Docker – for more details, see the main Docker topical page.

-
    -
  1. Install Docker. Follow the instructions for your operating system at https://www.docker.com/community-edition#/download. -Once Docker is installed, make sure it is running. -To test that Docker is installed and running, open a terminal and run the following commands:

    -
    docker run hello-world
    -

    If successful, this should return a message starting with "Hello from Docker!". -If this doesn’t work, there is something wrong with your configuration. You may need to open the Docker desktop app to complete the installation. -Refer to the Docker documentation for debugging.

    -

    NOTE: Depending on how Docker is installed and configured, you may have to run this command as sudo. -Try running the command without sudo first. -If that fails, but running as sudo succeeds, see these instructions for steps to use Docker as a non-root user.

  2. -
  3. Install docker compose. If you are running this on a Mac or Windows this might be already installed. On Linux you will need to install this it separately; see https://docs.docker.com/compose/install/.

    -

    To see if docker compose is successfully installed, use the following shell command:

    -
    docker compose version
    -

    This should print the current version of docker-compose. We have tested the instruction below with versions of docker compose 1.22 and above.

  4. -
  5. Download the PEcAn docker compose file. It is located in the root directory of the PEcAn source code. For reference, here are direct links to the latest stable version and the bleeding edge development version. (To download the files, you should be able to right click the link and select “Save link as”.) Make sure the file is saved as docker-compose.yml in a directory called pecan.

  6. -
  7. Initialize the PEcAn database and data images. The following docker compose commands are used to download all the data PEcAn needs to start working. For more on how they work, see our Docker topical pages.

    -
      -
    1. Create and start the PEcAn database container (without any data)

      -
      docker compose up -d postgres
      -

      If this is successful, the end of the output should look like the following:

      -
      Creating pecan-postgres-1 ... done
    2. -
    3. “Initialize” the data for the PEcAn database.

      -
      docker run --rm --network pecan_pecan pecan/db
      -

      This should produce a lot of output describing the database operations happening under the hood. -Some of these will look like errors, but this is normal. -This command succeeded if the output ends with the following (the syntax for creating a new user for accessing BetyDB):

      -
      docker compose run bety user 'login' 'password' 'full name' 'email' 1 1
    4. -
    5. Add a user to BetyDB using the example syntax provided as the last line of the output of the previous step:

      -
      # guest user
      -docker compose run --rm bety user guestuser guestuser "Guest User" guestuser@example.com 4 4
      -
      -# example user
      -docker compose run --rm bety user carya illinois "Carya Demo User" carya@example.com 1 1
    6. -
    7. Download and configure the core PEcAn database files.

      -
      docker run -ti --rm --network pecan_pecan --volume pecan_pecan:/data --env FQDN=docker pecan/data:develop
      -

      This will produce a lot of output describing file operations. -This command succeeded if the output ends with the following:

      -
      ######################################################################
      -Done!
      -###################################################################### 
    8. -
    9. Download the pecan/docker/env.example & save it as .env file. -Now, open the .env file & uncomment the following lines:

      -
      COMPOSE_PROJECT_NAME=pecan
      -PECAN_VERSION=develop
      -
      -

      Setting PECAN_VERSION=develop indicates that you want to run the bleeding-edge develop branch, meaning it may have bugs. To go ahead with the stable version you may set PECAN_VERSION=latest or PECAN_VERSION=<release-number> (For example 1.7.0). You can look at the list of all the releases of PEcAn to see what options are availble.

    10. -
  8. -
  9. Start the PEcAn stack. Assuming all of the steps above completed successfully, start the full stack by running the following shell command:

    -
    docker compose up -d
    -

    If all of the containers started successfully, you should be able to access the various components from a browser via the following URLs (if you run these commands on a remote machine replace localhost with the actual hostname).

    -
  10. -
-

To shut down the docker images run docker-compose stop. -For troubleshooting and advanced configuration, see our Docker topical pages.

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/install-native.html b/master/install-native.html deleted file mode 100644 index 93aa7edb7..000000000 --- a/master/install-native.html +++ /dev/null @@ -1,874 +0,0 @@ - - - - - - - 4.4 (Advanced) Native install | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

4.4 (Advanced) Native install

-

The full PEcAn system has a lot of dependencies, including R packages, compiled C and Fortran libraries, and system services and utilities. -Installing all of these side by side, and getting them to work harmoniously, is very time-consuming and challenging, which is why we strongly encourage new users to use the VM or Docker if possible.

-

In a nutshell, the process for manual installation is as follows:

-
    -
  1. Download the PEcAn source code from GitHub. The recommended way to do this is with the shell command git clone, i.e. git clone https://github.com/pecanproject/pecan.

  2. -
  3. Download the BETY source code from GitHub.

  4. -
  5. Install the PEcAn R packages and their dependencies. This can be done by running the shell command make inside the PEcAn source code directory. Note that many of the R packages on which PEcAn depends have system dependencies that are not included by default on most operating systems, but almost all of which should be available via your operating system’s package manager (e.g. Homebrew for MacOS, apt for Ubuntu/Debian/Mint Linux, yum for RedHat Fedora/CentOS).

  6. -
  7. Install and configure PostgreSQL

  8. -
  9. Install and configure the Apache web server.

  10. -
-

For more details, see our notes about OS Specific Installations.

- -
- -
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/install-vm.html b/master/install-vm.html deleted file mode 100644 index 344c2b1bc..000000000 --- a/master/install-vm.html +++ /dev/null @@ -1,886 +0,0 @@ - - - - - - - 4.1 Virtual Machine (VM) | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

4.1 Virtual Machine (VM)

-

The PEcAn virtual machine consists of all of PEcAn pre-compiled within a Linux operating system and saved in a “virtual machine” (VM). -Virtual machines allow for running consistent set-ups without worrying about differences between operating systems, library dependencies, compiling the code, etc.

-
    -
  1. Install VirtualBox This is the software that runs the virtual machine. You can find the download link and instructions at https://www.virtualbox.org. NOTE: On Windows you may see a warning about Logo testing, it is okay to ignore the warning.

  2. -
  3. Download the PEcAn VM You can find the download link at http://opensource.ncsa.illinois.edu/projects/artifacts.php?key=PECAN, under the “Files” header. Click the “.ova” file to begin the download. Note that the file is ~7 GB, so this download can take several minutes to hours depending on your connection speed. Also, the VM requires >4 GB of RAM to operate correctly. Please check current usage of RAM and shutdown processes as needed.

  4. -
  5. Import the VM Once the download is complete, open VirtualBox. In the VirtualBox menus, go to “File” → “Import Appliance” and locate the downloaded “.ova” file.

  6. -
-

For Virtualbox version 5.x: In the Appliance Import Settings, make sure you select “Reinitialize the MAC address of all network cards” (picture below). This is not selected by default and can result in networking issues since multiple machines might claim to have the same network MAC Address.

-

-

For Virtualbox versions starting with 6.0, there is a slightly different interface (see figure). Select “Generate new MAC addresses for all network adapters” from the MAC Address Policy:

-

-

NOTE: If you experience network connection difficulties in the VM with this enabled, try re-importing the VM without this setting selected).

-

Finally, click “Import” to build the Virtual Machine from its image.

-
    -
  1. Launch PEcAn Double click the icon for the PEcAn VM. A terminal window will pop up showing the machine booting up which may take a minute. It is done booting when you get to the pecan login: prompt. You do not need to login as the VM behaves like a server that we will be accessing through you web browser. Feel free to minimize the VM window.
  2. -
-
    -
  • If you do want to login to the VM, the credentials are as follows: username: carya, password: illinois (after the pecan tree, [Carya illinoinensis][pecan-wikipedia]).
  • -
-
    -
  1. Open the PEcAn web interface With the VM running in the background, open any web browser on the same machine and navigate to localhost:6480/pecan/ to start the PEcAn workflow. (NOTE: The trailing backslash may be necessary depending on your browser)

  2. -
  3. Advanced interaction with the VM is mostly done through the command line. You can perform these manipulations from inside the VM window. However, the VM is also configured for SSH access (username carya, hostname localhost, port 6422). For instance, to open an interactive shell inside the VM from a terminal on the host machine, use a command like ssh -l carya -p 6422 localhost (when prompted, the password is illinois, as above).

  4. -
-

These steps should be enough to get you started with running models and performing basic analyses with PEcAn. -For advanced details on VM configuration and maintenance, see the Advanced VM section.

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/installation-details.html b/master/installation-details.html deleted file mode 100644 index b0890f060..000000000 --- a/master/installation-details.html +++ /dev/null @@ -1,863 +0,0 @@ - - - - - - - 24 Installation details | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

24 Installation details

-

This chapter contains details about installing and maintaining the uncontainerized version of PEcAn on a virtual machine or a server. If you are running PEcAn inside of Docker, many of the particulars will be different and you should refer to the docker chapter instead of this one.

- -
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/installing-dependencies-let-the-machines-do-it.html b/master/installing-dependencies-let-the-machines-do-it.html deleted file mode 100644 index 395bfe3c1..000000000 --- a/master/installing-dependencies-let-the-machines-do-it.html +++ /dev/null @@ -1,864 +0,0 @@ - - - - - - - 31.6 Installing dependencies: Let the machines do it | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

31.6 Installing dependencies: Let the machines do it

-

In most cases you won’t need to think about how dependencies get installed – just declare them in your package’s DESCRIPTION and the installation will be handled automatically by R and devtools during the build process. The main exception is when a dependency relies on non-R software that R does not know how to install automatically. For example, rjags relies on JAGS, which might be installed in a different place on every machine. If your dependency falls in this category, you will know (because your CI builds will keep failing until you figure out how to fix it), but the exact details of the fix will differ for every case.

- -
- -
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/intermediate-user.html b/master/intermediate-user.html deleted file mode 100644 index 10afa87e0..000000000 --- a/master/intermediate-user.html +++ /dev/null @@ -1,877 +0,0 @@ - - - - - - - 7 More on the PEcAn Web Interface | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

7 More on the PEcAn Web Interface

-

This section will provide information to those wanting to take advantage of PEcAn’s customizations from the web interface.

- - -
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/introduction-4.html b/master/introduction-4.html deleted file mode 100644 index 1c10af690..000000000 --- a/master/introduction-4.html +++ /dev/null @@ -1,865 +0,0 @@ - - - - - - - 16.1 Introduction | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

16.1 Introduction

-

Welcome to the PEcAn Project API Documentation.

-

The Predictive Ecosystem Analyser (PEcAn) Project is an open source framework initiated to meet the demands for more accessible, transparent & repeatable modeling of ecosystems. PEcAn can be considered as an ecoinformatics toolbox combined with a set of workflows that wrap around ecosystem models that allow users to effectively perform data synthesis, propagation of uncertainty through a model & ecological predictions in an integrated fashion using a diverse repository of data & models.

-

Our API allows users to remotely interact with the PEcAn servers and leverage the functionalities provided by the PEcAn Project. It has been designed to follow common RESTful API conventions. Most operations are performed using the HTTP methods: GET (retrieve) & POST (create).

-

Please note that the PEcAn Project API is currently under active development and is possible that any information in this document is subject to change.

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/list-of-expectations.html b/master/list-of-expectations.html deleted file mode 100644 index bdc8fba24..000000000 --- a/master/list-of-expectations.html +++ /dev/null @@ -1,915 +0,0 @@ - - - - - - - 32.1 List of Expectations | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

32.1 List of Expectations

-
- -CM# - -ESM2M - -ESM2G -
-rcp26 - - -r1i1p1 - -r1i1p1 -
-rcp45 - -r1i1p1, r3i1p1,r5i1p1 - -r1i1p1 - -r1i1p1 -
-rcp60 - - -r1i1p1 - -r1i1p1 -
-rcp85 - -r1i1p1 - -r1i1p1 - -r1i1p1 -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FullAbbreviation
expect_that(x, is_true())expect_true(x)
expect_that(x, is_false())expect_false(x)
expect_that(x, is_a(y))expect_is(x, y)
expect_that(x, equals(y))expect_equal(x, y)
expect_that(x, is_equivalent_to(y))expect_equivalent(x, y)
expect_that(x, is_identical_to(y))expect_identical(x, y)
expect_that(x, matches(y))expect_matches(x, y)
expect_that(x, prints_text(y))expect_output(x, y)
expect_that(x, shows_message(y))expect_message(x, y)
expect_that(x, gives_warning(y))expect_warning(x, y)
expect_that(x, throws_error(y))expect_error(x, y)
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/load-settings.html b/master/load-settings.html deleted file mode 100644 index 1096eeeda..000000000 --- a/master/load-settings.html +++ /dev/null @@ -1,869 +0,0 @@ - - - - - - - 23.2 Load Settings | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

23.2 Load Settings

-
-

23.2.1 read.settings("/home/pecan/pecan.xml")

-
    -
  • loads settings
  • -
  • create directories
  • -
  • generates new xml, put in output folder
  • -
-
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/loading-code-dont-but-use-requirenamespace-when-you-do.html b/master/loading-code-dont-but-use-requirenamespace-when-you-do.html deleted file mode 100644 index c8acb8be3..000000000 --- a/master/loading-code-dont-but-use-requirenamespace-when-you-do.html +++ /dev/null @@ -1,878 +0,0 @@ - - - - - - - 31.5 Loading Code: Don’t… But Use requireNamespace When You Do | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

31.5 Loading Code: Don’t… But Use requireNamespace When You Do

-

The very short version of this section: We want to maintain clear separation between the package’s namespace (which we control and want to keep predictable) and the global namespace (which the user controls, might change in ways we have no control over, and will be justifiably angry if we change it in ways they were not expecting). Therefore, avoid attaching packages to the search path (so no Depends and no library() or require() inside functions), and do not explicitly load other namespaces if you can help it.

-

The longer version requires that we make a distinction often glossed over: Loading a package makes it possible for R to find things in the package namespace and does any actions needed to make it ready for use (e.g. running its .onLoad method, loading DLLs if the package contains compiled code, etc). Attaching a package (usually by calling library("somePackage")) loads it if it wasn’t already loaded, and then adds it to the search path so that the user can find things in its namespace. As discussed in the “Declaring Dependancies” section above, dependencies listed in Depends will be attached when your package is attached, but they will be neither attached nor loaded when your package is loaded without being attached.

-

Loading a dependency into the package namespace is undesirable because it makes it hard to understand our own code – if we need to use something from elsewhere, we’d prefer call it from its own namespace using :: (which implicitly loads the dependency!) or explicitly import it with a Roxygen @import directive. But in a few cases this isn’t enough. The most common reason to need to explicitly load a dependency is that some packages define new S3 methods for generic functions defined in other packages, but do not export these methods directly. We would prefer that these packages did not do this, but sometimes we have to use them anyway. An example from PEcAn is that PEcAn.MA needs to call as.matrix on objects of class mcmc.list. When the coda namespace is loaded, as.matrix(some_mcmc.list) can be correctly dispatched by base::as.matrix to the unexported method coda:::as.matrix.mcmc.list, but when coda is not loaded this dispatch will fail. Unfortunately coda does not export as.matrix.mcmc.list so we cannot call it directly or import it into the PEcAn.MA namespace, so instead we load the coda namespace whenever PEcAn.MA is loaded.

-

Attaching packages to the user’s search path is even more problematic because it makes it hard for the user to understand how your package will affect their own code. Packages attached by a function stay attached after the function exits, so they can cause name collisions far downstream of the function call, potentially in code that has nothing to do with your package. And worse, since names are looked up in reverse order of package loading, it can cause behavior that differs in strange ways depending on the order of lines that look independent of each other:

-
library(Hmisc)
-x = ...
-y = 3
-summarize(x) # calls Hmisc::summarize
-y2 <- some_package_that_attaches_dplyr::innocent.looking.function(y)
-# Loading required package: dplyr
-summarize(x) # Looks identical to previous summarize, but calls dplyr::summarize!
-

This is not to say that users will never want your package to attach another one for them, just that it’s rare and that attaching dependencies is much more likely to cause bugs than to fix them and additionally doesn’t usually save the package author any work.

-

One possible exception to the do-not-attach-packages rule is a case where your dependency ignores all good practice and wrongly assumes, without checking, that all of its own dependencies are attached; if its DESCRIPTION uses only Depends instead of Imports, this is often a warning sign. For example, a small-but-surprising number of packages depend on the methods package without proper checks (this is probably because most but not all R interpreters attach methods by default and therefore it’s easy for an author to forget it might ever be otherwise unless they happen to test with a but-not-all interpreter).

-

If you find yourself with a dependency that does this, accept first that you are relying on a package that is broken, and you should either convince its maintainer to fix it or find a way to remove the dependency from PEcAn. But as a short-term workaround, it is sometimes possible for your code to attach the direct dependency so that it will behave right with regard to its secondary dependencies. If so, make sure the attachment happens every time your package is loaded (e.g. by calling library(depname) inside your package’s .onLoad method) and not just when your package is attached (e.g. by putting it in Depends).

-

When you do need to load or attach a dependency, it is probably better to do it inside your package’s .onLoad method rather than in individual functions, but this isn’t ironclad. To only load, use requireNamespace(pkgname, quietly=TRUE) – this will make it available inside your package’s namespace while avoiding (most) annoying loadtime messages and not disturbing the user’s search path. To attach when you really can’t avoid it, declare the dependency in Depends and also attach it using library(pkgname) in your .onLoad method.

-

Note that scripts in inst/ are considered to be sample code rather than part of the package namespace, so it is acceptable for them to explicitly attach packages using library(). You may also see code that uses require(pkgname); this is just like library, but returns FALSE instead of erroring if package load fails. It is OK for scripts in inst/ that can do and do do something useful when a dependency is missing, but if it is used as if(!require(pkg)){ stop(...)} then replace it with library(pkg).

-

If you think your package needs to load or attach code for any reason, please note why in your pull request description and be prepared for questions about it during code review. If your reviewers can think of an alternate approach that avoids loading or attaching, they will likely ask you to use it even if it creates extra work for you.

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/maintain-vm.html b/master/maintain-vm.html deleted file mode 100644 index c0c9125e3..000000000 --- a/master/maintain-vm.html +++ /dev/null @@ -1,863 +0,0 @@ - - - - - - - 10.1 Updating the VM | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

10.1 Updating the VM

- -

The PEcAn VM is distributed with specific versions of PEcAn compiled. However, you do not need to constantly download the VM in order to update your code and version of BETY. To update and maintain your code you can follow the steps found in the Developer section in Updating PecAn and Code and BETY Database. However, if you are using the latest version of the PEcAn VM (>=1.7) you have the Dockerized version of PEcAn and need to follow the instructions under the DOCKER section to update your PEcAn and BETY containers.

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/met-drivers.html b/master/met-drivers.html deleted file mode 100644 index ea284f826..000000000 --- a/master/met-drivers.html +++ /dev/null @@ -1,861 +0,0 @@ - - - - - - - 15 Available Meteorological Drivers | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

15 Available Meteorological Drivers

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/meta-analysis.html b/master/meta-analysis.html deleted file mode 100644 index 1aaf63cdf..000000000 --- a/master/meta-analysis.html +++ /dev/null @@ -1,867 +0,0 @@ - - - - - - - 23.4 Meta Analysis | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

23.4 Meta Analysis

-
-

23.4.1 run.meta.analysis()

-

The meta-analysis code begins by distilling the trait.data to just the values needed for the meta-analysis statistical model, with this being stored in madata.Rdata. This reduced form includes the conversion of all error statistics into precision (1/variance), and the indexing of sites, treatments, and greenhouse. In reality, the core meta-analysis code can be run independent of the trait database as long as input data is correctly formatted into the form shown in madata.

-

The evaluation of the meta-analysis is done using a Bayesian statistical software package called JAGS that is called by the R code. For each trait, the R code will generate a [trait].model.bug file that is the JAGS code for the meta-analysis itself. This code is generated on the fly, with PEcAn adding or subtracting the site, treatment, and greenhouse terms depending upon the presence of these effects in the data itself.

-

Meta-analyses are run, and summary plots are produced.

-
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/miscellaneous.html b/master/miscellaneous.html deleted file mode 100644 index 40faa6a21..000000000 --- a/master/miscellaneous.html +++ /dev/null @@ -1,861 +0,0 @@ - - - - - - - 28 Miscellaneous | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

28 Miscellaneous

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/model-docker.html b/master/model-docker.html deleted file mode 100644 index 23d9be255..000000000 --- a/master/model-docker.html +++ /dev/null @@ -1,1031 +0,0 @@ - - - - - - - 25.5 Models using Docker | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

25.5 Models using Docker

-

This section will discuss how to add new models to PEcAn docker. To be able to add a new model to PEcAn when using docker is as simple as starting a new container. The model will come online and let the PEcAn framework know there is a new model available, there is no need to go through the process of registering this model with PEcAn. Users will be able to select this new model from web interface and run with this model selected.

-

For this process to work a docker image of the model will need to be created as well as small json file that is used to announce this new model. A separate service in PEcAn (monitor) will use this json file to keep track of all models available as well as register these models with PEcAn.

-

Model information -Model build -Common problems

-
-

25.5.1 Model information

-

Each model will have a small json file called model_info.json that is used to describe the model and used by the monitor service to register the model with PEcAn. This file will contain information about the model that is send as part of the heartbeat of the container to the monitor service. Below is an example of this file for the ED model. The required fields are name, type, version and binary. The fields type and version are used by PEcAn to send the messages to RabbitMQ. There is no need to specify the queue name explicitly. The queue name will be created by combining these two fields with an underscore. The field binary is used to point to the actual binary in the docker container.

-

There are 2 special values that can be used, @VERSION@ which will be replaced by the version that is passed in when building the container, and @BINARY@ which will be replaced by the binary when building the docker image.

-
{
-  "name": "ED2.2",
-  "type": "ED2",
-  "version": "@VERSION@",
-  "binary": "@BINARY@",
-  "description": "The Ecosystem Demography Biosphere Model (ED2) is an integrated terrestrial biosphere model incorporating hydrology, land-surface biophysics, vegetation dynamics, and soil carbon and nitrogen biogeochemistry",
-  "author": "Mike Dietze",
-  "contributors": ["David LeBauer", "Xiaohui Feng", "Dan Wang", "Carl Davidson", "Rob Kooper", "Shawn Serbin", "Alexey Shiklomanov"],
-  "links": {
-    "source": "https://github.com/EDmodel/ED2",
-    "issues": "https://github.com/EDmodel/ED2/issues"
-  },
-  "inputs": {},
-  "citation": ["Medvigy D., Wofsy S. C., Munger J. W., Hollinger D. Y., Moorcroft P. R. 2009. Mechanistic scaling of ecosystem function and dynamics in space and time: Ecosystem Demography model version 2. J. Geophys. Res. 114 (doi:10.1029/2008JG000812)"]
-}
-

Other fields that are recommended, but currently not used yet, are:

-
    -
  • description : a longer description of the model.
  • -
  • creator : contact person about this docker image.
  • -
  • contribuor : other people that have contributed to this docker image.
  • -
  • links : addtional links to help people when using this docker image, for example values that can be used are source to link to the source code, issues to link to issue tracking system, and documentation to link to model specific documentation.
  • -
  • citation : how the model should be cited in publications.
  • -
-
-
-

25.5.2 Model build

-

In general we try to minimize the size of the images. To be able to do this we split the process of creating the building of the model images into two pieces (or leverage of an image that exists from the original model developers). If you look at the example Dockerfile you will see that there are 2 sections, the first section will build the model binary, the second section will build the actual PEcAn model, which copies the binary from the first section.

-

This is an example of how the ED2 model is build. This will install all the packages needed to build ED2 model, gets the latest version from GitHub and builds the model.

-

The second section will create the actual model runner. This will leverage the PEcAn model image that has PEcAn already installed as well as the python code to listen for messages and run the actual model code. This will install some additional packages needed by the model binary (more about that below), copy the model_info.json file and change the @VERSION@ and @BINARY@ placeholders.

-

It is important values for type and version are set correct. The PEcAn code will use these to register the model with the BETY database, which is then used by PEcAn to send out a message to a specfic worker queue, if you do not set these variables correctly your model executor will pick up messages for the wrong model.

-

To build the docker image, we use a Dockerfile (see example below) and run the following command. This command will expect the Dockerfile to live in the model specific folder and the command is executed in the root pecan folder. It will copy the content of the pecan folder and make it available to the build process (in this example we do not need any additional files).

-

Since we can have multiple different versions of a model be available for PEcAn we ar using the following naming schema pecan/model-<modeltype>-<version>:<pecan version. For example the image below will be named pecan/model-ed2-git, since we do not specify the exact version it will be atomically be named pecan/model-ed2-git:latest.

-
docker build \
-    --tag pecan/model-ed2-git \
-    --file models/ed/Dockerfile \
-    .
-

Example of a Dockerfile, in this case to build the ED2 model.

-
ARG IMAGE_VERSION="latest"
-# ----------------------------------------------------------------------
-# BUILD MODEL BINARY
-# ----------------------------------------------------------------------
-FROM pecan/models:${IMAGE_VERSION} as model-binary
-
-# Some variables that can be used to set control the docker build
-ARG MODEL_VERSION=git
-
-# install dependencies
-RUN apt-get update \
-    && apt-get install -y --no-install-recommends \
-       build-essential \
-       curl \
-       gfortran \
-       git \
-       libhdf5-dev \
-       libopenmpi-dev \
-    && rm -rf /var/lib/apt/lists/*
-
-# download, unzip and build ed2
-WORKDIR /src
-RUN git -c http.sslVerify=false clone https://github.com/EDmodel/ED2.git \
-    && cd ED2/ED/build \
-    && curl -o make/include.mk.VM http://isda.ncsa.illinois.edu/~kooper/EBI/include.mk.opt.Linux \
-    && if [ "${MODEL_VERSION}" != "git" ]; then git checkout ${MODEL_VERSION}; fi \
-    && ./install.sh -g -p VM
-
-########################################################################
-
-# ----------------------------------------------------------------------
-# BUILD PECAN FOR MODEL
-# ----------------------------------------------------------------------
-FROM pecan/models:latest
-
-# ----------------------------------------------------------------------
-# INSTALL MODEL SPECIFIC PIECES
-# ----------------------------------------------------------------------
-
-RUN apt-get update \
-    && apt-get install -y --no-install-recommends \
-       libgfortran3 \
-       libopenmpi2 \
-    && rm -rf /var/lib/apt/lists/*
-
-# ----------------------------------------------------------------------
-# SETUP FOR SPECIFIC MODEL
-# ----------------------------------------------------------------------
-
-# Some variables that can be used to set control the docker build
-ARG MODEL_VERSION=git
-
-# Setup model_info file
-COPY models/ed/model_info.json /work/model.json
-RUN sed -i -e "s/@VERSION@/${MODEL_VERSION}/g" \
-           -e "s#@BINARY@#/usr/local/bin/ed2.${MODEL_VERSION}#g" /work/model.json
-
-# COPY model binary
-COPY --from=model-binary /src/ED2/ED/build/ed_2.1-opt /usr/local/bin/ed2.${MODEL_VERSION}
-

WARNING: Dockerfile environment variables set via ENV are assigned all at once; they do not evaluate successively, left to right. -Consider the following block:

-
# Don't do this!
-ENV MODEL_TYPE="SIPNET" \
-    MODEL_VERSION=136 \
-    MODEL_TYPE_VERSION=${MODEL_TYPE}_${MODEL_VERSION}   # <- Doesn't know about MODEL_TYPE or MODEL_VERSION!
-

In this block, the expansion for setting MODEL_TYPE_VERSION is not aware of the current values of MODEL_TYPE or MODEL_VERSION, and will therefore be set incorrectly to just _ (unless they have been set previously, in which case it will be aware only of their earlier values). -As such, variables depending on other variables must be set in a separate, subsequent ENV statement than the variables they depend on.

-

Once the model has build and is working we can add it to the PEcAn stack and be able to use this model in the web interface. There are two methods to start this new model. First, we can add it to the docker-compose.yml file and start the container using docker-compose -p pecan -d up.

-
  sipnet:
-    image: pecan/model-ed2-git
-    networks:
-      - pecan
-    volumes:
-      - pecan:/data
-    depends_on:
-       - rabbitmq
-    restart: unless-stopped
-

Alternatively we can start the container manually using the following command.

-
docker run \
-    --detach \
-    --rm \
-    --name pecan-ed2-git \
-    --networks pecan_pecan \
-    --volume pecan_pecan:/data
-    pecan/model-ed2-git
-
-
-

25.5.3 Common problems

-

Following are some solutions for common problems that you might encounter when building the docker images for a model.

-
-
-

25.5.4 Debugging missing libraries

-

When building the model binary it might require specific libraries to be installed. In the second stage the model binary is copied into a new image, which could result in the binary missing specific libraries. In the case of the ED2 model the following was used to find the libraries that are needed to be installed (libgfortran5 and libopenmpi3).

-

The first step is to build the model using the Dockerfile (in this case the ap-get install was missing in the second stage).

-
Step 5/9 : RUN git clone https://github.com/EDmodel/ED2.git     && cd ED2/ED/build     && curl -o make/include.mk.VM http://isda.ncsa.illinois.edu/~kooper/EBI/include.mk.opt.`uname -s`     && if [ "${MODEL_VERSION}" != "git" ]; then git checkout ${MODEL_VERSION}; fi     && ./install.sh -g -p VM
-... LOTS OF OUTPUT ...
-make[1]: Leaving directory '/src/ED2/ED/build/bin-opt-E'
-Installation Complete.
-Removing intermediate container a53eba9a8fc1
- ---> 7f23c6302130
-Step 6/9 : FROM pecan/executor:latest
- ---> f19d81b739f5
-... MORE OUTPUT ...
-Step 9/9 : COPY --from=model-binary /src/ED2/ED/build/ed_2.1-opt /usr/local/bin/ed2.${MODEL_VERSION}
- ---> 07ac841be457
-Successfully built 07ac841be457
-Successfully tagged pecan/pecan-ed2:latest
-

At this point we have created a docker image with the binary and all PEcAn code that is needed to run the model. Some models (especially those build as native code) might be missing additional packages that need to be installed in the docker image. To see if all libraries are installed for the binary.

-
> docker run -ti --rm pecan/pecan-ed2 /bin/bash
-root@8a95ee8b6b47:/work# ldd /usr/local/bin/ed2.git  | grep "not found"
-    libmpi_usempif08.so.40 => not found
-    libmpi_usempi_ignore_tkr.so.40 => not found
-    libmpi_mpifh.so.40 => not found
-    libmpi.so.40 => not found
-    libgfortran.so.5 => not found
-

Start the build container again (this is the number before the line FROM pecan/executor:latest, 7f23c6302130 in the example), and find the missing libraries listed above (for example libmpi_usempif08.so.40):

-
> docker run --rm -ti 7f23c6302130
-root@e716c63c031f:/src# dpkg -S libmpi_usempif08.so.40
-libopenmpi3:amd64: /usr/lib/x86_64-linux-gnu/openmpi/lib/libmpi_usempif08.so.40.10.1
-libopenmpi3:amd64: /usr/lib/x86_64-linux-gnu/libmpi_usempif08.so.40.10.1
-libopenmpi3:amd64: /usr/lib/x86_64-linux-gnu/libmpi_usempif08.so.40
-

This shows the pages is libopenmpi3 that needs to be installed, do this for all missing packages, modify the Dockerfile and rebuild. Next time you run the ldd command there should be no more packages being listed.

- -
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/models-biocro.html b/master/models-biocro.html deleted file mode 100644 index 05279070f..000000000 --- a/master/models-biocro.html +++ /dev/null @@ -1,937 +0,0 @@ - - - - - - - 14.1 BioCro | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

14.1 BioCro

- ---- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Model Information
Home Pagehttps://github.com/ebimodeling/biocro/blob/0.951/README.md
Source Codehttps://github.com/ebimodeling/biocro/tree/0.951
LicenseUniversity of Illinois/NCSA Open Source License
AuthorsFernando E. Miguez, Deepak Jaiswal, Justin McGrath, David LeBauer, Scott Rohde, Dan Wang
PEcAn IntegrationDavid LeBauer, Chris Black, Kristina Riemer
-
-

14.1.1 Introduction

-

BioCro is a model that estimates photosynthesis at the leaf, canopy, and ecosystem levels and determines plant biomass allocation and crop yields, using underlying physiological and ecological processes to do so.

-
-
-

14.1.2 PEcAn configuration file additions

-

The following sections of the PEcAn XML are relevant to the BioCro model:

-
    -
  • model -
      -
    • revision – Model version number
    • -
  • -
  • run -
      -
    • site/id – ID associated with desired site from BETYdb site entry
    • -
    • inputs -
        -
      • met/output – Set as BIOCRO
      • -
      • met/path – Path to file containing meteorological data
      • -
    • -
  • -
-
-
-

14.1.3 Model specific input files

-

List of inputs required by model, such as met, etc.

-
-
-

14.1.4 Model configuration files

-

Genus-specific parameter files are secretly required. These are stored in the PEcAn.BIOCRO package and looked up under the hood.

-

write.configs.BIOCRO looks for defaults in this order: first any file at a path specified by settings$pft$constants$file, next by matching the genus name in datasets exported by the BioCro package, and last by matching the genus name in PEcAn.BIOCRO’s extdata/defaults directory.

-

When adding a new genus, it is necessary to provide a new default parameter file in PEcAn.BIOCRO inst/extdata/defaults and also (for v<1.0) update the call_biocro() function.

-

BioCro uses a config.xml file similar to ED2. At this time, no other template files are required.

-
-
-

14.1.5 Installation notes

-

BioCro can be run standalone using the model’s R package. Instructions for installing and using the package are in the GitHub repo’s README file.

-

PEcAn works with v. 0.9x and 1.x. Support for v 2.x is not implemented. Support for v 0.9x is most robust and tested.

-

To install, use

-
remotes::install_github('ebimodeling/biocro@0.951')
- -
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/models-clm.html b/master/models-clm.html deleted file mode 100644 index 1044ea995..000000000 --- a/master/models-clm.html +++ /dev/null @@ -1,910 +0,0 @@ - - - - - - - 14.2 CLM | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

14.2 CLM

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Model Information
Home Page
Source Code
License
Authors
PEcAn Integration
-

Introduction

-

Introduction about model

-

PEcAn configuration file additions

-

Should list the model specific additions to the PEcAn file here

-

Model specific input files -List of inputs required by model, such as met, etc.

-

Model configuration files

-

MODEL is configured using 3 files which are placed in the run folder, as well as a symbolic link to the met file.

-
    -
  • file1 : template for this file is located at models/MODEL/inst/file1 and is not modified.
    -
  • -
  • file2 : template for this file is located at models/MODEL/inst/file2 and is not modified.
    -
  • -
  • file3 : template for this file is in models/MODEL/inst/file3 or it is specified in the <model> section as <template>. The values in this template are replaced by those computed in the earlier stages of PEcAN.
  • -
-

Installation notes

-

This section contains notes on how to compile the model. The notes for the VM might work on other machines or configurations as well.

-

VM

- -
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/models-dalec.html b/master/models-dalec.html deleted file mode 100644 index 94a9aea39..000000000 --- a/master/models-dalec.html +++ /dev/null @@ -1,910 +0,0 @@ - - - - - - - 14.3 DALEC | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

14.3 DALEC

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Model Information
Home Page
Source Code
License
Authors
PEcAn Integration
-

Introduction

-

Introduction about model

-

PEcAn configuration file additions

-

Should list the model specific additions to the PEcAn file here

-

Model specific input files

-

List of inputs required by model, such as met, etc.

-

Model configuration files

-

MODEL is configured using 3 files which are placed in the run folder, as well as a symbolic link to the met file.

-
    -
  • file1 : template for this file is located at models/MODEL/inst/file1 and is not modified.
    -
  • -
  • file2 : template for this file is located at models/MODEL/inst/file2 and is not modified.
    -
  • -
  • file3 : template for this file is in models/MODEL/inst/file3 or it is specified in the <model> section as <template>. The values in this template are replaced by those computed in the earlier stages of PEcAN.
  • -
-

Installation notes

-

This section contains notes on how to compile the model. The notes for the VM might work on other machines or configurations as well.

-

VM

- -
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/models-ed.html b/master/models-ed.html deleted file mode 100644 index 2dccfc6ae..000000000 --- a/master/models-ed.html +++ /dev/null @@ -1,1118 +0,0 @@ - - - - - - - 14.4 ED2 | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

14.4 ED2

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Model Information
Home Pagehttp://moorcroftlab.oeb.harvard.edu/
Source Codehttps://github.com/EDmodel/ED2
License
AuthorsPaul Moorcroft, …
PEcAn IntegrationMichael Dietze, Rob Kooper
-
-

14.4.1 Introduction

-

Introduction about ED model

-
-
-

14.4.2 PEcAn configuration file additions

-

The following sections of the PEcAn XML are relevant to the ED model:

-
    -
  • model -
      -
    • id – BETY model ID. Each ID corresponds to a different revision of ED (see below)

    • -
    • revision – The revision (a.k.a. release) number of ED (e.g. “r82”). “rgit” indicates the latest code on the ED repository.

    • -
    • edin – Name of the template ED2IN configuration file. If this is a functional path that points to a specific file, that file is used. If no file is found following the path literally, the workflow will try the path relative to the PEcAn.ED2 package using system.file (recall that files in inst are moved in the package root, but all other directory structure is preserved). If this is omitted, PEcAn.ED2::write.configs.ED2 will look for a file called ED2IN.<revision> (e.g. ED2IN.rgit, ED2IN.r86) in the PEcAn.ED2 package.

      -
        -
      • Example: <edin>ED2IN.rgit</edin> will use the ED2IN.rgit file shipped with PEcAn.ED2 regardless of the revision of ED used. (Note however that if a file called ED2IN.rgit exists in the workflow runtime directory, that file will be used instead).
      • -
    • -
    • start.date, end.date – Run start and end date, respectively

    • -
    • met.start, met.end – Start and end year of meteorology inputs. By default (if omitted), these are set to the years of start.date and end.date, respectively. Setting these values to a shorter interval than start.date and end.date will cause ED to loop the meteorology input over the specified years. This may be useful for, for example, spinning up ED under a set of constant climate conditions.

    • -
    • phenol.scheme

    • -
    • phenol

    • -
    • phenol.start

    • -
    • phenol.end

    • -
    • all_pfts – (Logical) If false or missing (default), only run ED2 with the PFTs configured via PEcAn (i.e. in the <pfts> section of the XML). If true, run with all 17 of ED2’s PFTs, using ED2’s internal default parameters for all PFTs not configured through PEcAn. See below for more details.

    • -
    • ed2in_tags – Named list of additional tags in the ED2IN to be modified. These modifications override any of those set by other parts of the PEcAn workflow. These tags must be in all caps. Any tags that are not already in the ED2IN file will be added; this makes this an effective way to run newer versions of ED2 that have new ED2IN parameters without having to provide an entire new ED2IN. For example:

      -
      <model>
      -  <ed2in_tags>
      -    <IOOUTPUT>0</IOOUTPUT>
      -    <PLANT_HYDRO_SCHEME>0</PLANT_HYDRO_SCHEME>
      -    <ISTOMATA_SCHEME>0</ISTOMATA_SCHEME>
      -    <ISTRUCT_GROWTH_SCHEME>0</ISTRUCT_GROWTH_SCHEME>
      -    <TRAIT_PLASTICITY_SCHEME>0</TRAIT_PLASTICITY_SCHEME>
      -  </ed2in_tags>
      -</model>
    • -
    • barebones_ed2in – Whether or not to try to annotate the ED2IN file with comments. If “true”, skip all comments and only write the tags themselves. If “false” (default), try to transfer comments from the template file into the target file.

    • -
    • jobtemplate

    • -
    • prerun – String of commands to be added to the job.sh model execution script before the model is run. Multiple commands should be separated by proper bash syntax – i.e. either with && or ;.

      -
        -
      • One common use of this argument is to load modules on some HPC systems – for instance:

        -
        <prerun>module load git hdf5</prerun>
      • -
      • If your particular version of ED is failing early during execution with a mysterious “Segmentation fault”, that may indicate that its process is exceeding its stack limit. In this case, you may need to remove the stack limit restriction with a prerun command like the following:

        -
        <prerun>ulimit -s unlimited</prerun>
      • -
    • -
    • postrun – Same as <prerun>, but for commands to be run after model execution.

    • -
    • binary – The full path to the ED2 binary on the target machine.

    • -
    • binary_args – Additional arguments to be passed to the ED2 binary. Some common arguments are:

      -
        -
      • -s – Delay OpenMPI initialization until the last possible moment. This is needed when running ED2 in a Docker container. It is included by default when the host is rabbitmq.
      • -
      • -f /path/to/ED2IN – Full path to a specific ED2IN namelist file. Typically, this is not needed because, by default, ED searches for the ED2IN in the current directory and the PEcAn workflow places the ED2IN file and a symbolic link to the ED executable in the same (run) directory for you.
      • -
    • -
  • -
  • run/site -
      -
    • lat – Latitude coordinate of site
    • -
    • lon – Longitude coordinate of site
    • -
  • -
  • inputs -
      -
    • met/path – Path to ED_MET_DRIVER_HEADER file
    • -
    • pss: [required] location of patch file
    • -
    • css: [required] location of cohort file
    • -
    • site: [optional] location of site file
    • -
    • lu: [required] location of land use file
    • -
    • thsums: [required] location of thermal sums file
    • -
    • veg: [required] location of vegetation data
    • -
    • soil: [required] location of soil data
    • -
  • -
-
-
-

14.4.3 PFT configuration in ED2

-

ED2 has more detailed PFTs than many models, and a more complex system for configuring these PFTs. -ED2 has 17 PFTs, based roughly on growth form (e.g. tree vs. grass), biome (tropical vs. temperate), leaf morphology (broad vs. needleleaf), leaf phenology (evergreen vs. deciduous), and successional status (e.g. early, mid, or late). -Each PFT is assigned an integer (1-17), which is used by the ED model to assign default model parameters. -The mappings of these integers onto PFT definitions are not absolute, and may change as the ED2 source code evolves. -Unfortunately, the only authoritative source for these PFT definitions for any given ED2 version is the Fortran source code of that version. -The following is the mapping as of ED2 commit 24e6df6a (October 2018):

-
    -
  1. C4 grass
  2. -
  3. Early-successional tropical
  4. -
  5. Mid-successional tropical
  6. -
  7. Late-successional tropical
  8. -
  9. Temperate C3 grass
  10. -
  11. Northern pine
  12. -
  13. Southern pine
  14. -
  15. Late-successional conifer
  16. -
  17. Early-successional temperate deciduous
  18. -
  19. Mid-successional temperate deciduous
  20. -
  21. Late-successional temperate deciduous
  22. -
  23. Agricultural (crop) 1
  24. -
  25. Agricultural (crop) 2
  26. -
  27. Agricultural (crop) 3
  28. -
  29. Agricultural (crop) 4
  30. -
  31. Subtropical C3 grass (C4 grass with C3 photosynthesis)
  32. -
  33. “Araucaria” (non-optimized southern pine), or liana
  34. -
-

ED2 parameter defaults are hard-coded in its Fortran source code. -However, most parameters can be modified via an XML file (determined by the ED2IN IEDCNFGF field; usually config.xml in the same directory as the ED2IN file). -The complete record of all parameters (defaults and user overrides) used by a given ED2 run is stored in a history.xml file (usually in the same directory as the ED2IN) – this is the file to check to make sure that an ED2 run is parameterized as you expect.

-

As with other models, PEcAn can set ED2 parameters using its built-in trait meta analysis. -The function specifically responsible for writing the config.xml is PEcAn.ED2::write.config.xml.ED2 (which is called as part of the more general PEcAn.ED2::write.config.ED2). -The configuration process proceeds as follows:

-

First, the mappings between PEcAn PFT names and ED2 PFT numbers are determined according to the following logic:

-
    -
  • If the PFT has a <ed2_pft_number> XML tag, that number is used. For example:

    -
    <pft>
    -  <name>umbs.early_hardwood</name>
    -  <ed2_pft_number>9</ed2_pft_number>
    -</pft>
  • -
  • If <ed2_pft_number> is not provided, the code tries to cross-reference the PFT name against the pftmapping.csv data provided with the PEcAn.ED2 package. If the name is not matched (perfectly!), the function will exit with an error.

  • -
-

Second, the PFT number from the previous step is used to write that PFT’s parameters to the config.xml. -The order of precedence for parameters is as follows (from highest to lowest):

-
    -
  1. Explicit user overrides. -These are specified via a <constants> tag in the PFT definition in the pecan.xml. -For example:

    -
    <pft>
    -  <name>umbs.early_hardwood</name>
    -  <constants>
    -     <sla>36.3</sla>
    -  </constants>
    -</pft>
    -

    Note that these values are passed through PEcAn.ED2::convert.samples.ED, so they should generally be given in PEcAn’s default units rather than ED2’s.

  2. -
  3. Samples from the PEcAn meta analysis. -These are also converted via PEcAn.ED2::convert.samples.ED.

  4. -
  5. ED2 defaults that PEcAn knows about. -These are stored in the edhistory.csv file inside of PEcAn.ED2 -This file is re-generated manually whenever there is a new version of ED2, so while we try our best to keep it up to date, there is no guarantee that it is.

  6. -
  7. (Implicitly) Defaults in the ED2 Fortran source code. -In general, our goal is to set all parameters through PEcAn (via steps 1-3), but if you are running PEcAn with new or experimental versions of ED2, you should be extra careful to make sure ED2 is running with the parameters you intend. -Again, the best way to know which parameters ED2 is actually using is to check the history.xml file produced once the run starts.

  8. -
-

The ED2IN field INCLUDE_THESE_PFT controls which of these PFTs are included in a given ED2 run. -By default, PEcAn will set this field to only include the PFTs specified by the user. -This is the recommended behavior because it ensures that all PFTs in ED2 were parameterized (one way or another, at least partially) through PEcAn. -However, if you would like ED2 to run with all 17 PFTs (NOTE: using ED2’s internal defaults for all PFTs not specified by the user!), you can set the <all_pfts> XML tag (in the <model> section) to true:

-
<model>
-    <all_pfts>true</all_pfts>
-</model>
-
-
-

14.4.4 Model specific input files

-

List of inputs required by model, such as met, etc.

-
-
-

14.4.5 Model configuration files

-

ED2 is configured using 2 files which are placed in the run folder.

-
    -
  • ED2IN : template for this file is located at models/ed/inst/ED2IN.<revision>. The values in this template that need to be modified are described below and are surrounded with @ symbols.
  • -
  • config.xml : this file is generated by PEcAn. Some values are stored in the pecan.xml in <pfts><pft><constants> section as well as in <model> section.
  • -
-

An example of the template can be found in ED2IN.r82

-

The ED2IN template can contain the following variables. These will be replaced with actual values when the model configuration is written.

-
    -
  • **@ENSNAME@** : run id of the simulation, used in template for NL%EXPNME

  • -
  • **@START_MONTH@** : start of simulation UTC time, from <run><start.date>, used in template for NL%IMONTHA
    -

  • -
  • **@START_DAY@** : start of simulation UTC time, from <run><start.date>, used in template for NL%IDATEA
    -

  • -
  • **@START_YEAR@** : start of simulation UTC time, from <run><start.date>, used in template for NL%IYEARA
    -

  • -
  • **@END_MONTH@** : end of simulation UTC time, from <run><end.date>, used in template for NL%IMONTHZ
    -

  • -
  • **@END_DAY@** : end of simulation UTC time, from <run><end.date>, used in template for NL%IDATEZ
    -

  • -
  • **@END_YEAR@** : end of simulation UTC time, from <run><end.date>, used in template for NL%IYEARZ

  • -
  • **@SITE_LAT@** : site latitude location, from <run><site><lat>, used in template for NL%POI_LAT
    -

  • -
  • **@SITE_LON@** : site longitude location, from <run><site><lon>, used in template for NL%POI_LON

  • -
  • **@SITE_MET@** : met header location, from <run><site><met>, used in template for NL%ED_MET_DRIVER_DB
    -

  • -
  • **@MET_START@** : first year of met data, from <run><site><met.start>, used in template for NL%METCYC1
    -

  • -
  • **@MET_END@** : last year of met data, from <run><site><met.end>, used in template for NL%METCYCF

  • -
  • **@PHENOL_SCHEME@** : phenology scheme, if this variabe is 1 the following 3 fields will be used, otherwise they will be set to empty strings, from <model><phenol.scheme>, used in template for NL%IPHEN_SCHEME
    -

  • -
  • **@PHENOL_START@** : first year for phenology, from <model><phenol.start>, used in template for NL%IPHENYS1 and NL%IPHENYF1
    -

  • -
  • @PHENOL_END@** : last year for phenology, from <model><phenol.end>, used in template for NL%IPHENYSF and NL%IPHENYFF
    -
    @PHENOL@** : path and prefix of the prescribed phenology data, from * <model><phenol>, used in template for NL%PHENPATH

  • -
  • **@SITE_PSSCSS@** : path and prefix of the previous ecosystem state, from <model><psscss>, used in template for NL%SFILIN
    -

  • -
  • **@ED_VEG@** : path and prefix of the vegetation database, used only to determine the land/water mask, from <model><veg>, used in template for NL%VEG_DATABASE
    -

  • -
  • **@ED_SOIL@** : path and prefix of the soil database, used to determine the soil type, from <model><soil>, used in template for NL%SOIL_DATABASE
    -

  • -
  • **@ED_INPUTS@** : input directory with dataset to initialise chilling degrees and growing degree days, which is used to drive the cold-deciduous phenology, from <model><inputs>, used in template for NL%THSUMS_DATABASE

  • -
  • **@FFILOUT@** : path and prefix for analysis files, generated from <run><host><outdir>/run.id/analysis, used in template for NL%FFILOUT
    -

  • -
  • **@SFILOUT@** : path and prefix for history files, generated from <run><host><outdir>/run.id/history, used in template for NL%SFILOUT

  • -
  • **@CONFIGFILE@** : XML file containing additional parameter settings, this is always “config.xml”, used in template for NL%IEDCNFGF

  • -
  • @OUTDIR@** : location where output files are written (without the runid**), from <run><host><outdir>, should not be used.
    -

  • -
  • **@SCRATCH@** : local scratch space for outputs, generated /scratch/<username>/run$scratch, should not be used right now since it only works on ebi-cluster

  • -
-
-
-

14.4.6 Installation notes

-

This section contains notes on how to compile the model. The notes for the VM might work on other machines or configurations as well.

-
-

14.4.6.1 VM

-
-
-

14.4.6.2 BU geo

-
-
-

14.4.6.3 TACC lonestar

-
module load hdf5
-curl -o ED.r82.tgz http://isda.ncsa.illinois.edu/~kooper/EBI/ED.r82.tgz
-tar zxf ED.r82.tgz
-rm ED.r82.tgz
-cd ED.r82/ED/build/bin
-curl -o include.mk.lonestar http://isda.ncsa.illinois.edu/~kooper/EBI/include.mk.lonestar
-make OPT=lonestar
-
-
-

14.4.6.4 TACC stampede

-
module load hdf5
-curl -o ED.r82.tgz http://isda.ncsa.illinois.edu/~kooper/EBI/ED.r82.tgz
-tar zxf ED.r82.tgz
-rm ED.r82.tgz
-cd ED.r82/ED/build/bin
-curl -o include.mk.stampede http://isda.ncsa.illinois.edu/~kooper/EBI/include.mk.stampede
-make OPT=stampede
- -
-
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/models-gday.html b/master/models-gday.html deleted file mode 100644 index f3b392689..000000000 --- a/master/models-gday.html +++ /dev/null @@ -1,910 +0,0 @@ - - - - - - - 14.5 GDAY | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

14.5 GDAY

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Model Information
Home Page
Source Code
License
Authors
PEcAn Integration
-

Introduction

-

Introduction about model

-

PEcAn configuration file additions

-

Should list the model specific additions to the PEcAn file here

-

Model specific input files

-

List of inputs required by model, such as met, etc.

-

Model configuration files

-

MODEL is configured using 3 files which are placed in the run folder, as well as a symbolic link to the met file.

-
    -
  • file1 : template for this file is located at models/MODEL/inst/file1 and is not modified.
    -
  • -
  • file2 : template for this file is located at models/MODEL/inst/file2 and is not modified.
    -
  • -
  • file3 : template for this file is in models/MODEL/inst/file3 or it is specified in the <model> section as <template>. The values in this template are replaced by those computed in the earlier stages of PEcAN.
  • -
-

Installation notes

-

This section contains notes on how to compile the model. The notes for the VM might work on other machines or configurations as well.

-

VM

- -
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/models-ldndc.html b/master/models-ldndc.html deleted file mode 100644 index a85044bc0..000000000 --- a/master/models-ldndc.html +++ /dev/null @@ -1,971 +0,0 @@ - - - - - - - 14.6 LDNDC | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

14.6 LDNDC

- ---- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Model Information
Home Pagehttps://ldndc.imk-ifu.kit.edu/about/model.php
Source Code
License
AuthorsProf. Dr. Klaus Butterbach-Bahl, Dr. Edwin Haas, …
PEcAn IntegrationHenri Kajasilta
-
-

14.6.1 Introduction

-

LandscapeDNDC is designed to simulate biosphere/hydrosphere processes of forest, arable and grassland ecosystems. The design of LDNDC allows different models/modules to be plugged in, allowing the simulations for different ecosystems. The most up-to-date information on LDNDC can be found here, as well as the authors, users guide and documentation of the model: https://ldndc.imk-ifu.kit.edu/index.php

-

Please note! The PEcAn setups here are written for the LDNDC version that has been downloaded on 2022-10-19. Some of the newer versions of LDNDC may have differences in the names of variables and parameters.

-

PEcAn configuration file additions

-

The following sections of the PEcAn XML are relevant or have influence at this development stage:

-

ensemble -variable: LAI, GPP, NPP, NEE, Respirations (AutoResp, HeteroResp, TotalResp), biomass of harvesting (harvest_carbon_flux), AGB and BGB (below_ground_carbon_content).

-

model -id: Corresponding the id of LDNDC in BETY.

-

run -inputs -start_date: Start date of the simulation -end_date: End date of the simulation

-

Paths to meteorological drivers, events and initial conditions. Paths to airchemistry and groundwater files, may also be included, but are not required.

-
-
-

14.6.2 Model specific input files

-

LDNDC takes multiple input files, and can also generate multiple output files. These notes on input files are written from the PEcAn integration point of view, and detailed information on input files can be found in the user guide, which is available via the links above.

-

Input files:

-

Project — Contains essential information in order to set up the simulation run. For example, the file contains paths to other files that will be used in the simulations, as well as the time period in which the simulations will take place.

-

Setup — Defines which modules are used.

-

Climate — Met data that is used in simulations.

-

Speciesparameters — Species used in the simulations should be defined here and the file contains the parametrization for the species.

-

Siteparameters — Works similarly to speciesparameters, but from the point of view of site parametrization.

-

Event — Holds information about the events, which are essential in arable simulations.

-

Site — Specific information about the site (e.g. carbon and nitrogen contents, hydrological characteristics).

-

Airchemistry — Information about the air chemistry.

-
-

14.6.2.1 Model configuration files

-

Due to the number of different input files, there are several templates that are used in the model configuration. -The templates are located in models/ldndc/inst/. These templates wll be populated with parametrizations and initial conditions when configurations are written. The drivers and events on the other hand should be informed by giving a path to the driver/event file in pecan.xml.

-

Many configurations for the model are (less surprisingly) written in write.configs.LDNDC. This is the file that may need to be modified in order to make the model to run appropriately in terms of the simulated species. Currently, there are a few crop species that the workflow recognizes (triticale, barley and oat), a couple of grass species (timothy and meadow) and one forest species (pipy). However, if other species options are needed, it is relatively easy to modify the code in configurations and add them so that the workflow can handle them. Also, the path for running the model binary is created in write.configs.LDNDC and will likely need some changes depending on the location of the model binaries/configurations on the user’s server.

-
    -
  • project.ldndc : The project file is populated in write.configs.LDNDC based on the input from the PEcAn settings. In addition to containing the correct names for the input files used in the simulation, the project file contains the start and end points for the simulation period. The file also specifies the path where the output files will be written. The other input files should be in the same directory as the project file when the model run is started. The output directory is created amongst the other outputs of the simulation. Simulations are run half-hourly by default and this is hard coded in the write.configs.LDNDC file.

  • -
  • template.job : Will be filled in with the information needed to run the model in PEcAn. For example, calls the model binary and executes the project.ldndc file.

  • -
  • speciesparameter_template.xml : Has a replaceable section. This section is filled in within write.configs.LDNDC. This file uses the given prior values for the species. Currently, there are a few species hard coded in write.configs.LDNDC. See the comment above.

  • -
  • siteparameters.xml : This file is populated by given site(parameter) prior values.

  • -
  • site.xml : This file is written based on the given initial condition file (netcdf). If no path is given in poolinitcond, then some default mineral clay soil settings will be written to this file. However, it is strongly recommended that some initial conditions based on the simulated site are provided. Variables that can be found from the initial conditions, but are not required:

    -
      -
    • For each layer -
        -
      • pH (-),
      • -
      • volume_fraction_of_water_in_soil_at_field_capacity (m3 m-3),
      • -
      • volume_fraction_of_condensed_water_in_soil_at_wilting_point (m3 m-3),
      • -
      • soil_nitrogen_content (kg kg-1),
      • -
      • soil_carbon_content (kg kg-1),
      • -
      • mass_fraction_of_clay_in_soil (kg kg-1),
      • -
      • mass_fraction_of_sand_in_soil (kg kg-1),
      • -
      • mass_fraction_of_silt_in_soil (kg kg-1),
      • -
      • soil_density (kg m-3),
      • -
      • soil_hydraulic_conductivity_at_saturation (m s-1),
      • -
      • stratum = (-) [number of how many stratums a soil layer has]
      • -
    • -
    • Single value -
        -
      • c2n_humus (ratio), [is written in siteparameter file]
      • -
      • AGB = (kg m-2), [is written in events file]
      • -
      • fractional_cover (%) [is written in events file]
      • -
    • -
    • Model specific -
        -
      • history (soil use history, e.g. arable)
      • -
      • soil_type (e.g. ORMA, SALO)
      • -
    • -
  • -
  • setup.xml : Contains information about which modules the model simulation is using. Default settings should be suitable for most of the purposes and are currently hard-coded. The setups differ for agricultural and forest sites.

  • -
-
-
-
-

14.6.3 Installation notes

-

In order to obtain the LDNDC model, the credentials are required. The user can request them from the developers of the model. With the credentials, the pre-compiled LDNDC program can be downloaded here: https://ldndc.imk-ifu.kit.edu/download/download-model.php

-

Once the necessary files have been obtained, the user should execute the installation script found in the ldndc-‘version-number’ directory. On linux, executing would happen with the command sh install.sh. A successful installation will create a .ldndc directory in the user’s home directory. (Note, that this .ldndc directory path will be used in write.configs.LDNDC.) Running the simulations is done by calling the ldndc executable (found in the /bin directory) and giving the path to the project file containing the specs of the simulation. Detailed instructions and how to play with these setups can be found in the user guide.

- -
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/models-linkages.html b/master/models-linkages.html deleted file mode 100644 index 5e1a06c16..000000000 --- a/master/models-linkages.html +++ /dev/null @@ -1,910 +0,0 @@ - - - - - - - 14.7 LINKAGES | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

14.7 LINKAGES

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Model Information
Home Page
Source Code
License
Authors
PEcAn Integration
-

Introduction

-

Introduction about model

-

PEcAn configuration file additions

-

Should list the model specific additions to the PEcAn file here

-

Model specific input files

-

List of inputs required by model, such as met, etc.

-

Model configuration files

-

MODEL is configured using 3 files which are placed in the run folder, as well as a symbolic link to the met file.

-
    -
  • file1 : template for this file is located at models/MODEL/inst/file1 and is not modified.
    -
  • -
  • file2 : template for this file is located at models/MODEL/inst/file2 and is not modified.
    -
  • -
  • file3 : template for this file is in models/MODEL/inst/file3 or it is specified in the <model> section as <template>. The values in this template are replaced by those computed in the earlier stages of PEcAN.
  • -
-

Installation notes

-

This section contains notes on how to compile the model. The notes for the VM might work on other machines or configurations as well.

-

VM

- -
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/models-lpjguess.html b/master/models-lpjguess.html deleted file mode 100644 index 30c75ee4a..000000000 --- a/master/models-lpjguess.html +++ /dev/null @@ -1,910 +0,0 @@ - - - - - - - 14.8 LPJ-GUESS | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

14.8 LPJ-GUESS

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Model Information
Home Page
Source Code
License
Authors
PEcAn Integration
-

Introduction

-

Introduction about model

-

PEcAn configuration file additions

-

Should list the model specific additions to the PEcAn file here

-

Model specific input files

-

List of inputs required by model, such as met, etc.

-

Model configuration files

-

MODEL is configured using 3 files which are placed in the run folder, as well as a symbolic link to the met file.

-
    -
  • file1 : template for this file is located at models/MODEL/inst/file1 and is not modified.
    -
  • -
  • file2 : template for this file is located at models/MODEL/inst/file2 and is not modified.
    -
  • -
  • file3 : template for this file is in models/MODEL/inst/file3 or it is specified in the <model> section as <template>. The values in this template are replaced by those computed in the earlier stages of PEcAN.
  • -
-

Installation notes

-

This section contains notes on how to compile the model. The notes for the VM might work on other machines or configurations as well.

-

VM

- -
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/models-maespa.html b/master/models-maespa.html deleted file mode 100644 index 8f857a30a..000000000 --- a/master/models-maespa.html +++ /dev/null @@ -1,934 +0,0 @@ - - - - - - - 14.9 MAESPA | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

14.9 MAESPA

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Model Information
Home Pagehttp://maespa.github.io/
Source Codehttp://maespa.github.io/download.html
License
AuthorsBelinda Medlyn and Remko Duursma
PEcAn IntegrationTony Gardella, Martim DeKauwe, Remki Duursma
-

Introduction

-

PEcAn configuration file additions

-

Model specific input files

-

Model configuration files

-

MODEL is configured using 3 files which are placed in the run folder, as well as a symbolic link to the met file.

-
    -
  • file1 : template for this file is located at models/MODEL/inst/file1 and is not modified.
    -
  • -
  • file2 : template for this file is located at models/MODEL/inst/file2 and is not modified.
    -
  • -
  • file3 : template for this file is in models/MODEL/inst/file3 or it is specified in the <model> section as <template>. The values in this template are replaced by those computed in the earlier stages of PEcAN.
  • -
-

Installation notes

-

Installing the MAESPA model requires cloning the MAESPA Bitbucket Repository, executing the makefile, and ensuring that the Maeswarp R package is correctly installed.

-

To clone and compile the model, execute this code at the command line

-
git clone https://bitbucket.org/remkoduursma/maespa.git
-
-cd maespa
-
-make clean
-
-make
-

maespa.out is your executable. Example input files can be found in the inputfiles directory. Executing measpa.out from within one of the example directories will produce output.

-

MAESPA developers have also developed a wrapper package called Maeswrap. The usual R package installation method install.packages may present issues with downloading an unpacking a dependency package called rgl. Here are a couple of solutions:

-

Solution 1

-

From the Command Line

-
sudo apt-get install r-cran-rgl
-
-then from within R
-
-install.packages("Maeswrap")
-

Solution 2

-

From the Command line

-
sudo apt-get install libglu1-mesa-dev
-
-then from within R
-
-install.packages("Maeswrap")
-
-
-

This section contains notes on how to compile the model. The notes for the VM might work on other machines or configurations as well.

-

VM

- -
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/models-preles.html b/master/models-preles.html deleted file mode 100644 index 0325ae52f..000000000 --- a/master/models-preles.html +++ /dev/null @@ -1,910 +0,0 @@ - - - - - - - 14.10 PRELES | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

14.10 PRELES

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Model Information
Home Page
Source Code
License
Authors
PEcAn Integration
-

Introduction

-

Introduction about model

-

PEcAn configuration file additions

-

Should list the model specific additions to the PEcAn file here

-

Model specific input files

-

List of inputs required by model, such as met, etc.

-

Model configuration files

-

MODEL is configured using 3 files which are placed in the run folder, as well as a symbolic link to the met file.

-
    -
  • file1 : template for this file is located at models/MODEL/inst/file1 and is not modified.
    -
  • -
  • file2 : template for this file is located at models/MODEL/inst/file2 and is not modified.
    -
  • -
  • file3 : template for this file is in models/MODEL/inst/file3 or it is specified in the <model> section as <template>. The values in this template are replaced by those computed in the earlier stages of PEcAN.
  • -
-

Installation notes

-

This section contains notes on how to compile the model. The notes for the VM might work on other machines or configurations as well.

-

VM

- -
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/models-sipnet.html b/master/models-sipnet.html deleted file mode 100644 index 2d2b11485..000000000 --- a/master/models-sipnet.html +++ /dev/null @@ -1,935 +0,0 @@ - - - - - - - 14.11 SiPNET | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

14.11 SiPNET

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Model Information
Home Page
Source Code
License
Authors
PEcAn IntegrationMichael Dietze, Rob Kooper
-

Introduction

-

Introduction about model

-

PEcAn configuration file additions

-

Should list the model specific additions to the PEcAn file here

-

Model specific input files

-

List of inputs required by model, such as met, etc.

-

Model configuration files

-

SIPNET is configured using 3 files which are placed in the run folder, as well as a symbolic link to the met file.

-
    -
  • sipnet.in : template for this file is located at models/sipnet/inst/sipnet.in and is not modified.
    -
  • -
  • sipnet.param-spatial : template for this file is located at models/sipnet/inst/template.param-spatial and is not modified.
    -
  • -
  • sipnet.param : template for this file is in models/sipnet/inst/template.param or it is specified in the <model> section as <default.param>. The values in this template are replaced by those computed in the earlier stages of PEcAN.
  • -
-

Installation notes

-

This section contains notes on how to compile the model. The notes for the VM might work on other machines or configurations as well.

-

SIPNET version unk:

-
if [ ! -e ${HOME}/sipnet_unk ]; then
-  cd
-  curl -o sipnet_unk.tar.gz http://isda.ncsa.illinois.edu/~kooper/PEcAn/models/sipnet_unk.tar.gz
-  tar zxf sipnet_unk.tar.gz
-  rm sipnet_unk.tar.gz
-fi
-cd ${HOME}/sipnet_unk/
-make clean
-make
-sudo cp sipnet /usr/local/bin/sipnet.runk
-make clean
-

SIPNET version 136:

-
if [ ! -e ${HOME}/sipnet_r136 ]; then
-  cd
-  curl -o sipnet_r136.tar.gz http://isda.ncsa.illinois.edu/~kooper/EBI/sipnet_r136.tar.gz
-  tar zxf sipnet_r136.tar.gz
-  rm sipnet_r136.tar.gz
-  sed -i 's#$(LD) $(LIBLINKS) \(.*\)#$(LD) \1 $(LIBLINKS)#' ${HOME}/sipnet_r136/Makefile
-fi
-cd ${HOME}/sipnet_r136/
-make clean
-make
-sudo cp sipnet /usr/local/bin/sipnet.r136
-make clean
-

VM

- -
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/models-stics.html b/master/models-stics.html deleted file mode 100644 index a187db0b7..000000000 --- a/master/models-stics.html +++ /dev/null @@ -1,904 +0,0 @@ - - - - - - - 14.12 STICS | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

14.12 STICS

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Model Information
Home Pagehttps://www6.paca.inrae.fr/stics/
Source Code
License
Authors
PEcAn IntegrationIstem Fer
-

Introduction

-

STICS (Simulateur mulTIdisciplinaire pour les Cultures Standard) is a crop model that has been developed since 1996 at INRA (French National Institute for Agronomic Research) in collaboration with other research (CIRAD, Irstea, Ecole des Mines de Paris, ESA, LSCE) or professional (ARVALIS, Terres Inovia, CTIFL, ITV, ITB, Agrotransferts, etc.) and teaching institutes or organizations.

-

PEcAn configuration file additions

-

Should list the model specific additions to the PEcAn file here

-

Model specific input files

-

List of inputs required by model, such as met, etc.

-

Model configuration files

-

STICS is configured using different XML files located in two fixed directories: config, plant and user defined workspace(s) directorie(s). A java app called JavaStics allows users to generate these files.

-

Installation notes

-

The software (JavaStics interface and STICS model) is available for download after a registration procedure (see procedure at http://www6.paca.inra.fr/stics_eng/ Download).

-

VM

- -
- -
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/models_singularity.html b/master/models_singularity.html deleted file mode 100644 index 7075a02e5..000000000 --- a/master/models_singularity.html +++ /dev/null @@ -1,2479 +0,0 @@ - - - - - - - 34 singularity | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

34 singularity

-

Running a model using singularity.

-

This is work in progress.

-

This assumes you have singulariy already installed.

-

This will work on a Linux machine (x86_64).

-

First make sure you have all the data files:

-
- -bash script to install required files (click to expand) - -
#!/bin/bash
-
-if [ ! -e sites ]; then
-  curl -s -o sites.tgz http://isda.ncsa.illinois.edu/~kooper/EBI/sites.tgz
-  tar zxf sites.tgz
-  sed -i -e "s#/home/kooper/Projects/EBI#/data/sites#" sites/*/ED_MET_DRIVER_HEADER
-  rm sites.tgz
-fi
-
-if [ ! -e inputs ]; then
-  curl -s -o inputs.tgz http://isda.ncsa.illinois.edu/~kooper/EBI/inputs.tgz
-  tar zxf inputs.tgz
-  rm inputs.tgz
-fi
-
-if [ ! -e testrun.s83 ]; then
-  curl -s -o testrun.s83.zip http://isda.ncsa.illinois.edu/~kooper/EBI/testrun.s83.zip
-  unzip -q testrun.s83.zip
-  sed -i -e "s#/home/pecan#/data#" testrun.s83/ED2IN
-  rm testrun.s83.zip
-fi
-
-if [ ! -e ${HOME}/sites/Santarem_Km83 ]; then
-  curl -s -o Santarem_Km83.zip http://isda.ncsa.illinois.edu/~kooper/EBI/Santarem_Km83.zip
-  unzip -q -d sites Santarem_Km83.zip
-  sed -i -e "s#/home/pecan#/data#" sites/Santarem_Km83/ED_MET_DRIVER_HEADER
-  rm Santarem_Km83.zip
-fi
-
-

Next edit the ED2IN file in testrun.s83

-
- -ED2IN file (click to expand) - -
!==========================================================================================!
-!==========================================================================================!
-!    ED2IN .                                                                               !
-!                                                                                          !
-!    This is the file that contains the variables that define how ED is to be run.  There  !
-! is some brief information about the variables here.                                      !
-!------------------------------------------------------------------------------------------!
-$ED_NL
-
-   !----- Simulation title (64 characters). -----------------------------------------------!
-   NL%EXPNME = 'ED version 2.1 test'
-   !---------------------------------------------------------------------------------------!
-
-
-
-
-   !---------------------------------------------------------------------------------------!
-   !    Type of run:                                                                       !
-   ! INITIAL -- Starts a new run, that can be based on a previous run (restart/history),   !
-   !            but then it will use only the biomass and soil carbon information.         !
-   ! HISTORY -- Resumes a simulation from the last history.  This is different from        !
-   !            initial in the sense that exactly the same information written in the      !
-   !            history will be used here.                                                 !
-   !---------------------------------------------------------------------------------------!
-   NL%RUNTYPE  = 'INITIAL'
-   !---------------------------------------------------------------------------------------!
-
-
-
-   !---------------------------------------------------------------------------------------!
-   !     Start of simulation. Information must be given in UTC time.                       !
-   !---------------------------------------------------------------------------------------!
-   NL%IMONTHA  = 01
-   NL%IDATEA   = 01
-   NL%IYEARA   = 2001
-   NL%ITIMEA   = 0000
-   !---------------------------------------------------------------------------------------!
-
-
-
-   !---------------------------------------------------------------------------------------!
-   !     End of simulation. Information must be given in UTC time.                         !
-   !---------------------------------------------------------------------------------------!
-   NL%IMONTHZ  = 01
-   NL%IDATEZ   = 01
-   NL%IYEARZ   = 2002
-   NL%ITIMEZ   = 0000
-   !---------------------------------------------------------------------------------------!
-
-
-
-   !---------------------------------------------------------------------------------------!
-   ! DTLSM  -- Time step to integrate photosynthesis, and the maximum time step for        !
-   !           integration of energy and water budgets (units: seconds).  Notice that the  !
-   !           model will take steps shorter than this if this is too coarse and could     !
-   !           lead to loss of accuracy or unrealistic results in the biophysics.          !
-   !           Recommended values are < 60 seconds if INTEGRATION_SCHEME is 0, and 240-900 !
-   !           seconds otherwise.                                                          !
-   ! RADFRQ -- Time step to integrate radiation, in seconds.  This must be an integer      !
-   !            multiple of DTLSM, and we recommend it to be exactly the same as DTLSM.    !
-   !---------------------------------------------------------------------------------------!
-   NL%DTLSM  =  600.
-   NL%RADFRQ  = 600.
-   !---------------------------------------------------------------------------------------!
-
-
-
-
-   !---------------------------------------------------------------------------------------!
-   !      The following variables are used in case the user wants to run a regional run.   !
-   !                                                                                       !
-   ! N_ED_REGION -- number of regions for which you want to run ED.  This can be set to    !
-   !                zero provided that N_POI is not...                                     !
-   ! GRID_TYPE   -- which kind of grid to run:                                             !
-   !                0.  Longitude/latitude grid                                            !
-   !                1.  Polar-stereographic                                                !
-   !---------------------------------------------------------------------------------------!
-   NL%N_ED_REGION =  0
-   NL%GRID_TYPE   =  1
-
-      !------------------------------------------------------------------------------------!
-      !     The following variables are used only when GRID_TYPE is set to 0.  You must    !
-      ! provide one value for each grid, except otherwise noted.                           !
-      !                                                                                    !
-      ! GRID_RES       -- Grid resolution, in degrees (first grid only, the other grids    !
-      !                   resolution will be defined by NSTRATX/NSTRATY).                  !
-      ! ED_REG_LATMIN  -- Southernmost point of each region.                               !
-      ! ED_REG_LATMAX  -- Northernmost point of each region.                               !
-      ! ED_REG_LONMIN  -- Westernmost point of each region.                                !
-      ! ED_REG_LONMAX  -- Easternmost point of each region.                                !
-      !------------------------------------------------------------------------------------!
-      NL%GRID_RES       =    1.0
-      NL%ED_REG_LATMIN  =  -12.0, -7.5, 10.0,  -6.0
-      NL%ED_REG_LATMAX  =    1.0, -3.5, 15.0,  -1.0
-      NL%ED_REG_LONMIN  =  -66.0,-58.5, 70.0, -63.0
-      NL%ED_REG_LONMAX  =  -49.0,-54.5, 35.0, -53.0
-      !------------------------------------------------------------------------------------!
-
-
-
-      !------------------------------------------------------------------------------------!
-      !     The following variables are used only when GRID_TYPE is set to 1.              !
-      !                                                                                    !
-      ! NNXP    -- number of points in the X direction.  One value for each grid.          !
-      ! NNYP    -- number of points in the Y direction.  One value for each grid.          !
-      ! DELTAX  -- grid resolution in the X direction, near the grid pole.  Units: [  m].  !
-      !            this value is used to define the first grid only, other grids are       !
-      !            defined using NNSTRATX.                                                 !
-      ! DELTAY  -- grid resolution in the Y direction, near the grid pole.  Units: [  m].  !
-      !            this value is used to define the first grid only, other grids are       !
-      !            defined using NNSTRATX.  Unless you are running some specific tests,    !
-      !            both DELTAX and DELTAY should be the same.                              !
-      ! POLELAT -- Latitude of the pole point.  Set this close to CENTLAT for a more       !
-      !            traditional "square"  domain.  One value for all grids.                 !
-      ! POLELON -- Longitude of the pole point.  Set this close to CENTLON for a more      !
-      !            traditional "square"  domain.  One value for all grids.                 !
-      ! CENTLAT -- Latitude of the central point.  One value for each grid.                !
-      ! CENTLON -- Longitude of the central point.  One value for each grid.               !
-      !------------------------------------------------------------------------------------!
-      NL%NNXP    = 110
-      NL%NNYP    =  70
-      NL%DELTAX  = 60000.
-      NL%DELTAY  = 60000.
-      NL%POLELAT = -2.609075
-      NL%POLELON = -60.2093
-      NL%CENTLAT  = -2.609075
-      NL%CENTLON  = -60.2093
-      !------------------------------------------------------------------------------------!
-
-
-
-      !------------------------------------------------------------------------------------!
-      !     Nest ratios.  These values are used by both GRID_TYPE=0 and GRID_TYPE=1.       !
-      ! NSTRATX --  this is will divide the values given by DELTAX or GRID_RES for the     !
-      !             nested grids.  The first value should be always one.                   !
-      ! NSTRATY --  this is will divide the values given by DELTAY or GRID_RES for the     !
-      !             nested grids.  The first value should be always one, and this must     !
-      !             be always the same as NSTRATX when GRID_TYPE = 0, and this is also     !
-      !             strongly recommended for when GRID_TYPE = 1.                           !
-      !------------------------------------------------------------------------------------!
-      NL%NSTRATX = 1,4
-      NL%NSTRATY = 1,4
-      !------------------------------------------------------------------------------------!
-   !---------------------------------------------------------------------------------------!
-
-
-
-   !---------------------------------------------------------------------------------------!
-   !     The following variables are used to define single polygon of interest runs, and   !
-   ! they are ignored when N_ED_REGION = 0.                                                !
-   !                                                                                       !
-   ! N_POI   -- number of polygons of interest (POIs).  This can be zero as long as        !
-   !            N_ED_REGION is not.                                                        !
-   ! POI_LAT -- list of latitudes of each POI.                                             !
-   ! POI_LON -- list of longitudes of each POI.                                            !
-   ! POI_RES -- grid resolution of each POI (degrees).  This is used only to define the    !
-   !            soil types                                                                 !
-   !---------------------------------------------------------------------------------------!
-   NL%N_POI    =    1
-   NL%POI_LAT  = -3.018
-   NL%POI_LON  = -54.971
-   NL%POI_RES  = 1.00
-   !---------------------------------------------------------------------------------------!
-
-
-
-   !---------------------------------------------------------------------------------------!
-   !  LOADMETH -- Load balancing method.  This is used only in regional runs run in        !
-   !              parallel.                                                                !
-   !              0.  Let ED decide the best way of splitting the polygons.  Commonest     !
-   !                  option and default.                                                  !
-   !              1.  One of the methods to split polygons based on their previous         !
-   !                  work load.  Developpers only.                                        !
-   !              2.  Try to load an equal number of SITES per node.  Useful for when      !
-   !                  total number of polygon is the same as the total number of cores.    !
-   !              3.  Another method to split polygons based on their previous work load.  !
-   !                  Developpers only.                                                    !
-   !---------------------------------------------------------------------------------------!
-   NL%LOADMETH  = 0
-   !---------------------------------------------------------------------------------------!
-
-
-
-
-   !---------------------------------------------------------------------------------------!
-   ! ED2 File output.  For all the variables 0 means no output and 3 means HDF5 output.    !
-   !                                                                                       !
-   ! IFOUTPUT -- Fast analysis.  These are mostly polygon-level averages, and the time     !
-   !             interval between files is determined by FRQANL                            !
-   ! IDOUTPUT -- Daily means (one file per day)                                            !
-   ! IMOUTPUT -- Monthly means (one file per month)                                        !
-   ! IQOUTPUT -- Monthly means of the diurnal cycle (one file per month).  The number      !
-   !             of points for the diurnal cycle is 86400 / FRQANL                         !
-   ! IYOUTPUT -- Annual output.                                                            !
-   ! ITOUTPUT -- Instantaneous fluxes, mostly polygon-level variables, one file per year.  !
-   ! ISOUTPUT -- restart file, for HISTORY runs.  The time interval between files is       !
-   !             determined by FRQHIS                                                      !
-   !---------------------------------------------------------------------------------------!
-   NL%IFOUTPUT  =  0
-   NL%IDOUTPUT  =  0
-   NL%IMOUTPUT  =  0
-   NL%IQOUTPUT  =  3
-   NL%IYOUTPUT  =  0
-   NL%ITOUTPUT  =  0
-   NL%ISOUTPUT  =  3
-   !---------------------------------------------------------------------------------------!
-
-
-
-
-   !---------------------------------------------------------------------------------------!
-   ! ATTACH_METADATA -- Flag for attaching metadata to HDF datasets.  Attaching metadata   !
-   !                    will aid new users in quickly identifying dataset descriptions but !
-   !                    will compromise I/O performance significantly.                     !
-   !                    0 = no metadata, 1 = attach metadata                               !
-   !---------------------------------------------------------------------------------------!
-   NL%ATTACH_METADATA = 0
-   !---------------------------------------------------------------------------------------!
-
-
-
-   !---------------------------------------------------------------------------------------!
-   ! UNITFAST  --  The following variables control the units for FRQFAST/OUTFAST, and      !
-   ! UNITSTATE     FRQSTATE/OUTSTATE, respectively.  Possible values are:                  !
-   !               0.  Seconds;                                                            !
-   !               1.  Days;                                                               !
-   !               2.  Calendar months (variable)                                          !
-   !               3.  Calendar years  (variable)                                          !
-   !                                                                                       !
-   ! N.B.: 1. In case OUTFAST/OUTSTATE are set to special flags (-1 or -2)                 !
-   !          UNITFAST/UNITSTATE will be ignored for them.                                 !
-   !       2. In case IQOUTPUT is set to 3, then UNITFAST has to be 0.                     !
-   !                                                                                       !
-   !---------------------------------------------------------------------------------------!
-   NL%UNITFAST   = 0
-   NL%UNITSTATE  = 3
-   !---------------------------------------------------------------------------------------!
-
-
-
-   !---------------------------------------------------------------------------------------!
-   ! OUTFAST/OUTSTATE -- these control the number of times per file.                       !
-   !                      0. Each time gets its own file                                   !
-   !                     -1. One file per day                                              !
-   !                     -2. One file per month                                            !
-   !                    > 0. Multiple timepoints can be recorded to a single file reducing !
-   !                         the number of files and i/o time in post-processing.          !
-   !                         Multiple timepoints should not be used in the history files   !
-   !                         if you intend to use these for HISTORY runs.                  !
-   !---------------------------------------------------------------------------------------!
-   NL%OUTFAST    = 1.
-   NL%OUTSTATE   = 1.
-   !---------------------------------------------------------------------------------------!
-
-
-
-   !---------------------------------------------------------------------------------------!
-   ! ICLOBBER -- What to do in case the model finds a file that it was supposed the        !
-   !             written? 0 = stop the run, 1 = overwrite without warning.                 !
-   ! FRQFAST  -- time interval between analysis files, units defined by UNITFAST.          !
-   ! FRQSTATE -- time interval between history files, units defined by UNITSTATE.          !
-   !---------------------------------------------------------------------------------------!
-   NL%ICLOBBER  = 1
-   NL%FRQFAST   = 3600.
-   NL%FRQSTATE  = 1.
-   !---------------------------------------------------------------------------------------!
-
-
-
-   !---------------------------------------------------------------------------------------!
-   ! FFILOUT -- Path and prefix for analysis files (all but history/restart).              !
-   ! SFILOUT -- Path and prefix for history files.                                         !
-   !---------------------------------------------------------------------------------------!
-   NL%FFILOUT = '/data/testrun.s83/analy/ts83'
-   NL%SFILOUT = '/data/testrun.s83/histo/ts83'
-   !---------------------------------------------------------------------------------------!
-
-
-
-   !---------------------------------------------------------------------------------------!
-   ! IED_INIT_MODE -- This controls how the plant community and soil carbon pools are      !
-   !                  initialised.                                                         !
-   !                                                                                       !
-   !   -1.  Start from a true bare ground run, or an absolute desert run.  This will       !
-   !        never grow any plant.                                                          !
-   !    0.  Start from near-bare ground (only a few seedlings from each PFT to be included !
-   !        in this run).                                                                  !
-   !    1.  This will use history files written by ED-1.0.  It will grab the ecosystem     !
-   !        state (like biomass, LAI, plant density, etc.), but it will start the          !
-   !        thermodynamic state as a new simulation.                                       !
-   !    2.  Same as 1, but it uses history files from ED-2.0 without multiple sites, and   !
-   !        with the old PFT numbers.                                                      !
-   !    3.  Same as 1, but using history files from ED-2.0 with multiple sites and         !
-   !        TOPMODEL hydrology.                                                            !
-   !    4.  Same as 1, but using ED2.1 H5 history/state files that take the form:          !
-   !        'dir/prefix-gxx.h5'                                                            !
-   !        Initialization files MUST end with -gxx.h5 where xx is a two digit integer     !
-   !        grid number.  Each grid has its own initialization file.  As an example, if a  !
-   !        user has two files to initialize their grids with:                             !
-   !        example_file_init-g01.h5 and example_file_init-g02.h5                          !
-   !        NL%SFILIN = 'example_file_init'                                                !
-   !                                                                                       !
-   !    5.  This is similar to option 4, except that you may provide several files         !
-   !        (including a mix of regional and POI runs, each file ending at a different     !
-   !        date).  This will not check date nor grid structure, it will simply read all   !
-   !        polygons and match the nearest neighbour to each polygon of your run.  SFILIN  !
-   !        must have the directory common to all history files that are sought to be used,! 
-   !        up to the last character the files have in common.  For example if your files  !
-   !        are                                                                            !
-   !        /mypath/P0001-S-2000-01-01-000000-g01.h5,                                      !
-   !        /mypath/P0002-S-1966-01-01-000000-g02.h5,                                      !
-   !        ...                                                                            !
-   !        /mypath/P1000-S-1687-01-01-000000-g01.h5:                                      !
-   !        NL%SFILIN = '/mypath/P'                                                        !
-   !                                                                                       !
-   !    6 - Initialize with ED-2 style files without multiple sites, exactly like option   !
-   !        2, except that the PFT types are preserved.                                    !
-   !---------------------------------------------------------------------------------------!
-   NL%IED_INIT_MODE   = 6
-   !---------------------------------------------------------------------------------------!
-
-
-
-   !---------------------------------------------------------------------------------------!
-   ! EDRES -- Expected input resolution for ED2.0 files.  This is not used unless          !
-   !          IED_INIT_MODE = 3.                                                           !
-   !---------------------------------------------------------------------------------------!
-   NL%EDRES  = 1.0
-   !---------------------------------------------------------------------------------------!
-
-
-   !---------------------------------------------------------------------------------------!
-   ! SFILIN --  The meaning and the size of this variable depends on the type of run, set  !
-   !            at variable NL%RUNTYPE.                                                    !
-   !                                                                                       !
-   ! 1. INITIAL.  Then this is the path+prefix of the previous ecosystem state.  This has  !
-   !              dimension of the number of grids so you can initialize each grid with a  !
-   !              different dataset.  In case only one path+prefix is given, the same will !
-   !              be used for every grid.  Only some ecosystem variables will be set up    !
-   !              here, and the initial condition will be in thermodynamic equilibrium.    !
-   !                                                                                       !
-   ! 2. HISTORY.  This is the path+prefix of the history file that will be used.  Only the !
-   !              path+prefix will be used, as the history for every grid must have come   !
-   !              from the same simulation.                                                !
-   !---------------------------------------------------------------------------------------!
-   NL%SFILIN   = '/data/sites/Santarem_Km83/s83_default.'
-   !---------------------------------------------------------------------------------------!
-
-
-
-
-   !---------------------------------------------------------------------------------------!
-   !     History file information.  These variables are used to continue a simulation from !
-   ! a point other than the beginning.  Time must be in UTC.                               !
-   !                                                                                       !
-   ! IMONTHH -- the time of the history file.  This is the only place you need to change   !
-   ! IDATEH     dates for a HISTORY run.  You may change IMONTHZ and related in case you   !
-   ! IYEARH     want to extend the run, but yo should NOT change IMONTHA and related.      !
-   ! ITIMEH                                                                                !
-   !---------------------------------------------------------------------------------------!
-   NL%ITIMEH   = 0000
-   NL%IDATEH   = 01
-   NL%IMONTHH  = 05
-   NL%IYEARH   = 2001
-   !---------------------------------------------------------------------------------------!
-
-
-
-   !---------------------------------------------------------------------------------------!
-   !  NZG    - number of soil layers.  One value for all grids.                            !
-   !  NZS    - maximum number of snow/water pounding layers.  This is used only for        !
-   !           snow, if only liquid water is standing, the water will be all collapsed     !
-   !           into a single layer, so if you are running for places where it doesn't snow !
-   !           a lot, leave this set to 1.  One value for all grids.                       ! 
-   !---------------------------------------------------------------------------------------!
-   NL%NZG = 16
-   NL%NZS = 4
-   !---------------------------------------------------------------------------------------!
-
-
-
-   !---------------------------------------------------------------------------------------!
-   ! ISOILFLG -- this controls which soil type input you want to use.                      !
-   !             1. Read in from a dataset I will provide in the SOIL_DATABASE variable a  !
-   !                few lines below.                                                       !
-   !                  below.                                                               !
-   !             2. No data available, I will use constant values I will provide in        !
-   !                NSLCON or by prescribing the fraction of sand and clay (see SLXSAND    !
-   !                and SLXCLAY).                                                          !
-   !---------------------------------------------------------------------------------------!
-   NL%ISOILFLG = 2
-   !---------------------------------------------------------------------------------------!
-
-
-
-
-   !---------------------------------------------------------------------------------------!
-   ! NSLCON -- ED-2 Soil classes that the model will use when ISOILFLG is set to 2.        !
-   !           Possible values are:                                                        !
-   !---------------------------------------------------------------------------------------!
-   !   1 -- sand                |   7 -- silty clay loam     |  13 -- bedrock              !
-   !   2 -- loamy sand          |   8 -- clayey loam         |  14 -- silt                 !
-   !   3 -- sandy loam          |   9 -- sandy clay          |  15 -- heavy clay           !
-   !   4 -- silt loam           |  10 -- silty clay          |  16 -- clayey sand          !
-   !   5 -- loam                |  11 -- clay                |  17 -- clayey silt          !
-   !   6 -- sandy clay loam     |  12 -- peat                                              !
-   !---------------------------------------------------------------------------------------!
-   NL%NSLCON   =  11
-   !---------------------------------------------------------------------------------------!
-
-
-
-   !---------------------------------------------------------------------------------------!
-   ! ISOILCOL -- LEAF-3 and ED-2 soil colour classes that the model will use when ISOILFLG !
-   !             is set to 2.  Soil classes are from 1 to 20 (1 = lightest; 20 = darkest). !
-   !             The values are the same as CLM-4.0.  The table is the albedo for visible  !
-   !             and near infra-red.                                                       !
-   !---------------------------------------------------------------------------------------!
-   !                                                                                       !
-   !       |-----------------------------------------------------------------------|       !
-   !       |       |   Dry soil  |  Saturated  |       |   Dry soil  |  Saturated  |       !
-   !       | Class |-------------+-------------| Class +-------------+-------------|       !
-   !       |       |  VIS |  NIR |  VIS |  NIR |       |  VIS |  NIR |  VIS |  NIR |       !
-   !       |-------+------+------+------+------+-------+------+------+------+------|       !
-   !       |     1 | 0.36 | 0.61 | 0.25 | 0.50 |    11 | 0.24 | 0.37 | 0.13 | 0.26 |       !
-   !       |     2 | 0.34 | 0.57 | 0.23 | 0.46 |    12 | 0.23 | 0.35 | 0.12 | 0.24 |       !
-   !       |     3 | 0.32 | 0.53 | 0.21 | 0.42 |    13 | 0.22 | 0.33 | 0.11 | 0.22 |       !
-   !       |     4 | 0.31 | 0.51 | 0.20 | 0.40 |    14 | 0.20 | 0.31 | 0.10 | 0.20 |       !
-   !       |     5 | 0.30 | 0.49 | 0.19 | 0.38 |    15 | 0.18 | 0.29 | 0.09 | 0.18 |       !
-   !       |     6 | 0.29 | 0.48 | 0.18 | 0.36 |    16 | 0.16 | 0.27 | 0.08 | 0.16 |       !
-   !       |     7 | 0.28 | 0.45 | 0.17 | 0.34 |    17 | 0.14 | 0.25 | 0.07 | 0.14 |       !
-   !       |     8 | 0.27 | 0.43 | 0.16 | 0.32 |    18 | 0.12 | 0.23 | 0.06 | 0.12 |       !
-   !       |     9 | 0.26 | 0.41 | 0.15 | 0.30 |    19 | 0.10 | 0.21 | 0.05 | 0.10 |       !
-   !       |    10 | 0.25 | 0.39 | 0.14 | 0.28 |    20 | 0.08 | 0.16 | 0.04 | 0.08 |       !
-   !       |-----------------------------------------------------------------------|       !
-   !                                                                                       !
-   !   Soil type 21 is a special case in which we use the albedo method that used to be    !
-   ! the default in ED-2.1.                                                                !
-   !---------------------------------------------------------------------------------------!
-   NL%ISOILCOL  = 21
-   !---------------------------------------------------------------------------------------!
-
-
-
-   !---------------------------------------------------------------------------------------!
-   !     These variables are used to define the soil properties when you don't want to use !
-   ! the standard soil classes.                                                            !
-   !                                                                                       !
-   ! SLXCLAY -- Prescribed fraction of clay  [0-1]                                         !
-   ! SLXSAND -- Prescribed fraction of sand  [0-1].                                        !
-   !                                                                                       !
-   !     They are used only when ISOILFLG is 2, both values are between 0. and 1., and     !
-   ! theira sum doesn't exceed 1.  Otherwise standard ED values will be used instead.      !
-   !---------------------------------------------------------------------------------------!
-   NL%SLXCLAY = 0.59
-   NL%SLXSAND = 0.39
-   !---------------------------------------------------------------------------------------!
-
-
-
-   !---------------------------------------------------------------------------------------!
-   !    Soil grid and initial conditions if no file is provided:                           !
-   !                                                                                       !
-   ! SLZ     - soil depth in m.  Values must be negative and go from the deepest layer to  !
-   !           the top.                                                                    !
-   ! SLMSTR  - this is the initial soil moisture, now given as the soil moisture index.    !
-   !           Values can be fraction, in which case they will be linearly interpolated    !
-   !           between the special points (e.g. 0.5 will put soil moisture half way        !
-   !           between the wilting point and field capacity).                              !
-   !              -1 = dry air soil moisture                                               !
-   !               0 = wilting point                                                       !
-   !               1 = field capacity                                                      !
-   !               2 = porosity (saturation)                                               !
-   ! STGOFF  - initial temperature offset (soil temperature = air temperature + offset)    !
-   !---------------------------------------------------------------------------------------!
-   NL%SLZ     = -8.000, -6.959, -5.995, -5.108, -4.296, -3.560, -2.897, -2.307,
-                -1.789, -1.340, -0.961, -0.648, -0.400, -0.215, -0.089, -0.020
-   NL%SLMSTR  =   1.00,   1.00,   1.00,   1.00,   1.00,   1.00,   1.00,   1.00,
-                  1.00,   1.00,   1.00,   1.00,   1.00,   1.00,   1.00,   1.00
-   NL%STGOFF  =   0.00,   0.00,   0.00,   0.00,   0.00,   0.00,   0.00,   0.00,
-                  0.00,   0.00,   0.00,   0.00,   0.00,   0.00,   0.00,   0.00
-   !---------------------------------------------------------------------------------------!
-
-
-
-
-   !---------------------------------------------------------------------------------------!
-   !  Input databases                                                                      !
-   !  VEG_DATABASE     -- vegetation database, used only to determine the land/water mask. !
-   !                      Fill with the path and the prefix.                               !
-   !  SOIL_DATABASE    -- soil database, used to determine the soil type.  Fill with the   !
-   !                      path and the prefix.                                             !
-   !  LU_DATABASE      -- land-use change disturbance rates database, used only when       !
-   !                      IANTH_DISTURB is set to 1.  Fill with the path and the prefix.   !
-   !  PLANTATION_FILE  -- plantation fraction file.  In case you don't have such a file or !
-   !                      you do not want to use it, you must leave this variable empty:   !
-   !                      (NL%PLANTATION_FILE = ''                                         !
-   !  THSUMS_DATABASE  -- input directory with dataset to initialise chilling degrees and  !
-   !                      growing degree days, which is used to drive the cold-deciduous   !
-   !                      phenology (you must always provide this, even when your PFTs are !
-   !                      not cold deciduous).                                             !
-   !  ED_MET_DRIVER_DB -- File containing information for meteorological driver            !
-   !                      instructions (the "header" file).                                !
-   !  SOILSTATE_DB     -- Dataset in case you want to provide the initial conditions of    !
-   !                      soil temperature and moisture.                                   !
-   !  SOILDEPTH_DB     -- Dataset in case you want to read in soil depth information.      !
-   !---------------------------------------------------------------------------------------!
-   NL%VEG_DATABASE      = '/data/oge2OLD/OGE2_'
-   NL%SOIL_DATABASE     = '/data/faoOLD/FAO_'
-   NL%LU_DATABASE       = '/data/ed_inputs/glu/'
-   NL%PLANTATION_FILE   = ''
-   NL%THSUMS_DATABASE   = '/data/ed_inputs/'
-   NL%ED_MET_DRIVER_DB  = '/data/sites/Santarem_Km83/ED_MET_DRIVER_HEADER'
-   NL%SOILSTATE_DB      = ''
-   NL%SOILDEPTH_DB      = ''
-   !---------------------------------------------------------------------------------------!
-
-
-
-
-   !---------------------------------------------------------------------------------------!
-   ! ISOILSTATEINIT -- Variable controlling how to initialise the soil temperature and     !
-   !                   moisture                                                            !
-   !                   0.  Use SLMSTR and STGOFF.                                          !
-   !                   1.  Read from SOILSTATE_DB.                                         !
-   ! ISOILDEPTHFLG  -- Variable controlling how to initialise soil depth                   !
-   !                   0.  Constant, always defined by the first SLZ layer.                !
-   !                   1.  Read from SOILDEPTH_DB.                                         !
-   !---------------------------------------------------------------------------------------!
-   NL%ISOILSTATEINIT = 0
-   NL%ISOILDEPTHFLG  = 0
-   !---------------------------------------------------------------------------------------!
-
-
-
-
-   !---------------------------------------------------------------------------------------!
-   ! ISOILBC -- This controls the soil moisture boundary condition at the bottom.  If      !
-   !            unsure, use 0 for short-term simulations (couple of days), and 1 for long- !
-   !            -term simulations (months to years).                                       !
-   !            0.  Bedrock.  Flux from the bottom of the bottommost layer is set to 0.    !
-   !            1.  Gravitational flow.  The flux from the bottom of the bottommost layer  !
-   !                is due to gradient of height only.                                     !
-   !            2.  Super drainage.  Soil moisture of the ficticious layer beneath the     !
-   !                bottom is always at dry air soil moisture.                             !
-   !            3.  Half-way.  Assume that the fictious layer beneath the bottom is always !
-   !                at field capacity.                                                     !
-   !            4.  Aquifer.  Soil moisture of the ficticious layer beneath the bottom is  !
-   !                always at saturation.                                                  !
-   !---------------------------------------------------------------------------------------!
-   NL%ISOILBC        = 1
-   !---------------------------------------------------------------------------------------!
-
-
-
-
-   !---------------------------------------------------------------------------------------!
-   ! IVEGT_DYNAMICS -- The vegetation dynamics scheme.                                     !
-   !                   0.  No vegetation dynamics, the initial state will be preserved,    !
-   !                       even though the model will compute the potential values.  This  !
-   !                       option is useful for theoretical simulations only.              !
-   !                   1.  Normal ED vegetation dynamics (Moorcroft et al 2001).           !
-   !                       The normal option for almost any simulation.                    !
-   !---------------------------------------------------------------------------------------!
-   NL%IVEGT_DYNAMICS = 1
-   !---------------------------------------------------------------------------------------!
-
-
-   !---------------------------------------------------------------------------------------!
-   ! IBIGLEAF -- Do you want to run ED as a 'big leaf' model?                              !
-   !             0.  No, use the standard size- and age-structure (Moorcroft et al. 2001)  !
-   !                 This is the recommended method for most applications.                 !
-   !             1. 'big leaf' ED:  this will have no horizontal or vertical hetero-       !
-   !                 geneities; 1 patch per PFT and 1 cohort per patch; no vertical        !
-   !                 growth, recruits will 'appear' instantaneously at maximum height.     !
-   !                                                                                       !
-   ! N.B. if you set IBIGLEAF to 1, you MUST turn off the crown model (CROWN_MOD = 0)      !
-   !---------------------------------------------------------------------------------------!
-   NL%IBIGLEAF = 0           
-   !---------------------------------------------------------------------------------------!
-
-
-
-
-   !---------------------------------------------------------------------------------------!
-   ! INTEGRATION_SCHEME -- The biophysics integration scheme.                              !
-   !                       0.  Euler step.  The fastest, but it doesn't estimate           !
-   !                           errors.                                                     !
-   !                       1.  Fourth-order Runge-Kutta method.  ED-2.1 default method     !
-   !                       2.  Heun's method (a second-order Runge-Kutta).                 !
-   !                       3.  Hybrid Stepping (BDF2 implicit step for the canopy air and  !
-   !                           leaf temp, forward Euler for else, under development).      !
-   !---------------------------------------------------------------------------------------!
-   NL%INTEGRATION_SCHEME = 1
-   !---------------------------------------------------------------------------------------!
-
-
-
-
-   !---------------------------------------------------------------------------------------!
-   ! RK4_TOLERANCE -- This is the relative tolerance for Runge-Kutta or Heun's             !
-   !                  integration.  Larger numbers will make runs go faster, at the        !
-   !                  expense of being less accurate.  Currently the valid range is        !
-   !                  between 1.e-7 and 1.e-1, but recommended values are between 1.e-4    !
-   !                  and 1.e-2.                                                           !
-   !---------------------------------------------------------------------------------------!
-   NL%RK4_TOLERANCE  = 0.01
-   !---------------------------------------------------------------------------------------!
-
-
-
-
-   !---------------------------------------------------------------------------------------!
-   ! IBRANCH_THERMO -- This determines whether branches should be included in the          !
-   !                   vegetation thermodynamics and radiation or not.                     !
-   !                   0.  No branches in energy/radiation (ED-2.1 default);               !
-   !                   1.  Branches are accounted in the energy and radiation.  Branchwood !
-   !                       and leaf are treated separately in the canopy radiation scheme, !
-   !                       but solved as a single pool in the biophysics integration.      !
-   !                   2.  Similar to 1, but branches are treated as separate pools in the !
-   !                       biophysics (thus doubling the number of prognostic variables).  !
-   !---------------------------------------------------------------------------------------!
-   NL%IBRANCH_THERMO = 1
-   !---------------------------------------------------------------------------------------!
-
-   !---------------------------------------------------------------------------------------!
-   ! IPHYSIOL --  This variable will determine the functional form that will control how   !
-   !              the various parameters will vary with temperature, and how the CO2       !
-   !              compensation point for gross photosynthesis (Gamma*) will be found.      !
-   !              Options are:                                                             !
-   !                                                                                       !
-   ! 0 -- Original ED-2.1, we use the "Arrhenius" function as in Foley et al. (1996) and   !
-   !      Moorcroft et al. (2001).  Gamma* is found using the parameters for tau as in     !
-   !      Foley et al. (1996).                                                             !
-   ! 1 -- Modified ED-2.1.  In this case Gamma* is found using the Michaelis-Mentel        !
-   !      coefficients for CO2 and O2, as in Farquhar et al. (1980) and in CLM.            !
-   ! 2 -- Collatz et al. (1991).  We use the power (Q10) equations, with Collatz et al.    !
-   !      parameters for compensation point, and the Michaelis-Mentel coefficients.  The   !
-   !      correction for high and low temperatures are the same as in Moorcroft et al.     !
-   !      (2001).                                                                          !
-   ! 3 -- Same as 2, except that we find Gamma* as in Farquhar et al. (1980) and in CLM.   !
-   !---------------------------------------------------------------------------------------!
-   NL%IPHYSIOL = 2
-   !---------------------------------------------------------------------------------------!
-
-
-
-   !---------------------------------------------------------------------------------------!
-   ! IALLOM -- Which allometry to use (this mostly affects tropical PFTs.  Temperate PFTs  !
-   !           will use the new root allometry and the maximum crown area if IALLOM is set !
-   !           to 1 or 2).                                                                 !
-   !           0.  Original ED-2.1                                                         !
-   !           1.  a. The coefficients for structural biomass are set so the total AGB     !
-   !                  is similar to Baker et al. (2004), equation 2.  Balive is the        !
-   !                  default ED-2.1;                                                      !
-   !               b. Experimental root depth that makes canopy trees to have root depths  !
-   !                  of 5m and grasses/seedlings at 0.5 to have root depth of 0.5 m.      !
-   !               c. Crown area defined as in Poorter et al. (2006), imposing maximum     !
-   !                  crown area                                                           !
-   !           2.  Similar to 1, but with a few extra changes.                             !
-   !               a. Height -> DBH allometry as in Poorter et al. (2006)                  !
-   !               b. Balive is retuned, using a few leaf biomass allometric equations for !
-   !                  a few genuses in Costa Rica.  References:                            !
-   !                  Cole and Ewel (2006), and Calvo Alvarado et al. (2008).              !
-   !---------------------------------------------------------------------------------------!
-   NL%IALLOM          = 2
-   !---------------------------------------------------------------------------------------!
-
-
-
-   !---------------------------------------------------------------------------------------!
-   ! IGRASS -- This controls the dynamics and growth calculation for grasses.  A new       !
-   !           grass scheme is now available where bdead = 0, height is a function of bleaf!
-   !           and growth happens daily.  ALS (3/3/12)                                     !
-   ! 0: grasses behave like trees as in ED2.1 (old scheme)                                 !
-   !                                                                                       !
-   ! 1: new grass scheme as described above                                                !
-   !---------------------------------------------------------------------------------------!
-   NL%IGRASS          = 0
-   !---------------------------------------------------------------------------------------!
-
-
-   !---------------------------------------------------------------------------------------!
-   ! IPHEN_SCHEME -- It controls the phenology scheme.  Even within each scheme, the       !
-   !                 actual phenology will be different depending on the PFT.              !
-   !                                                                                       !
-   ! -1: grasses   - evergreen;                                                            !
-   !     tropical  - evergreen;                                                            !
-   !     conifers  - evergreen;                                                            !
-   !     hardwoods - cold-deciduous (Botta et al.);                                        !
-   !                                                                                       !
-   !  0: grasses   - drought-deciduous (old scheme);                                       !
-   !     tropical  - drought-deciduous (old scheme);                                       !
-   !     conifers  - evergreen;                                                            !
-   !     hardwoods - cold-deciduous;                                                       !
-   !                                                                                       !
-   !  1: prescribed phenology                                                              !
-   !                                                                                       !
-   !  2: grasses   - drought-deciduous (new scheme);                                       !
-   !     tropical  - drought-deciduous (new scheme);                                       !
-   !     conifers  - evergreen;                                                            !
-   !     hardwoods - cold-deciduous;                                                       !
-   !                                                                                       !
-   !  3: grasses   - drought-deciduous (new scheme);                                       !
-   !     tropical  - drought-deciduous (light phenology);                                  !
-   !     conifers  - evergreen;                                                            !
-   !     hardwoods - cold-deciduous;                                                       !
-   !                                                                                       !
-   !  Old scheme: plants shed their leaves once instantaneous amount of available water    !
-   !              becomes less than a critical value.                                      !
-   !  New scheme: plants shed their leaves once a 10-day running average of available      !
-   !              water becomes less than a critical value.                                !
-   !---------------------------------------------------------------------------------------!
-   NL%IPHEN_SCHEME    = 2
-   !---------------------------------------------------------------------------------------!
-
-
-   !---------------------------------------------------------------------------------------!
-   !     Parameters that control the phenology response to radiation, used only when       !
-   ! IPHEN_SCHEME = 3.                                                                     !
-   !                                                                                       !
-   ! RADINT -- Intercept                                                                   !
-   ! RADSLP -- Slope.                                                                      !
-   !---------------------------------------------------------------------------------------!
-   NL%RADINT          = -11.3868
-   NL%RADSLP          = 0.0824
-   !---------------------------------------------------------------------------------------!
-
-
-
-   !---------------------------------------------------------------------------------------!
-   ! REPRO_SCHEME -- This controls plant reproduction and dispersal.                       !
-   !                 0.  Reproduction off.  Useful for very short runs only.               !
-   !                 1.  Original reproduction scheme.  Seeds are exchanged between        !
-   !                     patches belonging to the same site, but they can't go outside     !
-   !                     their original site.                                              !
-   !                 2.  Similar to 1, but seeds are exchanged between patches belonging   !
-   !                     to the same polygon, even if they are in different sites.  They   !
-   !                     can't go outside their original polygon, though.  This is the     !
-   !                     same as option 1 if there is only one site per polygon.           !
-   !                 3.  Similar to 2, but recruits will only be formed if their phenology !
-   !                     status would be "leaves fully flushed".  This only matters for    !
-   !                     drought deciduous plants.  This option is for testing purposes    !
-   !                     only, think 50 times before using it...                           !
-   !---------------------------------------------------------------------------------------!
-   NL%REPRO_SCHEME    = 2
-   !---------------------------------------------------------------------------------------!
-
-
-
-   !---------------------------------------------------------------------------------------!
-   ! LAPSE_SCHEME -- This specifies the met lapse rate scheme:                             !
-   !                 0.  No lapse rates                                                    !
-   !                 1.  phenomenological, global                                          !
-   !                 2.  phenomenological, local (not yet implemented)                     !
-   !                 3.  mechanistic(not yet implemented)                                  !
-   !---------------------------------------------------------------------------------------!
-   NL%LAPSE_SCHEME    = 0
-   !---------------------------------------------------------------------------------------!
-
-
-
-   !---------------------------------------------------------------------------------------!
-   ! CROWN_MOD -- Specifies how tree crowns are represent in the canopy radiation model,   !
-   !              and in the turbulence scheme depending on ICANTURB.                      !
-   !              0.  ED1 default, crowns are evenly spread throughout the patch area, and !
-   !                  cohorts are stacked on the top of each other.                        !
-   !              1.  Dietze (2008) model.  Cohorts have a finite radius, and cohorts are  !
-   !                  stacked on the top of each other.                                    !
-   !---------------------------------------------------------------------------------------!
-   NL%CROWN_MOD       = 0
-   !---------------------------------------------------------------------------------------!
-
-
-
-   !---------------------------------------------------------------------------------------!
-   !      The following variables control the canopy radiation solver.                     !
-   !                                                                                       !
-   ! ICANRAD      -- Specifies how canopy radiation is solved.  This variable sets both    !
-   !                 shortwave and longwave.                                               !
-   !                 0.  Two-stream model (Medvigy 2006), with the possibility to apply    !
-   !                     finite crown area to direct shortwave radiation.                  !
-   !                 1.  Multiple-scattering model (Zhao and Qualls 2005,2006), with the   !
-   !                     possibility to apply finite crown area to all radiation fluxes.   !
-   ! LTRANS_VIS   -- Leaf transmittance for tropical plants - Visible/PAR                  !
-   ! LTRANS_NIR   -- Leaf transmittance for tropical plants - Near Infrared                !
-   ! LREFLECT_VIS -- Leaf reflectance for tropical plants - Visible/PAR                    !
-   ! LREFLECT_NIR -- Leaf reflectance for tropical plants - Near Infrared                  !
-   ! ORIENT_TREE  -- Leaf orientation factor for tropical trees.  Extremes are:            !
-   !                 -1.  All leaves are oriented in the vertical                          !
-   !                  0.  Leaf orientation is perfectly random                             !
-   !                  1.  All leaves are oriented in the horizontal                        !
-   !                  In practice, acceptable values range from -0.4 and 0.6               !
-   ! ORIENT_GRASS -- Leaf orientation factor for tropical grasses.  Extremes are:          !
-   !                 -1.  All leaves are oriented in the vertical                          !
-   !                  0.  Leaf orientation is perfectly random                             !
-   !                  1.  All leaves are oriented in the horizontal                        !
-   !                  In practice, acceptable values range from -0.4 and 0.6               !
-   ! CLUMP_TREE   -- Clumping factor for tropical trees.  Extremes are:                    !
-   !                 lim -> 0.  Black hole (0 itself is unacceptable)                      !
-   !                        1.  Homogeneously spread over the layer (i.e., no clumping)    !
-   ! CLUMP_GRASS  -- Clumping factor for tropical grasses.  Extremes are:                  !
-   !                 lim -> 0.  Black hole (0 itself is unacceptable)                      !
-   !                        1.  Homogeneously spread over the layer (i.e., no clumping)    !
-   !---------------------------------------------------------------------------------------!
-   NL%ICANRAD        =      0
-   NL%LTRANS_VIS     =  0.050
-   NL%LTRANS_NIR     =  0.230
-   NL%LREFLECT_VIS   =  0.100
-   NL%LREFLECT_NIR   =  0.460
-   NL%ORIENT_TREE    =  0.100
-   NL%ORIENT_GRASS   =  0.000
-   NL%CLUMP_TREE     =  0.800
-   NL%CLUMP_GRASS    =  1.000
-   !---------------------------------------------------------------------------------------!
-
-
-
-
-   !---------------------------------------------------------------------------------------!
-   ! DECOMP_SCHEME -- This specifies the dependence of soil decomposition on temperature.  !
-   !                  0.  ED-2.0 default, the original exponential                         !
-   !                  1.  Lloyd and Taylor (1994) model                                    !
-   !                      [[option 1 requires parameters to be set in xml]]                !
-   !---------------------------------------------------------------------------------------!
-   NL%DECOMP_SCHEME   = 0
-   !---------------------------------------------------------------------------------------!
-
-
-
-   !---------------------------------------------------------------------------------------!
-   ! H2O_PLANT_LIM -- this determines whether plant photosynthesis can be limited by       !
-   !                  soil moisture, the FSW, defined as FSW = Supply / (Demand + Supply). !
-   !                                                                                       !
-   !                  Demand is always the transpiration rates in case soil moisture is    !
-   !                  not limiting (the psi_0 term times LAI).  The supply is determined   !
-   !                  by Kw * nplant * Broot * Available_Water, and the definition of      !
-   !                  available water changes depending on H2O_PLANT_LIM:                  !
-   !                  0.  Force FSW = 1 (effectively available water is infinity).         !
-   !                  1.  Available water is the total soil water above wilting point,     !
-   !                      integrated across all layers within the rooting zone.            !
-   !                  2.  Available water is the soil water at field capacity minus        !
-   !                      wilting point, scaled by the so-called wilting factor:           !
-   !                      (psi(k) - (H - z(k)) - psi_wp) / (psi_fc - psi_wp)               !
-   !                      where psi is the matric potentital at layer k, z is the layer    !
-   !                      depth, H it the crown height and psi_fc and psi_wp are the       !
-   !                      matric potentials at wilting point and field capacity.           !
-   !---------------------------------------------------------------------------------------!
-   NL%H2O_PLANT_LIM   = 2
-   !---------------------------------------------------------------------------------------!
-
-
-   !---------------------------------------------------------------------------------------!
-   !     The following variables are factors that control photosynthesis and respiration.  !
-   ! Notice that some of them are relative values whereas others are absolute.             !
-   !                                                                                       !
-   ! VMFACT_C3     -- Factor multiplying the default Vm0 for C3 plants (1.0 = default).    !
-   ! VMFACT_C4     -- Factor multiplying the default Vm0 for C4 plants (1.0 = default).    !
-   ! MPHOTO_TRC3   -- Stomatal slope (M) for tropical C3 plants                            !
-   ! MPHOTO_TEC3   -- Stomatal slope (M) for conifers and temperate C3 plants              !
-   ! MPHOTO_C4     -- Stomatal slope (M) for C4 plants.                                    !
-   ! BPHOTO_BLC3   -- cuticular conductance for broadleaf C3 plants  [umol/m2/s]           !
-   ! BPHOTO_NLC3   -- cuticular conductance for needleleaf C3 plants [umol/m2/s]           !
-   ! BPHOTO_C4     -- cuticular conductance for C4 plants            [umol/m2/s]           !
-   ! KW_GRASS      -- Water conductance for trees, in m2/yr/kgC_root.  This is used only   !
-   !                  when H2O_PLANT_LIM is not 0.                                         !
-   ! KW_TREE       -- Water conductance for grasses, in m2/yr/kgC_root.  This is used only !
-   !                  when H2O_PLANT_LIM is not 0.                                         !
-   ! GAMMA_C3      -- The dark respiration factor (gamma) for C3 plants.  Subtropical      !
-   !                  conifers will be scaled by GAMMA_C3 * 0.028 / 0.02                   !
-   ! GAMMA_C4      -- The dark respiration factor (gamma) for C4 plants.                   !
-   ! D0_GRASS      -- The transpiration control in gsw (D0) for ALL grasses.               !
-   ! D0_TREE       -- The transpiration control in gsw (D0) for ALL trees.                 !
-   ! ALPHA_C3      -- Quantum yield of ALL C3 plants.  This is only applied when           !
-   !                  QUANTUM_EFFICIENCY_T = 0.                                            !
-   ! ALPHA_C4      -- Quantum yield of C4 plants.  This is always applied.                 !
-   ! KLOWCO2IN     -- The coefficient that controls the PEP carboxylase limited rate of    !
-   !                  carboxylation for C4 plants.                                         !
-   ! RRFFACT       -- Factor multiplying the root respiration factor for ALL PFTs.         !
-   !                  (1.0 = default).                                                     !
-   ! GROWTHRESP    -- The actual growth respiration factor (C3/C4 tropical PFTs only).     !
-   !                  (1.0 = default).                                                     !
-   ! LWIDTH_GRASS  -- Leaf width for grasses, in metres.  This controls the leaf boundary  !
-   !                  layer conductance (gbh and gbw).                                     !
-   ! LWIDTH_BLTREE -- Leaf width for trees, in metres.  This controls the leaf boundary    !
-   !                  layer conductance (gbh and gbw).  This is applied to broadleaf trees !
-   !                  only.                                                                !
-   ! LWIDTH_NLTREE -- Leaf width for trees, in metres.  This controls the leaf boundary    !
-   !                  layer conductance (gbh and gbw).  This is applied to conifer trees   !
-   !                  only.                                                                !
-   ! Q10_C3        -- Q10 factor for C3 plants (used only if IPHYSIOL is set to 2 or 3).   !
-   ! Q10_C4        -- Q10 factor for C4 plants (used only if IPHYSIOL is set to 2 or 3).   !
-   !---------------------------------------------------------------------------------------!
-   NL%VMFACT_C3       = 1
-   NL%VMFACT_C4       = 1
-   NL%MPHOTO_TRC3     = 9
-   NL%MPHOTO_TEC3     = 7.2
-   NL%MPHOTO_C4       = 5.2
-   NL%BPHOTO_BLC3     = 10000
-   NL%BPHOTO_NLC3     = 1000
-   NL%BPHOTO_C4       = 10000
-   NL%KW_GRASS        = 900
-   NL%KW_TREE         = 600
-   NL%GAMMA_C3        = 0.0145
-   NL%GAMMA_C4        = 0.035
-   NL%D0_GRASS        = 0.016
-   NL%D0_TREE         = 0.016
-   NL%ALPHA_C3        = 0.08
-   NL%ALPHA_C4        = 0.055
-   NL%KLOWCO2IN       = 4000
-   NL%RRFFACT         = 1
-   NL%GROWTHRESP      = 0.333
-   NL%LWIDTH_GRASS    = 0.05
-   NL%LWIDTH_BLTREE   = 0.1
-   NL%LWIDTH_NLTREE   = 0.05
-   NL%Q10_C3          = 2.4
-   NL%Q10_C4          = 2.4
-   !---------------------------------------------------------------------------------------!
-
-
-
-
-   !---------------------------------------------------------------------------------------!
-   ! THETACRIT -- Leaf drought phenology threshold.  The sign matters here:                !
-   !              >= 0. -- This is the relative soil moisture above the wilting point      !
-   !                       below which the drought-deciduous plants will start shedding    !
-   !                       their leaves                                                    !
-   !              <  0. -- This is the soil potential in MPa below which the drought-      !
-   !                       -deciduous plants will start shedding their leaves.  The wilt-  !
-   !                       ing point is by definition -1.5MPa, so make sure that the value !
-   !                       is above -1.5.                                                  !
-   !---------------------------------------------------------------------------------------!
-   NL%THETACRIT       = -1.20
-   !---------------------------------------------------------------------------------------!
-
-
-
-   !---------------------------------------------------------------------------------------!
-   ! QUANTUM_EFFICIENCY_T -- Which quantum yield model should to use for C3 plants         !
-   !                         0.  Original ED-2.1, quantum efficiency is constant.          !
-   !                         1.  Quantum efficiency varies with temperature following      !
-   !                             Ehleringer (1978) polynomial fit.                         !
-   !---------------------------------------------------------------------------------------!
-   NL%QUANTUM_EFFICIENCY_T = 0
-   !---------------------------------------------------------------------------------------!
-
-
-
-   !---------------------------------------------------------------------------------------!
-   ! N_PLANT_LIM -- This controls whether plant photosynthesis can be limited by nitrogen. !
-   !                0.  No limitation                                                      !
-   !                1.  ED-2.1 nitrogen limitation model.                                  !
-   !---------------------------------------------------------------------------------------!
-   NL%N_PLANT_LIM     = 0
-   !---------------------------------------------------------------------------------------!
-
-
-
-   !---------------------------------------------------------------------------------------!
-   ! N_DECOMP_LIM -- This controls whether decomposition can be limited by nitrogen.       !
-   !                0.  No limitation                                                      !
-   !                1.  ED-2.1 nitrogen limitation model.                                  !
-   !---------------------------------------------------------------------------------------!
-   NL%N_DECOMP_LIM    = 0
-   !---------------------------------------------------------------------------------------!
-
-
-
-
-   !---------------------------------------------------------------------------------------!
-   !      The following parameters adjust the fire disturbance in the model.               !
-   ! INCLUDE_FIRE   -- Which threshold to use for fires.                                   !
-   !                   0.  No fires;                                                       !
-   !                   1.  (deprecated) Fire will be triggered with enough biomass and     !
-   !                       integrated ground water depth less than a threshold.  Based on  !
-   !                       ED-1, the threshold assumes that the soil is 1 m, so deeper     !
-   !                       soils will need to be much drier to allow fires to happen and   !
-   !                       often  will never allow fires.                                  !
-   !                   2.  Fire will be triggered with enough biomass and the total soil   !
-   !                       water at the top 75 cm falls below a threshold.                 !
-   ! FIRE_PARAMETER -- If fire happens, this will control the intensity of the disturbance !
-   !                   given the amount of fuel (currently the total above-ground          !
-   !                   biomass).                                                           !
-   ! SM_FIRE        -- This is used only when INCLUDE_FIRE = 2.  The sign here matters.    !
-   !                   >= 0. - Minimum relative soil moisture above dry air of the top 1m  !
-   !                           that will prevent fires to happen.                          !
-   !                   <  0. - Minimum mean soil moisture potential in MPa of the top 1m   !
-   !                           that will prevent fires to happen.  The dry air soil        !
-   !                           potential is defined as -3.1 MPa, so make sure SM_FIRE is   !
-   !                           greater than this value.                                    !
-   !---------------------------------------------------------------------------------------!
-   NL%INCLUDE_FIRE    = 0
-   NL%FIRE_PARAMETER  = 0.5
-   NL%SM_FIRE         = -1.40
-   !---------------------------------------------------------------------------------------!
-
-
-
-   !---------------------------------------------------------------------------------------!
-   !  IANTH_DISTURB -- This flag controls whether to include anthropogenic disturbances    !
-   !                   such as land clearing, abandonment, and logging.                    !
-   !                   0.  no anthropogenic disturbance.                                   !
-   !                   1.  use anthropogenic disturbance dataset.                          !
-   !---------------------------------------------------------------------------------------!
-   NL%IANTH_DISTURB   = 0
-   !---------------------------------------------------------------------------------------!
-
-
-
-   !---------------------------------------------------------------------------------------!
-   ! ICANTURB -- This flag controls the canopy roughness.                                  !
-   !             0.  Based on Leuning et al. (1995), wind is computed using the similarity !
-   !                 theory for the top cohort, and they are extinguished with cumulative  !
-   !                 LAI.  If using CROWN_MOD 1 or 2, this will use local LAI and average  !
-   !                 by crown area.                                                        !
-   !             1.  The default ED-2.1 scheme, except that it uses the zero-plane         !
-   !                 displacement height.                                                  !
-   !             2.  This uses the method of Massman (1997) using constant drag and no     !
-   !                 sheltering factor.                                                    !
-   !             3.  This is also based on Massman (1997), but with the option of varying  !
-   !                 the drag and sheltering within the canopy.                            !
-   !             4.  Same as 0, but if finds the ground conductance following CLM          !
-   !                 technical note (equations 5.98-5.100).                                !
-   !---------------------------------------------------------------------------------------!
-   NL%ICANTURB        = 2
-   !---------------------------------------------------------------------------------------!
-
-
-
-   !---------------------------------------------------------------------------------------!
-   ! ISFCLYRM -- Similarity theory model.  The model that computes u*, T*, etc...          !
-   ! 1.  BRAMS default, based on Louis (1979).  It uses empirical relations to             !
-   !     estimate the flux based on the bulk Richardson number                             !
-   !                                                                                       !
-   !       All models below use an interative method to find z/L, and the only change      !
-   !  is the functional form of the psi functions.                                         !
-   !                                                                                       !
-   ! 2.  Oncley and Dudhia (1995) model, based on MM5.                                     !
-   ! 3.  Beljaars and Holtslag (1991) model. Similar to 2, but it uses an alternative      !
-   !     method for the stable case that mixes more than the OD95.                         !
-   ! 4.  CLM (2004).  Similar to 2 and 3, but they have special functions to deal with     !
-   !     very stable and very stable cases.                                                !
-   !---------------------------------------------------------------------------------------!
-   NL%ISFCLYRM        = 3
-   !---------------------------------------------------------------------------------------!
-
-
-
-   !---------------------------------------------------------------------------------------!
-   ! IED_GRNDVAP -- Methods to find the ground -> canopy conductance.                      !
-   !    0.  Modified Lee Pielke (1992), adding field capacity, but using beta factor       !
-   !        without the square, like in Noilhan and Planton (1989).  This is the closest   !
-   !        to the original ED-2.0 and LEAF-3, and it is also the recommended one.         !
-   !    1.  Test # 1 of Mahfouf and Noilhan (1991)                                         !
-   !    2.  Test # 2 of Mahfouf and Noilhan (1991)                                         !
-   !    3.  Test # 3 of Mahfouf and Noilhan (1991)                                         !
-   !    4.  Test # 4 of Mahfouf and Noilhan (1991)                                         !
-   !    5.  Combination of test #1 (alpha) and test #2 (soil resistance).                  !
-   !    In all cases the beta term is modified so it approaches zero as soil moisture goes !
-   ! to dry air soil.                                                                      !
-   !---------------------------------------------------------------------------------------!
-   NL%IED_GRNDVAP   = 0
-   !---------------------------------------------------------------------------------------!
-
-
-
-
-   !---------------------------------------------------------------------------------------!
-   !     The following variables are used to control the similarity theory model.  For the !
-   ! meaning of these parameters, check Beljaars and Holtslag (1991).                      !
-   ! GAMM        -- gamma coefficient for momentum, unstable case (dimensionless)          !
-   !                Ignored when ISTAR = 1                                                 !
-   ! GAMH        -- gamma coefficient for heat, unstable case (dimensionless)              !
-   !                Ignored when ISTAR = 1                                                 !
-   ! TPRANDTL    -- Turbulent Prandtl number                                               !
-   !                Ignored when ISTAR = 1                                                 !
-   ! RIBMAX      -- maximum bulk Richardson number.                                        !
-   ! LEAF_MAXWHC -- Maximum water that can be intercepted by leaves, in kg/m2leaf.         !
-   !---------------------------------------------------------------------------------------!
-   NL%GAMM            = 13.0
-   NL%GAMH            = 13.0
-   NL%TPRANDTL        = 0.74
-   NL%RIBMAX          = 0.50
-   NL%LEAF_MAXWHC     = 0.11
-   !---------------------------------------------------------------------------------------!
-
-
-
-
-   !---------------------------------------------------------------------------------------!
-   ! IPERCOL -- This controls percolation and infiltration.                                !
-   !            0.  Default method.  Assumes soil conductivity constant and for the        !
-   !                temporary surface water, it sheds liquid in excess of a 1:9 liquid-    !
-   !                -to-ice ratio through percolation.  Temporary surface water exists     !
-   !                only if the top soil layer is at saturation.                           !
-   !            1.  Constant soil conductivity, and it uses the percolation model as in    !
-   !                Anderson (1976) NOAA technical report NWS 19.  Temporary surface       !
-   !                water may exist after a heavy rain event, even if the soil doesn't     !
-   !                saturate.  Recommended value.                                          !
-   !            2.  Soil conductivity decreases with depth even for constant soil moisture !
-   !                , otherwise it is the same as 1.                                       !
-   !---------------------------------------------------------------------------------------!
-   NL%IPERCOL        = 1
-   !---------------------------------------------------------------------------------------!
-
-
-
-   !---------------------------------------------------------------------------------------!
-   !      The following variables control the plant functional types (PFTs) that will be   !
-   ! used in this simulation.                                                              !
-   !                                                                                       !
-   ! INCLUDE_THESE_PFT -- a list containing all the PFTs you want to include in this run   !
-   ! AGRI_STOCK        -- which PFT should be used for agriculture                         !
-   !                      (used only when IANTH_DISTURB = 1)                               !
-   ! PLANTATION_STOCK  -- which PFT should be used for plantation                          !
-   !                      (used only when IANTH_DISTURB = 1)                               !
-   !                                                                                       !
-   ! PFT table                                                                             !
-   !---------------------------------------------------------------------------------------!
-   ! 1 - C4 grass                         |  9 - early temperate deciduous                 !
-   ! 2 - early tropical                   | 10 - mid temperate deciduous                   !
-   ! 3 - mid tropical                     | 11 - late temperate deciduous                  !
-   ! 4 - late tropical                    | 12:15 - agricultural PFTs                      !
-   ! 5 - temperate C3 grass               | 16 - Subtropical C3 grass                      !
-   ! 6 - northern pines                   |      (C4 grass with C3 photo).                 !
-   ! 7 - southern pines                   | 17 - "Araucaria" (non-optimised                !
-   ! 8 - late conifers                    |      Southern Pines).                          !
-   !---------------------------------------------------------------------------------------!
-   NL%INCLUDE_THESE_PFT = 1,2,3,4,16
-   NL%AGRI_STOCK        = 1
-   NL%PLANTATION_STOCK  = 3
-   !---------------------------------------------------------------------------------------!
-
-
-
-
-   !---------------------------------------------------------------------------------------!
-   ! PFT_1ST_CHECK -- What to do if the initialisation file has a PFT that is not listed   !
-   !                  in INCLUDE_THESE_PFT (ignored if IED_INIT_MODE is -1 or 0)           !
-   !                  0.  Stop the run                                                     !
-   !                  1.  Add the PFT in the INCLUDE_THESE_PFT list                        !
-   !                  2.  Ignore the cohort                                                !
-   !---------------------------------------------------------------------------------------!
-   NL%PFT_1ST_CHECK = 0
-   !---------------------------------------------------------------------------------------!
-
-
-
-   !---------------------------------------------------------------------------------------!
-   ! The following variables control the size of sub-polygon structures in ED-2.           !
-   ! MAXSITE        -- This is the strict maximum number of sites that each polygon can    !
-   !                   contain.  Currently this is used only when the user wants to run    !
-   !                   the same polygon with multiple soil types.  If there aren't that    !
-   !                   many different soil types with a minimum area (check MIN_SITE_AREA  !
-   !                   below), then the model will allocate just the amount needed.        !
-   ! MAXPATCH       -- If number of patches in a given site exceeds MAXPATCH, force patch  !
-   !                   fusion.  If MAXPATCH is 0, then fusion will never happen.  If       !
-   !                   MAXPATCH is negative, then the absolute value is used only during   !
-   !                   the initialization, and fusion will never happen again.  Notice     !
-   !                   that if the patches are too different, then the actual number of    !
-   !                   patches in a site may exceed MAXPATCH.                              !
-   ! MAXCOHORT      -- If number of cohorts in a given patch exceeds MAXCOHORT, force      !
-   !                   cohort fusion.  If MAXCOHORT is 0, then fusion will never happen.   !
-   !                   If MAXCOHORT is negative, then the absolute value is used only      !
-   !                   during the initialization, and fusion will never happen again.      !
-   !                   Notice that if the cohorts are too different, then the actual       !
-   !                   number of cohorts in a patch may exceed MAXCOHORT.                  !
-   ! MIN_SITE_AREA  -- This is the minimum fraction area of a given soil type that allows  !
-   !                   a site to be created (ignored if IED_INIT_MODE is set to 3).        !
-   ! MIN_PATCH_AREA -- This is the minimum fraction area of a given soil type that allows  !
-   !                   a site to be created (ignored if IED_INIT_MODE is set to 3).        !
-   !---------------------------------------------------------------------------------------!
-   NL%MAXSITE        =     1
-   NL%MAXPATCH       =    10
-   NL%MAXCOHORT      =    40
-   NL%MIN_SITE_AREA  = 0.005
-   NL%MIN_PATCH_AREA = 0.005
-   !---------------------------------------------------------------------------------------!
-
-
-
-
-   !---------------------------------------------------------------------------------------!
-   !  ZROUGH -- constant roughness, in metres, if for all domain                           !
-   !---------------------------------------------------------------------------------------!
-   NL%ZROUGH = 0.1
-   !---------------------------------------------------------------------------------------!
-
-
-
-
-   !---------------------------------------------------------------------------------------!
-   !     Treefall disturbance parameters.                                                  !
-   ! TREEFALL_DISTURBANCE_RATE -- Sign-dependent treefall disturbance rate:                !
-   !                              > 0. usual disturbance rate, in 1/years;                 !
-   !                              = 0. No treefall disturbance;                            !
-   !                              < 0. Treefall will be added as a mortality rate (it      !
-   !                                   will kill plants, but it won't create a new patch). !
-   ! TIME2CANOPY               -- Minimum patch age for treefall disturbance to happen.    !
-   !                              If TREEFALL_DISTURBANCE_RATE = 0., this value will be    !
-   !                              ignored.  If this value is different than zero, then     !
-   !                              TREEFALL_DISTURBANCE_RATE is internally adjusted so the  !
-   !                              average patch age is still 1/TREEFALL_DISTURBANCE_RATE   !
-   !---------------------------------------------------------------------------------------!
-   NL%TREEFALL_DISTURBANCE_RATE  = 0.014
-   NL%TIME2CANOPY    =     0.0
-   !---------------------------------------------------------------------------------------!
-
-
-
-
-   !---------------------------------------------------------------------------------------!
-   ! RUNOFF_TIME -- In case a temporary surface water (TSW) is created, this is the "e-    !
-   !                -folding lifetime" of the TSW in seconds due to runoff.  If you don't  !
-   !                want runoff to happen, set this to 0.                                  !
-   !---------------------------------------------------------------------------------------!
-   NL%RUNOFF_TIME    = 3600.0
-   !---------------------------------------------------------------------------------------!
-
-
-
-
-   !---------------------------------------------------------------------------------------!
-   !     The following variables control the minimum values of various velocities in the   !
-   ! canopy.  This is needed to avoid the air to be extremely still, or to avoid singular- !
-   ! ities.  When defining the values, keep in mind that UBMIN >= UGBMIN >= USTMIN.        !
-   !                                                                                       !
-   !  UBMIN  -- minimum wind speed at the top of the canopy air space               [ m/s] !
-   !  UGBMIN -- minimum wind speed at the leaf level                                [ m/s] !
-   !  USTMIN -- minimum friction velocity, u*, in m/s.                              [ m/s] !
-   !---------------------------------------------------------------------------------------!
-   NL%UBMIN          = 0.65
-   NL%UGBMIN         = 0.25
-   NL%USTMIN         = 0.05
-   !---------------------------------------------------------------------------------------!
-
-
-
-   !---------------------------------------------------------------------------------------!
-   !      Control parameters for printing to standard output.  Any variable can be printed !
-   ! to standard output as long as it is one dimensional.  Polygon variables have been     !
-   ! tested, no gaurtantees for other hierarchical levels.  Choose any variables that are  !
-   ! defined in the variable table fill routine in ed_state_vars.f90.  Choose the start    !
-   ! and end index of the polygon,site,patch or cohort.  It should work in parallel.  The  !
-   ! indices are global indices of the entire domain.  The are printed out in rows of 10   !
-   ! columns each.                                                                         !
-   !                                                                                       !
-   ! IPRINTPOLYS -- 0.  Do not print information to screen                                 !
-   !                1.  Print polygon arrays to screen, use variables described below to   !
-   !                    determine which ones and how                                       !
-   ! NPVARS      -- Number of variables to be printed                                      !
-   ! PRINTVARS   -- List of variables to be printed                                        !
-   ! PFMTSTR     -- The standard fortran format for the prints.  One format per variable   !
-   ! IPMIN       -- First polygon (absolute index) to be print                             !
-   ! IPMAX       -- Last polygon (absolute index) to print                                 !
-   !---------------------------------------------------------------------------------------!
-   NL%IPRINTPOLYS  =  0
-   NL%NPVARS       =  1
-   NL%PRINTVARS    = 'AVG_PCPG','AVG_CAN_TEMP','AVG_VAPOR_AC','AVG_CAN_SHV'
-   NL%PFMTSTR      = 'f10.8','f5.1','f7.2','f9.5'
-   NL%IPMIN        = 1
-   NL%IPMAX        = 60
-   !---------------------------------------------------------------------------------------!
-
-
-
-   !---------------------------------------------------------------------------------------!
-   !      Variables that control the meteorological forcing.                               !
-   !                                                                                       !
-   ! IMETTYPE    -- Format of the meteorological dataset                                   !
-   !                0. ASCII (deprecated)                                                  !
-   !                1. HDF5                                                                !
-   ! ISHUFFLE    -- How to choose an year outside the meterorological data range (see      !
-   !                METCYC1 and METCYCF).                                                  !
-   !                0. Sequentially cycle over years                                       !
-   !                1. Randomly pick the years, using the same sequence.  This has worked  !
-   !                   with gfortran running in Mac OS X system, but it acts like option 2 !
-   !                   when running ifort.                                                 !
-   !                2. Randomly pick the years, choosing a different sequence each time    !
-   !                   the  model is run.                                                  !
-   ! IMETCYC1    -- First year with meteorological information                             !
-   ! IMETCYCF    -- Last year with meteorological information                              !
-   ! IMETAVG     -- How the input radiation was originally averaged.  You must tell this   !
-   !                because ED-2.1 can make a interpolation accounting for the cosine of   !
-   !                zenith angle.                                                          !
-   !               -1.  I don't know, use linear interpolation.                            !
-   !                0.  No average, the values are instantaneous                           !
-   !                1.  Averages ending at the reference time                              !
-   !                2.  Averages beginning at the reference time                           !
-   !                3.  Averages centred at the reference time                             !
-   ! IMETRAD     -- What should the model do with the input short wave radiation?          !
-   !                0.  Nothing, use it as is.                                             !
-   !                1.  Add them together, then use the SiB method to break radiation down !
-   !                    into the four components (PAR direct, PAR diffuse, NIR direct,     !
-   !                    NIR diffuse).                                                      !
-   !                2.  Add then together, then use the method by Weiss and Norman (1985)  !
-   !                    to break radiation down to the four components.                    !
-   !                3.  Gloomy -- All radiation goes to diffuse.                           !
-   !                4.  Sesame street -- all radiation goes to direct, except at night.    !
-   ! INITIAL_CO2 -- Initial value for CO2 in case no CO2 is provided at the meteorological !
-   !                driver dataset [Units: µmol/mol]                                       !
-   !---------------------------------------------------------------------------------------!
-   NL%IMETTYPE    = 1
-   NL%ISHUFFLE    = 0
-   NL%METCYC1     = 2000
-   NL%METCYCF     = 2003
-   NL%IMETAVG     = 1
-   NL%IMETRAD     = 2
-   NL%INITIAL_CO2 = 378.0
-   !---------------------------------------------------------------------------------------!
-
-
-
-   !---------------------------------------------------------------------------------------!
-   !     The following variables control the phenology prescribed from observations:       !
-   !                                                                                       !
-   ! IPHENYS1 -- First year for spring phenology                                           !
-   ! IPHENYSF -- Final year for spring phenology                                           !
-   ! IPHENYF1 -- First year for fall/autumn phenology                                      !
-   ! IPHENYFF -- Final year for fall/autumn phenology                                      !
-   ! PHENPATH -- path and prefix of the prescribed phenology data.                         !
-   !                                                                                       !
-   ! If the years don't cover the entire simulation period, they will be recycled.         !
-   !---------------------------------------------------------------------------------------!
-   NL%IPHENYS1 = 1992
-   NL%IPHENYSF = 2003
-   NL%IPHENYF1 = 1992
-   NL%IPHENYFF = 2003
-   NL%PHENPATH   = '/n/moorcroft_data/data/ed2_data/phenology/phenology'
-   !---------------------------------------------------------------------------------------!
-
-
-
-   !---------------------------------------------------------------------------------------!
-   !     These are some additional configuration files.                                    !
-   ! IEDCNFGF   -- XML file containing additional parameter settings.  If you don't have   !
-   !               one, leave it empty                                                     !
-   ! EVENT_FILE -- file containing specific events that must be incorporated into the      !
-   !               simulation.                                                             !
-   ! PHENPATH   -- path and prefix of the prescribed phenology data.                       !
-   !---------------------------------------------------------------------------------------!
-   NL%IEDCNFGF   = 'config.xml'
-   NL%EVENT_FILE = 'myevents.xml'
-   !---------------------------------------------------------------------------------------!
-
-
-
-   !---------------------------------------------------------------------------------------!
-   !     The following variables are used to control the detailed output for debugging     !
-   ! purposes.                                                                             !
-   !                                                                                       !
-   !  IDETAILED -- This flag controls the possible detailed outputs, mostly used for       !
-   !               debugging purposes.  Notice that this doesn't replace the normal debug- !
-   !               ger options, the idea is to provide detailed output to check bad        !
-   !               assumptions.  The options are additive, and the indices below represent !
-   !               the different types of output:                                          !
-   !                                                                                       !
-   !               1  -- Detailed budget (every DTLSM)                                     !
-   !               2  -- Detailed photosynthesis (every DTLSM)                             !
-   !               4  -- Detailed output from the integrator (every HDID)                  !
-   !               8  -- Thermodynamic bounds for sanity check (every DTLSM)               !
-   !               16 -- Daily error stats (which variable caused the time step to shrink) !
-   !               32 -- Allometry parameters, and minimum and maximum sizes               !
-   !                     (two files, only at the beginning)                                !
-   !                                                                                       !
-   !               In case you don't want any detailed output (likely for most runs), set  !
-   !               IDETAILED to zero.  In case you want to generate multiple outputs, add  !
-   !               the number of the sought options: for example, if you want detailed     !
-   !               photosynthesis and detailed output from the integrator, set IDETAILED   !
-   !               to 6 (2 + 4).  Any combination of the above outputs is acceptable, al-  !
-   !               though all but the last produce a sheer amount of txt files, in which   !
-   !               case you may want to look at variable PATCH_KEEP.  It is also a good    !
-   !               idea to set IVEGT_DYNAMICS to 0 when using the first five outputs.      !
-   !                                                                                       !
-   !                                                                                       !
-   ! PATCH_KEEP -- This option will eliminate all patches except one from the initial-     !
-   !               isation.  This is only used when one of the first five types of         !
-   !               detailed output is active, otherwise it will be ignored.  Options are:  !
-   !                 -2.  Keep only the patch with the lowest potential LAI                !
-   !                 -1.  Keep only the patch with the highest potential LAI               !
-   !                  0.  Keep all patches.                                                !
-   !                > 0.  Keep the patch with the provided index.  In case the index is    !
-   !                      not valid, the model will crash.                                 !
-   !---------------------------------------------------------------------------------------!
-   NL%IDETAILED  = 0
-   NL%PATCH_KEEP = 0
-   !---------------------------------------------------------------------------------------!
-
-
-   !---------------------------------------------------------------------------------------!
-   ! IOPTINPT -- Optimization configuration. (Currently not used)                          !
-   !---------------------------------------------------------------------------------------!
-   !NL%IOPTINPT = ''
-   !---------------------------------------------------------------------------------------!
-   NL%IOOUTPUT = 3
-   NL%IADD_SITE_MEANS = 0
-   NL%IADD_PATCH_MEANS = 0
-   NL%IADD_COHORT_MEANS = 0
-   NL%GROWTH_RESP_SCHEME = 0
-   NL%STORAGE_RESP_SCHEME = 0
-   NL%PLANT_HYDRO_SCHEME = 0
-   NL%ISTOMATA_SCHEME = 0
-   NL%ISTRUCT_GROWTH_SCHEME = 0
-   NL%TRAIT_PLASTICITY_SCHEME = 0
-   NL%IDDMORT_SCHEME = 0
-   NL%CBR_SCHEME = 0
-   NL%DDMORT_CONST = 0
-   NL%ICANRAD = 1
-   NL%DT_CENSUS = 60
-   NL%YR1ST_CENSUS = 2000
-   NL%MON1ST_CENSUS = 6
-   NL%MIN_RECRUIT_DBH = 50   
-$END
-!==========================================================================================!
-!==========================================================================================!
-
-

Convert the docker image to singularity

-
singularity pull docker://pecan/model-ed2-git
-

Finally you can run the singularity image

-
singularity exec -B ed_inputs:/data/ed_inputs -B faoOLD:/data/faoOLD -B oge2OLD:/data/oge2OLD -B sites:/data/sites -B testrun.s83:/data/testrun.s83 --pwd /data/testrun.s83 ./model-ed2-git.simg ed2.git -s
-

Note that the -B option will mount the folder into the singularity image as the second argument (afther the :)

-

The ed2.git command is started with the -s which will run it in single mode, and not initialize and use MPI.

-

Once the model is finished the outputs should be available under testrun.s83.

-

The example ED2IN file is not 100% correct and will result in the following error:

-
- -output of (failed) run (click to expand) - -
+---------------- MPI parallel info: --------------------+
-+  - Machnum  =      0
-+  - Machsize =      1
-+---------------- OMP parallel info: --------------------+
-+  - thread  use:       1
-+  - threads max:       1
-+  - cpu     use:       1
-+  - cpus    max:       1
-+  Note: Max vals are for node, not sockets.
-+--------------------------------------------------------+
-Reading namelist information
-Copying namelist
-
-!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-!!!  WARNING! WARNING! WARNING! WARNING! WARNING!   !!!
-!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- -> Outfast cannot be less than frqfast.
-    Oufast was redefined to    3600. seconds.
-!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-
-!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-!!!  WARNING! WARNING! WARNING! WARNING! WARNING!   !!!
-!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- -> Outstate cannot be different than frqstate when
-    unitstate is set to 3 (years).
-    Oustate was set to       1. years.
-    Oustate was redefined to       1. years.
-!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-+------------------------------------------------------------+
-|           Ecosystem Demography Model, version 2.2
-+------------------------------------------------------------+
-|  Input namelist filename is ED2IN
-|
-|  Single process execution on INITIAL run.
-+------------------------------------------------------------+
-  => Generating the land/sea mask.
-/data/oge2OLD/OGE2_HEADER
- -> Getting file: /data/oge2OLD/OGE2_30S060W.h5...
- + Work allocation, node     1;
- + Polygon array allocation, node     1;
- + Memory successfully allocated on none     1;
- [+] Load_Ed_Ecosystem_Params...
-----------------------------------------
-  Treefall disturbance parameters:
-  - LAMBDA_REF  =  1.40000E-02
-  - LAMBDA_EFF  =  1.40000E-02
-  - TIME2CANOPY =  0.00000E+00
-----------------------------------------
- [+] Checking for XML config...
-*********************************************
-**               WARNING!                  **
-**                                         **
-**    XML file wasn't found. Using default **
-** parameters in ED.                       **
-** (You provided config.xml).
-**                                         **
-*********************************************
- [+] Alloc_Soilgrid...
- [+] Set_Polygon_Coordinates...
- [+] Sfcdata_ED...
- [+] Load_Ecosystem_State...
- + Doing sequential initialization over nodes.
- + Initializing from ED restart file. Node: 001
- [-] filelist_f: Checking prefix:  /data/sites/Santarem_Km83/s83_default.
- +  Showing first 10 files:
-   [-] File #:      1 /data/sites/Santarem_Km83/s83_default.lat-3.018lon-54.971.css
-   [-] File #:      2 /data/sites/Santarem_Km83/s83_default.lat-3.018lon-54.971.pss
-Using patch file: /data/sites/Santarem_Km83/s83_default.lat-3.018lon-54.971.pss
-Using cohort file: /data/sites/Santarem_Km83/s83_default.lat-3.018lon-54.971.css
- + Initializing phenology. Node: 001
- - Reading thermal sums.
- + Initializing anthropogenic disturbance forcing. Node: 001
-
-   --------------------------------------------------------
-    Soil information:
-
-    Polygon name               : ts83
-    Longitude                  :     -54.971
-    Latitude                   :      -3.018
-    Prescribed sand and clay   :           T
-    # of sites                 :           1
-
-    Site :           1
-      - Type :         16
-      - Clay fraction  =  5.90000E-01
-      - Sand fraction  =  3.90000E-01
-      - Silt fraction  =  2.00000E-02
-      - SLBS           =  1.22460E+01
-      - SLPOTS         = -1.52090E-01
-      - SLCONS         =  2.30320E-06
-      - Dry air soil   =  2.29248E-01
-      - Wilting point  =  2.43249E-01
-      - Field capacity =  3.24517E-01
-      - Saturation     =  4.27790E-01
-      - Heat capacity  =  1.30601E+06
-   --------------------------------------------------------
-
- [+] Init_Met_Drivers...
- [+] Read_Met_Drivers_Init...
-------------------------------
- - METCYC1 =         2000
- - METCYCF =         2003
- - NYEARS  =            2
-------------------------------
-        IYEAR     YEAR_USE
-            1         2001
-            2         2002
-------------------------------
-
- [+] Update_met_drivers...
- [+] Ed_Init_Atm...
-Total count in node        1 for grid        1 : POLYGONS=        1 SITES=        1 PATCHES=       18 COHORTS=     1753
-Grid:      1 Poly:      1 Lon:  -54.9710 Lat:    -3.0180 Nplants:    0.73 Avg. LAI:    4.45 NPatches:   18 NCohorts:  660
- [+] initHydrology...
-initHydrology | mynum=         1 ngrids=         1 mpolys=         1 msites=         1
-Allocated | mynum=         1 ngrids=         1 mpolys=         1 msites=         1
-Updated | mynum=         1 ngrids=         1 mpolys=         1 msites=         1
-Deallocated | mynum=         1 ngrids=         1 mpolys=         1 msites=         1
- [+] Filltab_Alltypes...
- [+] Finding frqsum...
- [+] Loading obstime_list
-File /nowhere not found!
-Specify OBSTIME_DB properly in ED namelist.
-::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
-::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
-::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
-
---------------------------------------------------------------
-                     !!! FATAL ERROR !!!
---------------------------------------------------------------
-    ---> File:        ed_init.F90
-    ---> Subroutine:  read_obstime
-    ---> Reason:      OBSTIME_DB not found!
---------------------------------------------------------------
- ED execution halts (see previous error message)...
---------------------------------------------------------------
-STOP fatal_error
-
- -
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/narr.html b/master/narr.html deleted file mode 100644 index 3d4a03501..000000000 --- a/master/narr.html +++ /dev/null @@ -1,864 +0,0 @@ - - - - - - - 15.4 NARR | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

15.4 NARR

-

Scale: North America

-

Resolution: 3 hr, approx. 32km \(Lambert conical projection\)

-

Availability: 1979-present

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/network-status-map.html b/master/network-status-map.html deleted file mode 100644 index 159435888..000000000 --- a/master/network-status-map.html +++ /dev/null @@ -1,864 +0,0 @@ - - - - - - - 17.8 Network Status Map | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

17.8 Network Status Map

-

https://pecan2.bu.edu/pecan/status.php

-

Nodes: red = down, yellow = out-of-date schema, green = good

-

Edges: red = fail, yellow = out-of-date sync, green = good

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/nldas.html b/master/nldas.html deleted file mode 100644 index d012e77f2..000000000 --- a/master/nldas.html +++ /dev/null @@ -1,864 +0,0 @@ - - - - - - - 15.7 NLDAS | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

15.7 NLDAS

-

Scale: Lower 48 + buffer,

-

Resolution: 1 hour, .125 degree

-

Availability: 1980-present

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/osinstall.html b/master/osinstall.html deleted file mode 100644 index b154fe7b3..000000000 --- a/master/osinstall.html +++ /dev/null @@ -1,1795 +0,0 @@ - - - - - - - 24.5 OS Specific Installations | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

24.5 OS Specific Installations

- - -
-

24.5.1 Ubuntu

-

These are specific notes for installing PEcAn on Ubuntu (14.04) and will be referenced from the main installing PEcAn page. You will at least need to install the build environment and Postgres sections. If you want to access the database/PEcAn using a web browser you will need to install Apache. To access the database using the BETY interface, you will need to have Ruby installed.

-

This document also contains information on how to install the Rstudio server edition as well as any other packages that can be helpful.

-
-

24.5.1.1 Install build environment

-
sudo -s
-
-# point to latest R
-echo "deb http://cran.rstudio.com/bin/linux/ubuntu `lsb_release -s -c`/" > /etc/apt/sources.list.d/R.list
-apt-key adv --keyserver keyserver.ubuntu.com --recv-keys E084DAB9
-
-# update package list
-apt-get -y update
-
-# install packages needed for PEcAn
-apt-get -y install build-essential gfortran git r-base-core r-base-dev jags liblapack-dev libnetcdf-dev netcdf-bin bc libcurl4-gnutls-dev curl udunits-bin libudunits2-dev libgmp-dev python-dev libgdal1-dev libproj-dev expect
-
-# install packages needed for ED2
-apt-get -y install openmpi-bin libopenmpi-dev
-
-# install requirements for DALEC
-apt-get -y install libgsl0-dev
-
-# install packages for webserver
-apt-get -y install apache2 libapache2-mod-php5 php5
-
-# install packages to compile docs
-apt-get -y install texinfo texlive-latex-base texlive-latex-extra texlive-fonts-recommended
-
-# install devtools
-echo 'install.packages("devtools")' | R --vanilla
-
-# done as root
-exit
-
-
-

24.5.1.2 Install Postgres

-

Documentation: http://trac.osgeo.org/postgis/wiki/UsersWikiPostGIS21UbuntuPGSQL93Apt

-
sudo -s
-
-# point to latest PostgreSQL
-echo "deb http://apt.postgresql.org/pub/repos/apt `lsb_release -s -c`-pgdg main" > /etc/apt/sources.list.d/pgdg.list
-wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add -
-
-# update package list
-apt-get -y update
-
-# install packages for postgresql (using a newer version than default)
-apt-get -y install libdbd-pgsql postgresql postgresql-client libpq-dev postgresql-9.4-postgis-2.1 postgresql-9.4-postgis-2.1-scripts
-
-# install following if you want to run pecan through the web
-apt-get -y install php5-pgsql
-
-# enable bety user to login with trust by adding the following lines after
-# the ability of postgres user to login in /etc/postgresql/9.4/main/pg_hba.conf
-local   all             bety                                    trust
-host    all             bety            127.0.0.1/32            trust
-host    all             bety            ::1/128                 trust
-
-# Once done restart postgresql
-/etc/init.d/postgresql restart
-
-exit
-

To install the BETYdb database ..

-
-
-

24.5.1.3 Apache Configuration PEcAn

-
# become root
-sudo -s
-
-# get index page
-rm /var/www/html/index.html
-ln -s ${HOME}/pecan/documentation/index_vm.html /var/www/html/index.html
-
-# setup a redirect
-cat > /etc/apache2/conf-available/pecan.conf << EOF
-Alias /pecan ${HOME}/pecan/web
-<Directory ${HOME}/pecan/web>
-  DirectoryIndex index.php
-  Options +ExecCGI
-  Require all granted
-</Directory>
-EOF
-a2enconf pecan
-/etc/init.d/apache2 restart
-
-# done as root
-exit
-
-
-

24.5.1.4 Apache Configuration BETY

-
sudo -s
-
-# install all ruby related packages
-apt-get -y install ruby2.0 ruby2.0-dev libapache2-mod-passenger 
-
-# link static content
-ln -s ${HOME}/bety/public /var/www/html/bety
-
-# setup a redirect
-cat > /etc/apache2/conf-available/bety.conf << EOF
-RailsEnv production
-RailsBaseURI /bety
-PassengerRuby /usr/bin/ruby2.0
-<Directory /var/www/html/bety>
-  Options +FollowSymLinks
-  Require all granted
-</Directory>
-EOF
-a2enconf bety
-/etc/init.d/apache2 restart
-
-
-

24.5.1.5 Rstudio-server

-

NOTE This will allow anybody to login to the machine through the rstudio interface and run any arbitrary code. The login used however is the same as the system login/password.

-
wget http://download2.rstudio.org/rstudio-server-0.98.1103-amd64.deb
-
# bceome root
-sudo -s
-
-# install required packages
-apt-get -y install libapparmor1 apparmor-utils libssl0.9.8
-
-# install rstudio
-dpkg -i rstudio-server-*
-rm rstudio-server-*
-echo "www-address=127.0.0.1" >> /etc/rstudio/rserver.conf
-echo "r-libs-user=~/R/library" >> /etc/rstudio/rsession.conf
-rstudio-server restart
-
-# setup rstudio forwarding in apache
-a2enmod proxy_http
-cat > /etc/apache2/conf-available/rstudio.conf << EOF
-ProxyPass        /rstudio/ http://localhost:8787/
-ProxyPassReverse /rstudio/ http://localhost:8787/
-RedirectMatch permanent ^/rstudio$ /rstudio/
-EOF
-a2enconf rstudio
-/etc/init.d/apache2 restart
-
-# all done, exit root
-exit
-
-
-

24.5.1.6 Additional packages

-

HDF5 Tools, netcdf, GDB and emacs

-
sudo apt-get -y install hdf5-tools cdo nco netcdf-bin ncview gdb emacs ess nedit
- -
-
-
-

24.5.2 CentOS/RedHat

-

These are specific notes for installing PEcAn on CentOS (7) and will be referenced from the main installing PEcAn page. You will at least need to install the build environment and Postgres sections. If you want to access the database/PEcAn using a web browser you will need to install Apache. To access the database using the BETY interface, you will need to have Ruby installed.

-

This document also contains information on how to install the Rstudio server edition as well as any other packages that can be helpful.

-
-

24.5.2.1 Install build environment

-
sudo -s
-
-# install packages needed for PEcAn
-yum -y groupinstall 'Development Tools' 
-yum -y install git netcdf-fortran-openmpi-devel R bc curl libxml2-devel openssl-devel ed  udunits2 udunits2-devel netcdf netcdf-devel gmp-devel python-devel gdal-devel proj-devel proj-epsg expect
-
-# jags
-yum -y install http://download.opensuse.org/repositories/home:/cornell_vrdc/CentOS_7/x86_64/jags3-3.4.0-54.1.x86_64.rpm
-yum -y install http://download.opensuse.org/repositories/home:/cornell_vrdc/CentOS_7/x86_64/jags3-devel-3.4.0-54.1.x86_64.rpm
-
-# fix include folder for udunits2
-ln -s /usr/include/udunits2/* /usr/include/
-
-# install packages needed for ED2
-yum -y install environment-modules openmpi-bin libopenmpi-dev
-
-# install requirements for DALEC
-yum -y install gsl-devel
-
-# install packages for webserver
-yum -y install httpd php
-systemctl enable httpd
-systemctl start httpd
-firewall-cmd --zone=public --add-port=80/tcp --permanent
-firewall-cmd --reload
-
-# install packages to compile docs
-#apt-get -y install texinfo texlive-latex-base texlive-latex-extra texlive-fonts-recommended
-
-# install devtools
-echo 'install.packages("devtools")' | R --vanilla
-
-# done as root
-exit
-
-echo "module load mpi" >> ~/.bashrc
-module load mpi
-
-
-

24.5.2.2 Install and configure PostgreSQL, udunits2, NetCDF

-
sudo -s
-
-# point to latest PostgreSQL
-yum install -y epel-release 
-yum -y install http://yum.postgresql.org/9.4/redhat/rhel-7-x86_64/pgdg-centos94-9.4-1.noarch.rpm
-
-# install packages for postgresql (using a newer version than default)
-yum -y install postgresql94-server postgresql94-contrib postgis2_94 postgresql94-devel udunits2 netcdf
-
-# install following if you want to run pecan through the web
-yum -y install php-pgsql
-
-# enable bety user to login with trust by adding the following lines after
-# the ability of postgres user to login in /var/lib/pgsql/9.4/data/pg_hba.conf
-local   all             bety                                    trust
-host    all             bety            127.0.0.1/32            trust
-host    all             bety            ::1/128                 trust
-
-# Create database
-/usr/pgsql-9.4/bin/postgresql94-setup initdb
-
-# Enable postgres
-systemctl enable postgresql-9.4
-systemctl start postgresql-9.4
-
-exit
-
-
-

24.5.2.3 Apache Configuration PEcAn

-

Install and Start Apache

-
yum -y install httpd
-systemctl enable httpd
-systemctl start httpd
-
# become root
-sudo -s
-
-# get index page
-rm /var/www/html/index.html
-ln -s /home/carya/pecan/documentation/index_vm.html /var/www/html/index.html
-
-# fix selinux context (does this need to be done after PEcAn is installed?)
-chcon -R -t httpd_sys_content_t /home/carya/pecan /home/carya/output
-
-# setup a redirect
-cat > /etc/httpd/conf.d/pecan.conf << EOF
-Alias /pecan /home/carya/pecan/web
-<Directory /home/carya/pecan/web>
-  DirectoryIndex index.php
-  Options +ExecCGI
-  Require all granted
-</Directory>
-EOF
-a2enconf pecan
-/etc/init.d/apache2 restart
-
-# done as root
-exit
-
-
-

24.5.2.4 Apache Configuration BETY

-
sudo -s
-
-# install all ruby related packages
-sudo curl --fail -sSLo /etc/yum.repos.d/passenger.repo https://oss-binaries.phusionpassenger.com/yum/definitions/el-passenger.repo
-yum -y install ruby ruby-devel mod_passenger
-
-# link static content
-ln -s /home/carya/bety/public /var/www/html/bety
-
-# fix GemFile
-echo 'gem "test-unit"' >> bety/Gemlile
-
-# fix selinux context (does this need to be done after bety is installed?)
-chcon -R -t httpd_sys_content_t /home/carya/bety
-
-# setup a redirect
-cat > /etc/httpd/conf.d/bety.conf << EOF
-RailsEnv production
-RailsBaseURI /bety
-PassengerRuby /usr/bin/ruby
-<Directory /var/www/html/bety>
-  Options +FollowSymLinks
-  Require all granted
-</Directory>
-EOF
-systemctl restart httpd
-
-
-

24.5.2.5 Rstudio-server

-

NEED FIXING

-

NOTE This will allow anybody to login to the machine through the rstudio interface and run any arbitrary code. The login used however is the same as the system login/password.

-
wget http://download2.rstudio.org/rstudio-server-0.98.1103-amd64.deb
-
# bceome root
-sudo -s
-
-# install required packages
-apt-get -y install libapparmor1 apparmor-utils libssl0.9.8
-
-# install rstudio
-dpkg -i rstudio-server-*
-rm rstudio-server-*
-echo "www-address=127.0.0.1" >> /etc/rstudio/rserver.conf
-echo "r-libs-user=~/R/library" >> /etc/rstudio/rsession.conf
-rstudio-server restart
-
-# setup rstudio forwarding in apache
-a2enmod proxy_http
-cat > /etc/apache2/conf-available/rstudio.conf << EOF
-ProxyPass        /rstudio/ http://localhost:8787/
-ProxyPassReverse /rstudio/ http://localhost:8787/
-RedirectMatch permanent ^/rstudio$ /rstudio/
-EOF
-a2enconf rstudio
-/etc/init.d/apache2 restart
-
-# all done, exit root
-exit
-

Alternative Rstudio instructions

-
-
24.5.2.5.1 Install and configure Rstudio-server
-

Install RStudio Server by following the official documentation for your platform. -Then, proceed with the following:

-
    -
  • add PATH=$PATH:/usr/sbin:/sbin to /etc/profile
  • -
-
   cat "PATH=$PATH:/usr/sbin:/sbin; export PATH" >> /etc/profile
- -
   wget https://gist.github.com/dlebauer/6921889/raw/d1e0f945228e5519afa6223d6f49d6e0617262bd/rstudio.conf
-   sudo mv rstudio.conf /httpd/conf.d/
-
    -
  • restart the Apache server: sudo httpd restart
  • -
  • now you should be able to access http://<server>/rstudio
  • -
-
-
-
-

24.5.2.6 Install ruby-netcdf gem

-
cd $RUBY_APPLICATION_HOME
-export $NETCDF_URL=http://www.gfd-dennou.org/arch/ruby/products/ruby-netcdf/release/ruby-netcdf-0.6.6.tar.gz
-export $NETCDF_DIR=/usr/local/netcdf
-gem install narray
-export NARRAY_DIR="$(ls $GEM_HOME/gems | grep 'narray-')"
-export NARRAY_PATH="$GEM_HOME/gems/$NARRAY_DIR"
-cd $MY_RUBY_HOME/bin
-wget $NETCDF_URL -O ruby-netcdf.tgz
-tar zxf ruby-netcdf.tgz && cd ruby-netcdf-0.6.6/
-ruby -rubygems extconf.rb --with-narray-include=$NARRAY_PATH --with-netcdf-dir=/usr/local/netcdf-4.3.0
-sed -i 's|rb/$|rb|' Makefile
-make
-make install
-cd ../ && sudo rm -rf ruby-netcdf*
-
-cd $RUBY_APPLICATION
-bundle install --without development
-
-
-

24.5.2.7 Additional packages

-

NEED FIXING

-

HDF5 Tools, netcdf, GDB and emacs

-
sudo apt-get -y install hdf5-tools cdo nco netcdf-bin ncview gdb emacs ess nedit
- -
-
-
-

24.5.3 Mac OSX

-

These are specific notes for installing PEcAn on Mac OSX and will be referenced from the main installing PEcAn page. You will at least need to install the build environment and Postgres sections. If you want to access the database/PEcAn using a web browser you will need to install Apache. To access the database using the BETY interface, you will need to have Ruby installed.

-

This document also contains information on how to install the Rstudio server edition as well as any other packages that can be helpful.

-
-

24.5.3.1 Install build environment

-
# install R
-# download from http://cran.r-project.org/bin/macosx/
-
-# install gfortran 
-# download from http://cran.r-project.org/bin/macosx/tools/
-
-# install OpenMPI
-curl -o openmpi-1.6.3.tar.gz http://www.open-mpi.org/software/ompi/v1.6/downloads/openmpi-1.6.3.tar.gz
-tar zxf openmpi-1.6.3.tar.gz
-cd openmpi-1.6.3
-./configure --prefix=/usr/local
-make all
-sudo make install
-cd ..
-
-# install szip
-curl -o szip-2.1-MacOSX-intel.tar.gz ftp://ftp.hdfgroup.org/lib-external/szip/2.1/bin/szip-2.1-MacOSX-intel.tar.gz
-tar zxf szip-2.1-MacOSX-intel.tar.gz
-sudo mv szip-2.1-MacOSX-intel /usr/local/szip
-
-# install HDF5
-
-curl -o hdf5-1.8.11.tar.gz http://www.hdfgroup.org/ftp/HDF5/current/src/hdf5-1.8.11.tar.gz
-tar zxf hdf5-1.8.11.tar.gz
-cd hdf5-1.8.11
-sed -i -e 's/-O3/-O0/g' config/gnu-flags 
-./configure --prefix=/usr/local/hdf5 --enable-fortran --enable-cxx --with-szlib=/usr/local/szip
-make
-# make check
-sudo make install
-# sudo make check-install
-cd ..
-
-
-

24.5.3.2 Install Postgres

-

For those on a Mac I use the following app for postgresql which has -postgis already installed (http://postgresapp.com/)

-

To get postgis run the following commands in psql:

-
##### Enable PostGIS (includes raster)
-CREATE EXTENSION postgis;
-##### Enable Topology
-CREATE EXTENSION postgis_topology;
-##### fuzzy matching needed for Tiger
-CREATE EXTENSION fuzzystrmatch;
-##### Enable US Tiger Geocoder
-CREATE EXTENSION postgis_tiger_geocoder;
-

To check your postgis run the following command again in psql: SELECT PostGIS_full_version();

-
-
-

24.5.3.3 Additional installs

- -
-
24.5.3.3.2 Install udunits
-

Installing udunits-2 on MacOSX is done from source.

- -
curl -o udunits-2.1.24.tar.gz ftp://ftp.unidata.ucar.edu/pub/udunits/udunits-2.1.24.tar.gz
-tar zxf udunits-2.1.24.tar.gz
-cd udunits-2.1.24
-./configure
-make
-sudo make install
-
-
-
-

24.5.3.4 Apache Configuration

-

Mac does not support pdo/postgresql by default. The easiest way to install is use: http://php-osx.liip.ch/

-

To enable pecan to run from your webserver.

-
cat > /etc/apache2/others/pecan.conf << EOF
-Alias /pecan ${PWD}/pecan/web
-<Directory ${PWD}/pecan/web>
-  DirectoryIndex index.php
-  Options +All
-  Require all granted
-</Directory>
-EOF
-
-
-

24.5.3.5 Ruby

-

The default version of ruby should work. Or use JewelryBox.

-
-
-

24.5.3.6 Rstudio Server

-

For the mac you can download Rstudio Desktop.

- -
-
-
-

24.5.4 Installing BETY

-

**************THIS PAGE IS DEPRECATED*************

-

Official Instructions for BETY are maintained here: https://pecan.gitbook.io/betydb-documentation

-

If you would like to install the Docker Version of BETY, please consult the PEcAn Docker section.

-
-

24.5.4.1 Install Database + Data

- -
# install database (code assumes password is bety)
-sudo -u postgres createuser -d -l -P -R -S bety
-sudo -u postgres createdb -O bety bety
-sudo -u postgres ./scripts/load.bety.sh -c YES -u YES -r 0
-sudo -u postgres ./scripts/load.bety.sh -r 1
-sudo -u postgres ./scripts/load.bety.sh -r 2
-
-# configure for PEcAn web app (change password if needed)
-cp web/config.example.php web/config.php 
-
-# add models to database (VM only)
-./scripts/add.models.sh
-
-# add data to database
-./scripts/add.data.sh
-
-# create outputs folder
-mkdir ~/output
-chmod 777 ~/output
-
-
-

24.5.4.2 Installing BETYdb Web Application

-

There are two flavors of BETY, PHP and RUBY. The PHP version allows for a minimal interaction with the database while the RUBY version allows for full interaction with the database.

-
-
24.5.4.2.1 PHP version
-

The php version comes with PEcAn and is already configured.

-
-
-
24.5.4.2.2 RUBY version
-

The RUBY version requires a few extra packages to be installed first.

-

Next we install the web app.

-
# install bety
-cd
-git clone https://github.com/PecanProject/bety.git
-
-# install gems
-cd bety
-sudo gem2.0 install bundler
-bundle install --without development:test:javascript_testing:debug
-

and configure BETY

-
# create folders for upload folders
-mkdir paperclip/files paperclip/file_names
-chmod 777 paperclip/files paperclip/file_names
-
-# create folder for log files
-mkdir log
-touch log/production.log
-chmod 0666 log/production.log
-
-# fix configuration for vm
-cp config/additional_environment_vm.rb config/additional_environment.rb
-chmod go+w public/javascripts/cache/
-
-# setup bety database configuration
-cat > config/database.yml << EOF
-production:
-  adapter: postgis
-  encoding: utf-8
-  reconnect: false
-  database: bety
-  pool: 5
-  username: bety
-  password: bety
-EOF
-
-# setup login tokens
-cat > config/initializers/site_keys.rb << EOF
-REST_AUTH_SITE_KEY         = 'thisisnotasecret'
-REST_AUTH_DIGEST_STRETCHES = 10
-EOF
- -
-
-
-
-

24.5.5 Install Models

-

This page contains instructions on how to download and install ecosystem models that have been or are being coupled to PEcAn. -These instructions have been tested on the PEcAn unbuntu VM. Commands may vary on other operating systems. -Also, some model downloads require permissions before downloading, making them unavailable to the general public. Please contact the PEcAn team if you would like access to a model that is not already installed on the default PEcAn VM.

- - -
-

24.5.5.1 BioCro

-
# Version 0.951
-echo 'devtools::install_github("ebimodeling/biocro@0.951")' | R --vanilla
-# Version 1.x 
-echo 'devtools::install_github("ebimodeling/biocro-dev@26e0125b")' | R --vanilla
-

BioCro Developers: request access from @dlebauer on GitHub

- -
-
-

24.5.5.2 CLM 4.5

-

The version of CLM installed on PEcAn is the ORNL branch provided by Dan Ricciuto. This version includes Dan’s point-level CLM processing scripts

-

Download the code (~300M compressed), input data (1.7GB compressed and expands to 14 GB), and a few misc inputs.

-
mkdir models
-cd models
-wget ftp://nacp.ornl.gov/synthesis/2008/firenze/site/clm4_5_1_r085.tar.gz
-wget ftp://nacp.ornl.gov/synthesis/2008/firenze/site/clm/ccsm_inputdata.tar.gz
-tar -xvzf clm4_5*
-tar -xvzf ccsm_inputdata.tar.gz
-
-#Parameter file:
-mkdir /home/carya/models/ccsm_inputdata/lnd/clm2/paramdata
-cd  /home/carya/models/ccsm_inputdata/lnd/clm2/paramdata
-wget ftp://nacp.ornl.gov/synthesis/2008/firenze/site/clm_params.c130821.nc
-wget ftp://nacp.ornl.gov/synthesis/2008/firenze/site/clm_params.c140423.nc
-
-#Domain file:
-cd /home/carya/models/ccsm_inputdata/share/domains/domain.clm/
-wget ftp://nacp.ornl.gov/synthesis/2008/firenze/site/domain.lnd.1x1pt_US-UMB_navy.nc
-
-#Aggregated met data file:
-cd /home/carya/models/ccsm_inputdata/atm/datm7/CLM1PT_data/1x1pt_US-UMB
-wget ftp://nacp.ornl.gov/synthesis/2008/firenze/site/all_hourly.nc 
-
-## lightning database
-cd /home/carya/models/ccsm_inputdata/atm/datm7/NASA_LIS/
-wget ftp://nacp.ornl.gov/synthesis/2008/firenze/site/clmforc.Li_2012_climo1995-2011.T62.lnfm_Total_c140423.nc
-
-## surface data
-cd /home/carya/models/ccsm_inputdata/lnd/clm2/surfdata
-wget ftp://nacp.ornl.gov/synthesis/2008/firenze/site/clm/surfdata_360x720cru_simyr1850_c130927.nc
-cd /home/carya/models/ccsm_inputdata/lnd/clm2/surfdata_map
-wget ftp://nacp.ornl.gov/synthesis/2008/firenze/site/clm/surfdata_1x1pt_US-UMB_I1850CLM45CN_simyr1850.nc_new
-mv surfdata_1x1pt_US-UMB_I1850CLM45CN_simyr1850.nc_new surfdata_1x1pt_US-UMB_I1850CLM45CN_simyr1850.nc
-

Required libraries

-
sudo apt-get install mercurial csh tcsh subversion cmake
-
-sudo ln -s /usr/bin/make /usr/bin/gmake
-

Compile and build default inputs

-
cd ~/carya/models/clm4_5_1_r085/scripts
-python runCLM.py --site US-UMB ––compset I1850CLM45CN --mach ubuntu --ccsm_input /home/carya/models/ccsm_inputdata --tstep 1 --nopointdata --coldstart --cpl_bypass --clean_build
-
-
24.5.5.2.1 CLM Test Run
-

You will see a new directory in scripts: US-UMB_I1850CLM45CN -Enter this directory and run (you shouldn’t have to do this normally, but there is a bug with the python script and doing this ensures all files get to the right place):

-
./US-UMB_I1850CLM45CN.build
-

Next you are ready to go to the run directory:

-
/home/carya/models/clm4_5_1_r085/run/US-UMB_I1850CLM45CN/run
-

Open to edit file: datm.streams.txt.CLM1PT.CLM_USRDAT and check file paths such that all paths start with /home/carya/models/ccsm_inputdata

-

From this directory, launch the executable that resides in the bld directory:

-
/home/carya/clm4_5_1_r085/run/US-UMB_I1850CLM45CN/bld/cesm.exe
-

not sure this was the right location, but wherever the executable is

-

You should begin to see output files that look like this: -US-UMB_I1850CLM45CN.clm2.h0.yyyy-mm.nc (yyyy is year, mm is month) -These are netcdf files containing monthly averages of lots of variables.

-

The lnd_in file in the run directory can be modified to change the output file frequency and variables.

- -
-
-
-

24.5.5.3 DALEC

-
cd
-curl -o dalec_EnKF_pub.tgz http://isda.ncsa.illinois.edu/~kooper/EBI/dalec_EnKF_pub.tgz
-tar zxf dalec_EnKF_pub.tgz
-rm dalec_EnKF_pub.tgz
-
-cd dalec_EnKF_pub
-make dalec_EnKF
-make dalec_seqMH
-sudo cp dalec_EnKF dalec_seqMH /usr/local/bin
- -
-
-

24.5.5.4 ED2

-
-
24.5.5.4.1 ED2.2 r46 (used in PEcAn manuscript)
-
# ----------------------------------------------------------------------
-# Get version r46 with a few patches for ubuntu
-cd
-curl -o ED.r46.tgz http://isda.ncsa.illinois.edu/~kooper/EBI/ED.r46.tgz
-tar zxf ED.r46.tgz
-rm ED.r46.tgz
-# ----------------------------------------------------------------------
-# configure and compile ed
-cd ~/ED.r46/ED/build/bin
-curl -o include.mk.VM http://isda.ncsa.illinois.edu/~kooper/EBI/include.mk.opt.`uname -s`
-make OPT=VM
-sudo cp ../ed_2.1-VM /usr/local/bin/ed2.r46
-

Perform a test run using pre configured ED settings for ED2.2 r46

-
# ----------------------------------------------------------------------
-# Create sample run
-cd
-mkdir testrun.ed.r46
-cd testrun.ed.r46
-curl -o ED2IN http://isda.ncsa.illinois.edu/~kooper/EBI/ED2IN.r46
-sed -i -e "s#\$HOME#$HOME#" ED2IN
-curl -o config.xml  http://isda.ncsa.illinois.edu/~kooper/EBI/config.r46.xml
-# execute test run
-time ed2.r46
-
-
-
24.5.5.4.2 ED 2.2 r82
-
cd
-curl -o ED.r82.tgz http://isda.ncsa.illinois.edu/~kooper/EBI/ED.r82.tgz
-tar zxf ED.r82.tgz
-rm ED.r82.tgz
-
-cd ED.r82
-curl -o ED.r82.patch http://isda.ncsa.illinois.edu/~kooper/EBI/ED.r82.patch
-patch -p1 < ED.r82.patch
-cd ED/build/bin
-curl -o include.mk.VM http://isda.ncsa.illinois.edu/~kooper/EBI/include.mk.opt.`uname -s`
-make OPT=VM
-sudo cp ../ed_2.1-VM /usr/local/bin/ed2.r82
-

Perform a test run using pre configured ED settings for ED2.2 r82

-
cd
-mkdir testrun.ed.r82
-cd testrun.ed.r82
-curl -o ED2IN http://isda.ncsa.illinois.edu/~kooper/EBI/ED2IN.r82
-sed -i -e "s#\$HOME#$HOME#" ED2IN
-curl -o config.xml  http://isda.ncsa.illinois.edu/~kooper/EBI/config.r82.xml
-# execute test run
-time ed2.r82
-
-
-
24.5.5.4.3 ED 2.2 bleeding edge
-
cd
-git clone https://github.com/EDmodel/ED2.git
-
-cd ED2/ED/build/bin
-curl -o include.mk.VM http://isda.ncsa.illinois.edu/~kooper/EBI/include.mk.opt.`uname -s`
-./generate_deps.sh
-make OPT=VM
-sudo cp ../ed_2.1-VM /usr/local/bin/ed2.git
- -
-
-
-

24.5.5.5 CLM-FATES

-

Prerequisites

-
sudo apt-get upgrade libnetcdf-dev
-sudo apt-get install subversion
-sudo apt-get install csh
-sudo apt-get install cmake
-sudo ln -s /usr/bin/make /usr/bin/gmake
-sudo rm /bin/sh
-sudo ln -s /bin/bash /bin/sh
-
-wget https://github.com/Unidata/netcdf-fortran/archive/v4.4.4.tar.gz
-cd netcdf-4.4.4
-./configure
-make
-sudo make install
-

you might need to mess around with installing netcdf and netcdf-fortran to get a version FATES likes…

-

Get code from Github (currently private) and go to cime/scripts directory

-
git clone git@github.com:NGEET/ed-clm.git
-cd ed-clm/cime/scripts/
-

Within CLM-FATES, to be able to build an executable we need to create a reference run. We’ll also use this reference run to grab defaults from, so we’ll be registering the location of both the reference case (location of executable, scripts, etc) and the reference inputs with the PEcAn database. To begin, copy reference run script from pecan

-
cp ~/pecan/models/fates/inst/create_1x1_ref_case.sh .
-

Edit reference case script to set NETCDF_HOME, CROOT (reference run case), DIN_LOC_ROOT (reference run inputs). Also, make sure DIN_LOC_ROOT exists as FATES will not create it itself. Then run the script

-
./create_1x1_ref_case.sh
-

Be aware that this script WILL ask you for your password on the NCAR server to download the reference case input data (the guest password may work, haven’t tried this). If it gives an error at the pio stage check the log, but the most likely error is it being unable to find a version of netcdf it likes.

-

Once FATES is installed, set the whole reference case directory as the Model path (leave filename blank) and set the whole inputs directory as an Input with format clm_defaults.

- -
-
-

24.5.5.6 GDAY

-

Navigate to a directory you would like to store GDAY and run the following:

-
git clone https://github.com/mdekauwe/GDAY.git
-
-cd GDAY
-
-cd src
-
-make
-

gday is your executable.

- -
-
-

24.5.5.7 JULES

-

INSTALL STEPS: -1) Download JULES and FCM -JULES: -Model requires registration to download. Not to be put on PEcAn VM -Getting Started documentation: https://jules.jchmr.org/content/getting-started -Registration: http://jules-lsm.github.io/access_req/JULES_access.html

-

FCM:

-
    https://github.com/metomi/fcm/
-    wget https://github.com/metomi/fcm/archive/2015.05.0.tar.gz
-
    -
  1. edit makefile
  2. -
-
open etc/fcm-make/make.cfg
-
-set JULES_NETCDF = actual instead of dummy
-set path (e.g. /usr/) and lib_path /lib64 to netCDF libraries
-
    -
  1. compile JULES
  2. -
-
cd etc/fcm-make/
-{path.to.fcm}/fcm make -f etc/fcm-make/make.cfg --new
-
UBUNTU VERSION: installed without having to add any perl libraries
-#perl stuff that I had to install on pecan2 not PEcAN VM
-sudo yum install perl-Digest-SHA
-sudo yum install perl-Time-modules
-sudo yum install cpan
-curl -L http://cpanmin.us | perl - --sudo App::cpanminus
-sudo cpanm Time/Piece.pm
-sudo cpanm IO/Uncompress/Gunzip.pm
-

Executable is under build/bin/jules.exe

-

Example rundir: examples/point_loobos

- -
-
-

24.5.5.8 LINKAGES

-
-
24.5.5.8.1 R Installation
-
# Public
-echo 'devtools::install_github("araiho/linkages_package")' | R --vanilla
-
-
-
24.5.5.8.2 FORTRAN VERSION
-
#FORTRAN VERSION
-cd
-git clone https://github.com/araiho/Linkages.git
-cd Linkages
-gfortran -o linkages linkages.f
-sudo cp linkages /usr/local/bin/linkages.git
- -
-
-
-

24.5.5.9 LPJ-GUESS

-

Instructions to download source code

-

Go to LPJ-GUESS website for instructions to access code.

- -
-
-

24.5.5.10 MAESPA

-

Navigate to a directory you would like store MAESPA and run the following:

-
git clone https://bitbucket.org/remkoduursma/maespa.git
-
-cd maespa
-
-make
-

maespa.out is your executable. Example input files can be found in the inpufiles directory. Executing measpa.out from within one of the example directories will produce output.

-

MAESPA developers have also developed a wrapper package called Maeswrap. The usual R package installation method install.packages may present issues with downloading an unpacking a dependency package called rgl. Here are a couple of solutions:

-
-
24.5.5.10.1 Solution 1
-
### From the Command Line
-sudo apt-get install r-cran-rgl
-

then from within R

-
install.packages("Maeswrap")
-
-
-
24.5.5.10.2 Solution 2
-
### From the Command line 
-sudo apt-get install libglu1-mesa-dev
-

then from within R

-
install.packages("Maeswrap")
- -
-
-
-

24.5.5.11 SIPNET {inst-sipnet}

-
cd
-curl -o sipnet_unk.tar.gz http://isda.ncsa.illinois.edu/~kooper/EBI/sipnet_unk.tar.gz
-tar zxf sipnet_unk.tar.gz
-rm sipnet_unk.tar.gz
-
-cd sipnet_unk
-make
-sudo cp sipnet /usr/local/bin/sipnet.runk
-
-
24.5.5.11.1 SIPNET testrun
-
cd
-curl -o testrun.sipnet.tar.gz http://isda.ncsa.illinois.edu/~kooper/EBI/testrun.sipnet.tar.gz
-tar zxf testrun.sipnet.tar.gz
-rm testrun.sipnet.tar.gz
-cd testrun.sipnet
-sipnet.runk
- -
-
-
-
-

24.5.6 Installing data for PEcAn

-

PEcAn assumes some of the data to be installed on the machine. This page will describe how to install this data.

-
-

24.5.6.1 Site Information

-

These are large-ish files that contain data used with ED2 and SIPNET

-
rm -rf sites
-curl -o sites.tgz http://isda.ncsa.illinois.edu/~kooper/EBI/sites.tgz
-tar zxf sites.tgz
-sed -i -e "s#/home/kooper/Projects/EBI#${PWD}#" sites/*/ED_MET_DRIVER_HEADER
-rm sites.tgz
-
-rm -rf inputs
-curl -o inputs.tgz http://isda.ncsa.illinois.edu/~kooper/EBI/inputs.tgz
-tar zxf inputs.tgz
-rm inputs.tgz
-
-
-

24.5.6.2 FIA database

-

FIA database is large and will add an extra 10GB to the installation.

-
# download and install database
-curl -o fia5data.psql.gz http://isda.ncsa.illinois.edu/~kooper/EBI/fia5data.psql.gz
-dropdb --if-exists fia5data
-createdb -O bety fia5data
-gunzip fia5data.psql.gz
-psql -U bety -d fia5data < fia5data.psql
-rm fia5data.psql
-
-
-

24.5.6.3 Flux Camp

-

Following will install the data for flux camp (as well as the demo script for PEcAn).

-
cd
-curl -o plot.tgz http://isda.ncsa.illinois.edu/~kooper/EBI/plot.tgz
-tar zxf plot.tgz
-rm plot.tgz
-
-
-

24.5.6.4 Harvard for ED tutorial

-

Add datasets and runs

-
curl -o Santarem_Km83.zip http://isda.ncsa.illinois.edu/~kooper/EBI/Santarem_Km83.zip
-unzip -d sites Santarem_Km83.zip
-sed -i -e "s#/home/pecan#${HOME}#" sites/Santarem_Km83/ED_MET_DRIVER_HEADER
-rm Santarem_Km83.zip
-
-curl -o testrun.s83.zip http://isda.ncsa.illinois.edu/~kooper/EBI/testrun.s83.zip
-unzip testrun.s83.zip
-sed -i -e "s#/home/pecan#${HOME}#" testrun.s83/ED2IN
-rm testrun.s83.zip
-
-curl -o ed2ws.harvard.tgz http://isda.ncsa.illinois.edu/~kooper/EBI/ed2ws.harvard.tgz
-tar zxf ed2ws.harvard.tgz
-mkdir ed2ws.harvard/analy ed2ws.harvard/histo
-sed -i -e "s#/home/pecan#${HOME}#g" ed2ws.harvard/input_harvard/met_driver/HF_MET_HEADER ed2ws.harvard/ED2IN ed2ws.harvard/*.r
-rm ed2ws.harvard.tgz
-
-curl -o testrun.PDG.zip http://isda.ncsa.illinois.edu/~kooper/EBI/testrun.PDG.zip
-unzip testrun.PDG.zip
-sed -i -e "s#/home/pecan#${HOME}#" testrun.PDG/Met/PDG_MET_DRIVER testrun.PDG/Template/ED2IN
-sed -i -e 's#/n/scratch2/moorcroft_lab/kzhang/PDG/WFire_Pecan/##' testrun.PDG/Template/ED2IN
-rm testrun.PDG.zip
-
-curl -o create_met_driver.tar.gz http://isda.ncsa.illinois.edu/~kooper/EBI/create_met_driver.tar.gz
-tar zxf create_met_driver.tar.gz
-rm create_met_driver.tar.gz
- -
-
-
- -
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/othervignettes.html b/master/othervignettes.html deleted file mode 100644 index 34d08bea5..000000000 --- a/master/othervignettes.html +++ /dev/null @@ -1,1745 +0,0 @@ - - - - - - - 5.5 Other Vignettes | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

5.5 Other Vignettes

- -
-

5.5.1 Simple Model-Data Comparisons

-
-

5.5.1.1 Author: Istem Fer, Tess McCabe

-

In this tutorial we will compare model outputs to data outside of the PEcAn web interface. The goal of this is to demonstrate how to perform additional analyses using PEcAn’s outputs. To do this you can download each of the Output files, and then perform the analyses using whatever software you prefer, or you can perform analyses directly on the PEcAn server itself. Here we’ll be analyzing model outputs in R using a browser-based version of RStudio that’s installed on the server

-
-
-

5.5.1.2 Starting RStudio Server

-
    -
  1. Open RStudio Server in a new window at URL/rstudio

  2. -
  3. The username is carya and the password is illinois.

  4. -
  5. To open a new R script click File > New File > R Script

  6. -
  7. Use the Files browser on the lower right pane to find where your run(s) are located

  8. -
-
    -
  • All PEcAn outputs are stored in the output folder. Click on this to open it up.

  • -
  • Within the outputs folder, there will be one folder for each workflow execution. For example, click to open the folder PEcAn_99000000001 if that’s your workflow ID

  • -
  • A workflow folder will have a few log and settings files (e.g. pecan.xml) and the following subfolders

  • -
-
run     contains all the inputs for each run
-out     contains all the outputs from each run
-pft     contains the parameter information for each PFT
-

Within both the run and out folders there will be one folder for each unique model run, where the folder name is the run ID. Click to open the out folder. For our simple case we only did one run so there should be only one folder (e.g. 99000000001). Click to open this folder.

-
    -
  • Within this folder you will find, among other things, files of the format .nc. Each of these files contains one year of model output in the standard PEcAn netCDF format. This is the model output that we will use to compare to data.
  • -
-
-
-

5.5.1.3 Read in settings From an XML file

-
## Read in the xml
-
-settings<-PEcAn.settings::read.settings("~/output/PEcAn_99000000001/pecan.CONFIGS.xml")
-
-## To read in the model output
-runid<-as.character(read.table(paste(settings$outdir, "/run/","runs.txt", sep=""))[1,1]) # Note: if you are using an xml from a run with multiple ensembles this line will provide only the first run id
-outdir<- paste(settings$outdir,"/out/",runid,sep= "")
-start.year<-as.numeric(lubridate::year(settings$run$start.date))
-end.year<-as.numeric(lubridate::year(settings$run$end.date))
-
-site.id<-settings$run$site$id
-File_path<-"~/output/dbfiles/AmerifluxLBL_site_0-772/AMF_US-NR1_BASE_HH_9-1.csv"
-
-## Open up a connection to The Bety Database
-con <- PEcAn.DB::db.open(settings$database$bety)
-
-
-

5.5.1.4 Read in model output from specific variables

-
model_vars<-c("time", "NEE") #varibles being read
-model <- PEcAn.utils::read.output(runid,outdir,start.year, end.year, model_vars,dataframe=TRUE)
-

The arguments to read.output are the run ID, the folder where the run is located, the start year, the end year, and the variables being read. The README file in the Input file dropdown menu of any successful run lists the run ID, the output folder, and the start and end year.

-
-
-

5.5.1.5 Compare model to flux observations

-

First load up the observations and take a look at the contents of the file

-
File_format<-PEcAn.DB::query.format.vars(bety = con, format.id = 5000000002) #This matches the file with a premade "format" or a template that describes how the information in the file is organized
-
-site<-PEcAn.DB::query.site(site.id, con) #This tells PEcAn where the data comes from
-
-observations<-PEcAn.benchmark::load_data(data.path = File_path, format= File_format, time.row = File_format$time.row,  site = site, start_year = start.year, end_year = end.year) #This will throw an error that not all of the units can be converted. That's ok, as the units of the varibles of interest (NEE) are being converted.
-

File_Path refers to where you stored your observational data. In this example the default file path is an Ameriflux dataset from Niwot Ridge.

-

File_format queries the database for the format your file is in. The default format ID “5000000002” is for csv files downloaded from the Ameriflux website. -You could query for diffent kinds of formats that exist in bety or make your own.

-

Here 772 is the database site ID for Niwot Ridge Forest, which tells pecan where the data is from and what time zone to assign any time data read in.

-

Second apply a conservative u* filter to observations

-
observations$NEE[observations$UST<0.2]<-NA
-

Third align model output and observations

-
aligned_dat = PEcAn.benchmark::align_data(model.calc = model, obvs.calc = observations, var ="NEE", align_method = "match_timestep")
-

When we aligned the data, we got a dataframe with the variables we requested in a \(NEE.m\) and a \(NEE.o\) format. The \(.o\) is for observations, and the \(.m\) is for model. The posix column allows for easy plotting along a timeseries.

-

Fourth, plot model predictions vs. observations and compare this to a 1:1 line

-
## predicted vs observed plot
-plot(aligned_dat$NEE.m, aligned_dat$NEE.o)
-abline(0,1,col="red")  ## intercept=0, slope=1
-

Fifth, calculate the Root Mean Square Error (RMSE) between the model and the data

-
rmse = sqrt(mean((aligned_dat$NEE.m-aligned_dat$NEE.o)^2,na.rm = TRUE))
-

na.rm makes sure we don’t include missing or screened values in either time series.

-

Finally, plot time-series of both the model and data together

-
## plot aligned data
-plot(aligned_dat$posix, aligned_dat$NEE.o, type="l")
-lines(aligned_dat$posix,aligned_dat$NEE.m, col = "red")
-

Bonus How would you compare aggregated data?

-

Try RMSE against monthly NEE instead of half-hourly. In this case, first average the values up to monthly in the observations. Then, use align_data to match the monthly timestep in model output.

-

NOTE: Align_data uses two seperate alignment function, match_timestep and mean_over_larger_timestep. Match_timestep will use only that data that is present in both the model and the observation. This is helpful for sparse observations. Mean_over_larger_timestep aggregates the values over the largest timestep present. If you were to look at averaged monthly data, you would use mean_over_larger_timestep.

-
monthlyNEEobs<-aggregate(observations, by= list(month(observations$posix)), simplify=TRUE, FUN =mean, na.rm= TRUE)
-plottable<-align_data(model.calc = model, obvs.calc = monthlyNEEobs, align_method = "mean_over_larger_timestep", var= "NEE")
-head(plottable)
- -
-
-
-

5.5.2 Data Assimilation Concepts

-

The goal of this tutorial is to help you gain some hands-on familiarity with some of the concepts, tools, and techniques involved in Bayesian Calibration. As a warm-up to more advanced approaches to model-data fusion involving full ecosystem models, this example will focus on fitting the Farquhar, von Caemmerer, and Berry (1980) photosynthesis model [FvCB model] to leaf-level photosynthetic data. This is a simple, nonlinear model consisting of 3 equations that models net carbon assimilation, \(A^{(m)}\), at the scale of an individual leaf as a function of light and CO2.

-

\[A_j = \frac{\alpha Q}{\sqrt{1+(\alpha^2 Q^2)/(Jmax^2)}} \frac{C_i- \Gamma}{4 C_i + 8 \Gamma}\]

-

\[A_c = V_{cmax} \frac{C_i - \Gamma}{C_i+ K_C (1+[O]/K_O) }\]

-

\[A^{(m)} = min(A_j,A_c) - r\]

-

The first equation \(A_j\) describes the RUBP-regeneration limited case. In this equation the first fraction is a nonrectangular hyperbola predicting \(J\), the electron transport rate, as a function of incident light \(Q\), quantum yield \(\alpha\), and the assymptotic saturation of \(J\) at high light \(J_{max}\). The second equation, \(A_c\), describes the Rubisco limited case. The third equation says that the overall net assimilation is determined by whichever of the two above cases is limiting, minus the leaf respiration rate, \(r\).

-

To keep things simple, as a Data Model (a.k.a. Likelihood or Cost Function) we’ll assume that the observed leaf-level assimilation \(A^{(o)}\) is Normally distributed around the model predictions with observation error \(\tau\).

-

\[A^{(o)} \sim N(A^{(m)},\tau)\]

-

To fit this model to data we’re going to rely on a piece of statistical software known as JAGS. The above model would be written in JAGS as:

-
model{
-
-## Priors
-  Jmax ~ dlnorm(4.7,2.7)             ## maximum electron transport rate prior
-  alpha~dnorm(0.25,100)              ##quantum yield  (mol electrons/mole photon) prior
-  vmax ~dlnorm(4.6,2.7)              ## maximum rubisco capacity prior
-
-  r ~ dlnorm(0.75,1.56)              ## leaf respiration prior
-  cp ~ dlnorm(1.9,2.7)               ## CO2 compensation point prior
-  tau ~ dgamma(0.1,0.1)
-
-  for(i in 1:n){
-
-     ## electron transport limited
-     Aj[i]<-(alpha*q[i]/(sqrt(1+(alpha*alpha*q[i]*q[i])/(Jmax*Jmax))))*(pi[i]-cp)/(4*pi[i]+8*cp)    
-
-     ## maximum rubisco limited without covariates
-     Ac[i]<- vmax*(pi[i]-cp)/(pi[i]+Kc*(1+po/Ko))                                                    
-
-     Am[i]<-min(Aj[i], Ac[i]) - r      ## predicted net photosynthesis
-     Ao[i]~dnorm(Am[i],tau)            ## likelihood
-     }
-
-}
-

The first chunk of code defines the prior probability distributions. In Bayesian inference every unknown parameter that needs to be estimated is required to have a prior distribution. Priors are the expression of our belief about what values a parameter might take on prior to observing the data. They can arise from many sources of information (literature survey, meta-analysis, expert opinion, etc.) provided that they do not make use of the data that is being used to fit the model. In this particular case, the priors were defined by Feng and Dietze 2013. Most priors are lognormal or gamma, which were choosen because most of these parameters need to be positive.

-

After the priors is the Data Model, which in JAGS needs to be implemented as a loop over every observation. This is simply a codified version of the earlier equations.

-

Table 1: FvCB model parameters in the statistical code, their symbols in equations, and definitions

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ParameterSymbolDefinition
alpha0\(\alpha\)quantum yield (mol electrons/mole photon)
Jmax\(J_{max}\)maximum electron transport
cp\(\Gamma\)CO2 compensation point
vmax0\(V_{cmax}\)maximum Rubisco capacity (a.k.a Vcmax)
r\(R_d\)leaf respiration
tau\(\tau\)residual precision
q\(Q\)PAR
pi\(C_i\)CO2 concentration
-
-

5.5.2.1 Fitting the model

-

To begin with we’ll load up an example A-Ci and A-Q curve that was collected during the 2012 edition of the Flux Course at Niwot Ridge. The exact syntax below may be a bit confusing to those unaccustomed to R, but the essence is that the filenames line is looking up where the example data is stored in the PEcAn.photosynthesis package and the dat line is loading up two files (once A-Ci, the other A-Q) and concatanating them together.

-
library(PEcAn.photosynthesis)
-
-### Load built in data
-filenames <- system.file("extdata", paste0("flux-course-3",c("aci","aq")), package = "PEcAn.photosynthesis")
-dat<-do.call("rbind", lapply(filenames, read_Licor))
-
-## Simple plots
-aci = as.character(dat$fname) == basename(filenames[1])
-plot(dat$Ci[aci],dat$Photo[aci],main="ACi")
-plot(dat$PARi[!aci],dat$Photo[!aci],main="AQ")
-

In PEcAn we’ve written a wrapper function, \(fitA\), around the statistical model discussed above, which has a number of other bells and whistles discussed in the PEcAn Photosynthesis Vignette. For today we’ll just use the most basic version, which takes as arguments the data and the number of MCMC iterations we want to run.

-
fit <- fitA(dat,model=list(n.iter=10000))
-
-
-

5.5.2.2 What’s going on

-

Bayesian numerical methods for model calibration are based on sampling parameter values from the posterior distribution. Fundamentally what’s returned is a matrix, with the number of iterations as rows and the number of parameters as columns, which are samples from the posterior distribution, from which we can approximate any quantity of interest (mean, median, variance, CI, etc.).

-

The following plots follow the trajectory of two correlated parameters, Jmax and alpha. In the first figure, arrows show the first 10 iterations. Internally JAGS is choosing between a variety of different Bayesian sampling methods (e.g. Metropolis-Hasting, Gibbs sampling, slice sampling, rejection sampling, etc) to draw a new value for each parameter conditional on the current value. After just 10 steps we don’t have a good picture of the overall posterior, but it should still be clear that the sampling is not a complete random walk.

-
params <- as.matrix(fit$params)
-xrng = range(fit$params[,"alpha0"])
-yrng = range(fit$params[,"Jmax0"])
-
-n = 1:10
-plot(params[n,"alpha0"],params[n,"Jmax0"],type='n',xlim=xrng,ylim=yrng)
-arrows(params[n[-10],"alpha0"],params[n[-10],"Jmax0"],params[n[-1],"alpha0"],params[n[-1],"Jmax0"],length=0.125,lwd=1.1)
-

After 100 steps, we can see a cloud start to form, with occassional wanderings around the periphery.

-
n = 1:100
-plot(params[n,"alpha0"],params[n,"Jmax0"],type='l',xlim=xrng,ylim=yrng)
-

After \(nrow(params)\) steps what we see is a point cloud of samples from the joint posterior distribution. When viewed sequentially, points are not independent, but we are interested in working with the overall distribution, where the order of samples is not important.

-
n = 1:nrow(params)
-plot(params[n,"alpha0"],params[n,"Jmax0"],type='p',pch="+",cex=0.5,xlim=xrng,ylim=yrng)
-
-
-

5.5.2.3 Evaluating the model output

-

A really important aspect of Bayesian inference is that the output is the joint posterior probability of all the parameters. This is very different from an optimization approach, which tries to find a single best parameter value. It is also different from estimating the independent posterior probabilities of each parameter – Bayesian posteriors frequently have strong correlation among parameters for reasons having to do both with model structure and the underlying data.

-

The model we’re fitting has six free parameters, and therefore the output matrix has 6 columns, of which we’ve only looked at two. Unfortunately it is impossible to visualize a 6 dimensional parameter space on a two dimensional screen, so a very common practice (for models with a small to medium number of parameters) is to look at all pairwise scatterplots. If parameters are uncorrelated we will typically see oval shaped clouds that are oriented in the same directions as the axes. For parameters with linear correlations those clouds will be along a diagonal. For parameters with nonlinear trade-offs the shapes of the parameter clouds can be more complex, such as the banana-shaped or triangular. For the FvCB model we see very few parameters that are uncorrelated or have simple linear correlations, a fact that we should keep in mind when interpreting individual parameters.

-
pairs(params,pch=".")
-

The three most common outputs that are performed on almost all Bayesian analyses are to look at the MCMC chains themselves, the marginal distributions of each parameter, and the overall summary statistics.

-

The ‘trace’ diagrams below show the history of individual parameters during the MCMC sampling. There are different color lines that represent the fact that JAGS ran the MCMC multiple times, with each run (i.e. each color) being refered to as a different \(chain\). It is common to run multiple chains in order to assess whether the model, started from different points, consistently converges on the same answer. The ideal trace plot looks like white noise with all chains in agreement.

-

The ‘density’ figures represent smoothed versions of the marginal distributions of each parameter. The tick marks on the x-axis are the actual samples. You will note that some posteriors will look approximately Normal, while others may be skewed or have clearly defined boundaries. On occassion there will even be posteriors that are multimodal. There is no assumption built into Bayesian statistics that the posteriors need be Normal, so as long as an MCMC has converged this diversity of shapes is valid. [note: the most common cause of multi-modal posteriors is a lack of convergence]

-

Finally, the summary table reports, for each parameter, a mean, standard deviation, two variants of standard error, and standard quantile estimates (95% CI, interquartile, and median). The standard deviation of the posterior is a good summary statistic about how uncertain we are about a parameter. The Naive SE is the traditonal \(\frac{SD}{\sqrt{n}}\), which is an estimate of the NUMERICAL accuracy in our estimate of the mean. As we run the MCMC longer (i.e. take more samples), we get an answer that is numerically more precise (SE converges to 0) but the uncertainty in the parameter (i.e. SD) stays the same because that’s determined by the sample size of the DATA not the length of the MCMC. Finally, the Time-series SE is a variant of the SE calculation that accounts for the autocorrelation in the MCMC samples. In practice is is therefore more appropriate to use this term to assess numerical accuracy.

-
plot(fit$params,auto.layout = FALSE)    ## MCMC diagnostic plots
-summary(fit$params) ## parameter estimates  
-

Assessing the convergence of the MCMC is first done visually, but more generally the use of statistical diagnostics to assess convergence is highly encouraged. There are a number of metrics in the literature, but the most common is the Gelman-Brooks-Rubin statistic, which compare the variance within each chain to the variance across chains. If the chains have converged then this quantity should be 1. Values less than 1.05 are typically considered sufficient by most statisticians, but these are just rules-of-thumb.

-
gelman.plot(fit$params,auto.layout = FALSE)
-gelman.diag(fit$params)
-

As with any modeling, whether statistical or process-based, another common diagnostic is a predicted vs observed plot. In a perfect model the data would fall along the 1:1 line. The deviations away from this line are the model residuals. If observations lie along a line other than the 1:1 this indicates that the model is biased in some way. This bias is often assessed by fitting a linear regression to the points, though two important things are noteworthy about this practice. First, the \(R^2\) and residual error of this regression are not the appropriate statistics to use to assess model performance (though you will frequently find them reported incorrectly in the literature). The correct \(R^2\) and residual error (a.k.a Root Mean Square Error, RMSE) are based on deviations from the 1:1 line, not the regression. The code below shows these two terms calculated by hand. The second thing to note about the regression line is that the standard regression F-test, which assesses deviations from 0, is not the test you are actually interested in, which is whether the line differs from 1:1. Therefore, while the test on the intercept is correct, as this value should be 0 in an unbiased model, the test statistic on the slope is typically of less interest (unless your question really is about whether the model is doing better than random). However, this form of bias can easily be assessed by looking to see if the CI for the slope overlaps with 1.

-
## predicted vs observed plot
-par(mfrow=c(1,1))
-mstats = summary(fit$predict)
-pmean = mstats$statistics[grep("pmean",rownames(mstats$statistics)),1]
-plot(pmean,dat$Photo,pch="+",xlab="Predicted A",ylab = "Observed A")
-abline(0,1,col=2,lwd=2)
-bias.fit = lm(dat$Photo~pmean)
-abline(bias.fit,col=3,lty=2,lwd=2)
-legend("topleft",legend=c("1:1","regression"),lwd=2,col=2:3,lty=1:2)
-summary(bias.fit)
-RMSE = sqrt(mean((pmean-dat$Photo)^2))
-RMSE
-R2 = 1-RMSE^2/stats::var(dat$Photo)
-R2
-confint(bias.fit)
-

In the final set of plots we look at the actual A-Ci and A-Q curves themselves. Here we’ve added two interval estimates around the curves. The CI captures the uncertainty in the parameters and will asympotically shrink with more and more data. The PI (predictive interval) includes the parameter and residual error. If our fit is good then 95% PI should thus encompass at least 95% of the observations. That said, as with any statistical model we want to look for systematic deviations in the residuals from either the mean or the range of the PI.

-
## Response curve
-plot_photo(dat,fit)
-

Note: on the last figure you will get warnings about “No ACi” and “No AQ” which can be ignored. These are occuring because the file that had the ACi curve didn’t have an AQ curve, and the file that had the AQ curve didn’t have an ACi curve.

-
-
-

5.5.2.4 Additional information

-

There is a more detailed R Vignette on the use of the PEcAn photosynthesis module available in the PEcAn Repository.

-
-
-

5.5.2.5 Citations

-

Dietze, M.C. (2014). Gaps in knowledge and data driving uncertainty in models of photosynthesis. Photosynth. Res., 19, 3–14.

-

Farquhar, G., Caemmerer, S. & Berry, J.A. (1980). A biochemical model of photosynthetic CO2 assimilation in leaves of C3 species. Planta, 149, 78–90.

-

Feng, X. & Dietze, M.C. (2013). Scale dependence in the effects of leaf ecophysiological traits on photosynthesis: Bayesian parameterization of photosynthesis models. New Phytol., 200, 1132–1144.

- -
-
-
-

5.5.3 Parameter Data Assimilation

-
-

5.5.3.1 Objectives

-
    -
  • Gain hands-on experience in using Bayesian MCMC techniques to calibrate a simple ecosystem model using parameter data assimilation (PDA)
  • -
  • Set up and run a PDA in PEcAn using model emulation technique, assimilating NEE data from Niwot Ridge
  • -
  • Examine outputs from a PDA for the SIPNET model and evaluation of the calibrated model against i) data used to constrain model, ii) additional data for the same site
  • -
-
-
-

5.5.3.2 Larger Context

-

Parameter data assimilation (PDA) occurs as one step in the larger process of model calibration, validation, and application. The goal of PDA is to update our estimates of the posterior distributions of the model parameters using data that correspond to model outputs. This differs from our previous use of PEcAn to constrain a simple model using data that map directly to the model parameters. Briefly, the recommended overall approach for model calibration and validation consists of the following steps:

-
    -
  1. Assemble and process data sets required by the model as drivers
  2. -
  3. Perform an initial test-run of the model as a basic sanity check
  4. -
-
    -
  • Were there errors in drivers? (return to 1)
  • -
  • Is the model in the same ballpark as the data?
  • -
-
    -
  1. Construct priors for model parameters
  2. -
  3. Collect/assemble the data that can be used to constrain model parameters and outputs
  4. -
  5. Meta-analysis
  6. -
  7. Sensitivity analysis (SA)
  8. -
  9. Variance Decomposition (VD)
  10. -
  11. Determine what parameters need further constraint
  12. -
-
    -
  • Does this data exist in the literature? (repeat 4-8)
  • -
  • Can I collect this data in the field? (repeat 4-8)
  • -
-
    -
  1. Ensemble Analysis
  2. -
-
    -
  • Is reality within the range of the uncertainty in the model?
  • -
-
    -
  1. Evaluate/estimate uncertainties in the data
  2. -
  3. Parameter Data Assimilation:
  4. -
-
    -
  • Propose new parameter values
  • -
  • Evaluate L(data | param) & prior(param)
  • -
  • Accept or reject the proposed parameter values
  • -
  • Repeat many times until a histogram of accepted parameter values approximates the true posterior distribution.
    -
  • -
-
    -
  1. Model evaluation [preferably ensemble based]
  2. -
-
    -
  • Against data used to constrain model
  • -
  • Against additional data for this site -
      -
    • Same variable, different time
    • -
    • Different variables
    • -
  • -
  • Against data at a new site
  • -
  • Do I need more data? Repeat 4-9 (direct data constraint) or 6-11 (parameter data assimilation).
  • -
-
    -
  1. Application [preferably ensemble forecast or hindcast]
  2. -
-
-
-

5.5.3.3 Connect to Rstudio

-

Today, we’re again going to work mostly in Rstudio, in order to easily edit advanced PEcAn settings and browse files. So if you haven’t already, connect now to the Rstudio server on your VM ([URL]/rstudio).

-

This tutorial assumes you have successfully completed an ensemble and a sensitivity analysis (Demo 2) before.

-
-
-

5.5.3.4 Defining variables

-

The following variables need to be set specific to the site being run and the workflow being run

-
workflow_id <- 99000000002  ## comes from the History table, your successful ensemble run's workflow ID
-
-## from URL/bety/inputs.  
-##   Search by Ameriflux ID (e.g. US-NR1)
-##   Find the "plain" site record (no CF or model name) that's on your server
-##    (probably last in the list)
-##   Click on the magnifying glass icon then look under "View Related Files"
-datadir     <- "/home/carya/output/dbfiles/AmerifluxLBL_site_0-772/"
-
-## where PEcAn is saving output (default OK on VM)
-outdir      <- "/home/carya/output/"
-
-
-

5.5.3.5 Initial Ensemble Analysis

-

A good place to start when thinking about a new PDA analysis is to look at the current model fit to observed data. In fact, we want to compare data to a full ensemble prediction from the model. This is important because our current parameter distributions will be the priors for PDA. While the analysis will translate these priors into more optimal (in terms of producing model output that matches observations) and more confident (i.e. narrower) posterior distributions, these results are inherently constrained by the current parameter distributions. Thus, if reality falls far outside the prior ensemble confidence interval (which reflects the current uncertainty of all model parameters), data assimilation will not be able to fix this. In such cases, the prior parameter estimates must already be over-constrained, or there are structural errors in the model itself that need fixing. -To begin, let’s load up some NEE observations so that we can plot them along with our ensemble predictions. In the code below the elements in bold may vary depending on site and your previous runs.

-
library(PEcAn.all)
-
-# read settings
-settings <- read.settings(file.path(outdir,paste0("PEcAn_",workflow_id),"pecan.CONFIGS.xml"))
-
-# open up a DB connection
-con <- PEcAn.DB::db.open(settings$database$bety)
-
-# Fill out the arguments needed by load_data function
-
-# read file format information
-format     <- PEcAn.DB::query.format.vars(bety = con, format.id = 5000000002)
-start_year <- lubridate::year(settings$run$start.date)
-end_year   <- lubridate::year(settings$run$end.date)
-vars.used.index <- which(format$vars$bety_name %in% c("NEE", "UST"))
-
-obs <-PEcAn.benchmark::load_data(data.path = file.path(datadir, "AMF_US-NR1_BASE_HH_9-1.csv"),
-                                 format = format, start_year = start_year,  end_year = end_year,
-                                  site = settings$run$site,
-                                  vars.used.index = vars.used.index,
-                                  time.row = format$time.row)
-
-obs$NEE[obs$UST<0.4] <- NA  ## U* filter
-NEEo <- obs$NEE
-

Now let’s load up our ensemble outputs from the previous ensemble analysis (Demo 2) and plot our ensemble predictions against our NEE observations.

-
# load outputs, try not to delete prePDA ensemble output filename from your environment
-prePDA_ensemble_output_file <- file.path(outdir,paste0("PEcAn_",workflow_id, "/ensemble.ts.", settings$ensemble$ensemble.id, ".NEE.2003.2006.Rdata"))
-load(prePDA_ensemble_output_file)
-
-# calculate CI
-pre_pda_ens <- ensemble.ts[["NEE"]]
-preCI <- apply(pre_pda_ens, 2, quantile, c(0.025, 0.5, 0.975), na.rm = TRUE)
-
-# plot model ensemble
-ymin <- min(min(c(preCI, NEEo), na.rm = TRUE))
-ymax <- max(max(c(preCI, NEEo), na.rm = TRUE))
-plot(preCI[2,], ylim = c(ymin, ymax), lwd = 2, xlab = "time", ylab = "NEE", main = "pre-PDA model ensemble vs data", type = "n")
-prepoly <- 1:dim(preCI)[2]
-polygon(c(prepoly, rev(prepoly)), c(preCI[3,], rev(preCI[1,])), col='khaki', border=NA)
-
-# add data
-points(NEEo, pch = ".", col= adjustcolor("purple",alpha.f=0.5))
-legend("topright", legend=c("Data","Pre-PDA Model"), pch=c(15,15),
-        col=c("purple","khaki"))
-

When interpreting your results it is important to remember the difference between a confidence interval, which just includes parameter uncertainties, and a predictive interval, which includes parameter and residual uncertainties. Your ensemble analysis plot illustrates the former—i.e., the confidence in the mean NEE. By contrast, the data reflect both changes in mean NEE, and random variability. As such, we can’t expect all the data to fall within the CI; in fact, if we had unlimited data to constrain mean NEE, the CI would collapse to a single line and none of the data would be contained! However, your plot will give you an idea of how much uncertainty there is in your model currently, and help to identify systematic errors like bias (values consistently too high or low) or poorly represented seasonal patterns.

-
-
-

5.5.3.6 Questions:

-
    -
  • Does your ensemble agree well with the data?
  • -
  • If so, how much room for improvement is there, in terms of tightening the CI?
  • -
  • If not, what are the greatest discrepancies?
  • -
  • What are some of the problems (with model, data, and/or PEcAn) that might explain the data-model disparity you see?
  • -
-
-
-

5.5.3.7 Choosing Parameters

-

Beyond exploratory exercises, the first step of PDA analysis is to choose the model parameters you will target for optimization. PDA is computationally expensive (even when using an emulator), and the cost increases exponentially with the number of parameters targeted. The number you can handle in any given analysis completely depends on the complexity of the model and your available computational resources, but in practice it’s going to be rather small (~1–10) relative to the large number of parameters in a mechanistic ecosystem model (~10–100). -Given this limitation, it is important to target parameters that can contribute substantially to improving model fit. If you recall, identifying those parameters was the goal of the uncertainty analysis you conducted previously, in the second PEcAn demo. Let’s revisit that analysis now. Open your variance decomposition graph from Demo 2 -From this figure decide which variables you will target with PDA. As noted, an obvious criterion is that the parameter should be contributing a large amount of uncertainty to the current model, because otherwise it simply can’t change the model output much no matter how much you try to optimize it. But there are other considerations too. For example, if two parameters have similar or competing roles in the model, you may have trouble optimizing both simultaneously. In practice, there will likely be some guess-and-testing involved, though a good understanding of how the model works will help. It may also help to look at the shape of the Sensitivity responses and details of model fit to data (your ensemble analysis from the previous section). -For the purposes of this demo, choose eight to ten parameters (in total, if you have more than one PFT) that contribute high uncertainty to model output and/or seem like good choices for some other rational reason.

-
-
-

5.5.3.8 Questions:

-
    -
  • Which parameters did you choose, and why?
  • -
-
-
-

5.5.3.9 Editing PEcAn settings

-

Now let’s add settings to tell PEcAn how to run the PDA with emulator, we will come to the details of model emulation later. Open up the pecan.CONFIGS.xml file you located previously, and choose File > Save as... from the menu to save a new copy as pecan.PDA.xml. Now add the block of XML listed below to the file, immediately after the line. Check and fill in the parts corresponding to your run when necessary. -In this block, use the <param.names><param> tags to identify the parameters you’ve chosen for PDA (it’s up to you to choose the number of parameters you want to constrain, then you can set the <n.knot> to be >= 10 per parameter you choose, e.g. 200 knots for 10 parameters). Here, you need to use PEcAn’s standard parameter names, which are generally not the same as what’s printed on your variance decomposition graph. To find your parameters look at the row names in the prior.distns.csv file for each PFT under the PFT pulldown menu. Insert the variable name (exactly, and case sensitive) into the <param> tags of the XML code below. -In addition, you may need to edit <inputs><file><path>, depending on the site and year you ran previously. The rest of the settings control options for the PDA analysis (how long to run, etc.), and also identify the data to be used for assimilation. For more details, see the assim.batch vignette on the PEcAn GitHub page (https://goo.gl/9hYVPQ).

-
<?xml version="1.0"?>    <-- These lines are already in there. Don't duplicate them,   
-<pecan>                  <-- just paste the <assim.batch> block below right after them.
-  <assim.batch>
-    <method>emulator</method>
-    <n.knot>160</n.knot>                         <-- FILL IN
-    <iter>25000</iter>
-    <chain>3</chain>
-    <param.names>
-      <soil>
-        <param>YOUR_PFT_1_PARAM_1</param>        <-- FILL IN
-        <param>YOUR_PFT_1_PARAM_2</param>        <-- FILL IN
-      </soil>
-       <temperate.coniferous>                                      
-         <param>YOUR_PFT_2_PARAM_1</param>       <-- FILL IN
-         <param>YOUR_PFT_2_PARAM_2</param>       <-- FILL IN
-         <param>YOUR_PFT_2_PARAM_3</param>       <-- FILL IN
-         <param>YOUR_PFT_2_PARAM_4</param>       <-- FILL IN
-         <param>YOUR_PFT_2_PARAM_5</param>       <-- FILL IN
-         <param>YOUR_PFT_2_PARAM_6</param>       <-- FILL IN
-       </temperate.coniferous>
-    </param.names>
-    <jump>
-        <adapt>100</adapt>
-        <adj.min>0.1</adj.min>
-        <ar.target>0.3</ar.target>
-    </jump>
-    <inputs>
-     <file>
-      <path>
-         <path>/home/carya/output/dbfiles/AmerifluxLBL_site_0-772/AMF_US-NR1_BASE_HH_9-1.csv</path>       
-      </path>
-      <format>5000000002</format>
-      <input.id>1000011238</input.id>        <-- FILL IN, from BETY inputs table, this is *NOT* the workflow ID
-      <likelihood>Laplace</likelihood>
-      <variable.name>
-        <variable.name>NEE</variable.name>
-        <variable.name>UST</variable.name>
-      </variable.name>
-      <variable.id>297</variable.id>
-     </file>
-    </inputs>
-  </assim.batch>
-

Once you’ve made and saved the changes to your XML, load the file and check that it contains the new settings:

-
settings <- read.settings(file.path(outdir,paste0("PEcAn_",workflow_id),"pecan.PDA.xml"))
-settings$assim.batch
-

If the printed list contains everything you just added to pecan.PDA.xml, you’re ready to proceed.

-
-
-

5.5.3.10 Investigating PEcAn function pda.emulator (optional)

-

Before we run the data assimilation, let’s take a high-level look at the organization of the code. Use the Rstudio file browser to open up ~/pecan/modules/assim.batch/R/pda.emulator.R. This code works in much the same way as the pure statistical models that we learned about earlier in the week, except that the model being fit is a statistical model that emulates a complicated process-based computer simulation (i.e., an ecosystem model). We could have directly used the ecosystem model (indeed PEcAn’s other PDA functions perform MCMC by actually running the ecosystem model at each iteration, see pda.mcmc.R script as an example), however, this would require a lot more computational time than we have today. Instead here we will use a technique called model emulation. This technique allows us to run the model for a relatively smaller number of times with parameter values that have been carefully chosen to give a good coverage of parameter space. Then we can interpolate the likelihood calculated for each of those runs to get a surface that “emulates” the true likelihood and perform regular MCMC, except instead of actually running the model on every iteration to get a likelihood, this time we will just get an approximation from the likelihood emulator. The general algorithm of this method can be further expressed as:

-
    -
  1. Propose initial parameter set sampling design
  2. -
  3. Run full model for each parameter set
  4. -
  5. Evaluate the likelihoods
  6. -
  7. Construct emulator of multivariate likelihood surface
  8. -
  9. Use emulator to estimate posterior parameter distributions
  10. -
  11. (Optional) Refine emulator by proposing new design points, goto 2)
  12. -
-

For now, we just want you to get a glimpse at the overall structure of the code, which is laid out in the comment headers in pda.emulator(). Most of the real work gets done by the functions this code calls, which are all located in the file ~/pecan/modules/assim.batch/R/pda.utils.R and the MCMC will be performed by the mcmc.GP() function in ~/pecan/modules/emulator/R/minimize.GP.R. To delve deeper into how the code works, take a look at these files when you have the time.

-
-
-

5.5.3.11 Running a demo PDA

-

Now we can go ahead and run a data assimilation MCMC with emulator. Since you’ve already loaded the settings containing your modified <assim.batch> XML block, all you need to do to start the PDA is run pda.emulator(settings). But, in the emulator workflow, there is a bit of a time consuming step where we calculate the effective sample size of the input data, and we have already done this step for you. You could load it up and pass it to the function explicitly in order to skip this step:

-
# load input data
-load("/home/carya/pda/pda_externals.Rdata")
-postPDA.settings <- pda.emulator(settings, external.data = inputs_w_neff)
-

After executing the code above, you will see print-outs to the console. The code begins with loading the prior values which in this case are the posterior distributions coming from your previous meta analysis. Then, normally, it loads the observational data and carries out necessary conversions and formatting to align it with model outputs, as we did separately above, but today it will skip this step as we are passing data externally. After this step, you will see a progress bar where the actual model is run n.knot times with the proposed parameter sets and then the outputs from these runs are read. Next, this model output is compared to the specified observational data, and the likelihood is calculated using the heteroskedastic Laplacian discussed previously. Once we calculate the likelihoods, we fit an emulator which interpolates the model output in parameter space between the points where the model has actually been run. Now we can put this emulator in the MCMC algorithm instead of the model itself. Within the MCMC loop the code proposes new parameter value from a multivariate normal jump distribution. The corresponding likelihood will be approximated by the emulator and the new parameter value is accepted or rejected based on its posterior probability relative to the current value.

-
-
-

5.5.3.12 Outputs from PEcAn’s Parameter Data Assimilation

-

When the PDA is finished, a number of outputs are automatically produced that are either the same as or similar to posterior outputs that we’ve seen before. These are located in the PEcAn_[workflow_id]/pft/* output directory and are identified by pda.[PFT]_[workflow_id] in the filenames:

-
    -
  • posteriors.pda.[PFT]*.pdf shows the posterior distributions resulting from your PDA
  • -
  • trait.mcmc.pda.[PFT]*.Rdata contains all the parameter samples contained in the PDA posterior
  • -
  • mcmc.pda.[PFT]*.Rdata is essentially the same thing in a different format
  • -
  • mcmc.diagnostics.pda.[PFT]*.pdf shows trace plots and posterior densities for each assimilated parameter, as well as pairs plots showing all pairwise parameter correlations.
  • -
-

Together, these files allow you to evaluate whether a completed PDA analysis has converged and how the posterior distributions compare to the priors, and to use the posterior samples in further analyses, including additional PDA. -If you haven’t done so already, take a look at all of the outputs described here.

-
-
-

5.5.3.13 Questions:

-
    -
  • Do the diagnostic figures indicate that your likelihood at least improved over the course of the analysis?
  • -
  • Does the MCMC appear to have converged?
  • -
  • Are the posterior distributions well resolved?
  • -
-
-
-

5.5.3.14 Post-PDA analyses

-

In addition to the outputs of the PDA itself, you may want to conduct ensemble and/or sensitivity analyses based on the posteriors of the data assimilation, in order to check progress towards improved model fit and/or changing sensitivity. For this, you need to generate new model runs based on parameters sampled from the updated (by PDA) posterior, which is a simple matter of rerunning several steps of the PEcAn workflow. -The PDA you ran has automatically produced an updated XML file (pecan.pda***.xml) that includes the posterior id to be used in the next round of runs. Locate this file in your run directory and load the file for the post-pda ensemble/sensitivity analysis (if you already have the settings list in your working environment you don’t need to re-read the settings):

-
 # read post-PDA settings if you don't have them in your wotking environment
- # replace the *** with the ensemble id given by the workflow
- # postPDA.settings <- read.settings(file.path(outdir,paste0("PEcAn_", workflow_id),"pecan.pda***.xml"))
-
- # Call model specific write.configs
-  postPDA.settings <- run.write.configs(postPDA.settings,
-                          write=postPDA.settings$database$bety$write,     
-                          ens.sample.method=postPDA.settings$ensemble$method)
-
- # Let's save the settings with the new ensemble id
-  PEcAn.settings::write.settings(settings, outputfile=paste0('pecan.pda', postPDA.settings$assim.batch$ensemble.id,'.xml'))
-
- # Start ecosystem model runs, this one takes awhile...
-  PEcAn.workflow::start_model_runs(postPDA.settings, postPDA.settings$database$bety$write)
-
- # Get results of model runs
-  get.results(postPDA.settings)
-
- # Repeat ensemble analysis with PDA-constrained params
- run.ensemble.analysis(postPDA.settings, TRUE)
-
- # let's re-load the pre-PDA ensemble outputs
- load(prePDA_ensemble_output_file)
- pre_pda_ens <- ensemble.ts[["NEE"]]
-
- # nowload the post-PDA ensemble outputs
- postPDA_ensemble_output_file <- file.path(outdir,paste0("PEcAn_", workflow_id, "/ensemble.ts.", postPDA.settings$ensemble$ensemble.id, ".NEE.2003.2006.Rdata"))
- load(postPDA_ensemble_output_file)
- post_pda_ens <- ensemble.ts[["NEE"]]
-
- # try changing the window value for daily, weekly, monthly smoothing later
- # see if this changes your model-data agreement, why?
- window <- 1 # no smoothing
- pre_pda <- t(apply(pre_pda_ens, 1, function(x) {
-        tapply(x, rep(1:(length(x)/window + 1), each = window)[1:length(x)],
-               mean, na.rm = TRUE)}))
- post_pda <- t(apply(post_pda_ens, 1, function(x) {
-        tapply(x, rep(1:(length(x)/window + 1), each = window)[1:length(x)],
-               mean, na.rm = TRUE)}))
- fobs <- tapply(NEEo, rep(1:(length(NEEo) / window + 1),
-                          each = window)[1:length(NEEo)], mean, na.rm = TRUE)
-
-
- # save the comparison plots to pdf
- pdf(file.path(outdir,paste0("PEcAn_",workflow_id),"model.data.comparison.pdf"), onefile=T,
-     paper='A4r', height=15, width=20)
-
- # now plot the pre-PDA ensemble similar to the way we did before
- preCI <- apply(pre_pda, 2, quantile, c(0.025, 0.5, 0.975), na.rm = TRUE)
- ymin <- min(min(c(preCI, fobs), na.rm = TRUE))
- ymax <- max(max(c(preCI, fobs), na.rm = TRUE))
- plot(pre_pda[1,], ylim = c(ymin, ymax), lwd = 2, xlab = "time", ylab = "NEE", main = "pre-PDA vs post-PDA", type = "n")
- prepoly <- 1:dim(preCI)[2]
- polygon(c(prepoly, rev(prepoly)),c(preCI[3,], rev(preCI[1,])),col='khaki',border=NA)
-
- # plot the post-PDA ensemble
- postCI <- apply(post_pda, 2, quantile, c(0.025, 0.5, 0.975), na.rm = TRUE)
- postpoly <- 1:dim(postCI)[2]
- polygon(c(postpoly, rev(postpoly)),c(postCI[3,], rev(postCI[1,])),col='lightblue',border=NA)
-
- # finally let's add the data and see how we did
- points(fobs, pch = ".", col= adjustcolor("purple",alpha.f=0.7))
- legend("topright", legend=c("Data","Pre-PDA Model", "Post-PDA Model"), pch=c(15,15,15),
-        col=c("purple","khaki","lightblue"))
-
- dev.off()
-
-
- # Repeat variance decomposition to see how constraints have changed
- run.sensitivity.analysis(postPDA.settings)
-

Now you can check the new figures produced by your analyses under PEcAn_[workflow_id]/pft/*/variance.decomposition.*.pdf and PEcAn_[workflow_id]/pft/*/sensitivity.analysis.*.pdf, and compare them to the previous ones. Also, take a look at the comparison of model outputs to data when we run SIPNET with pre- and post-PDA parameter (mean) values under PEcAn_[workflow_id]/model.data.comparison.pdf.

-
-
-

5.5.3.15 Questions:

-
    -
  • Looking at the ensemble analysis outputs in order (i.e., in order of increasing ID in the filenames), qualitatively how did the model fit to data change over the course of the analysis?
  • -
  • Based on the final ensemble analysis, what are the major remaining discrepancies between model and data?
  • -
  • Can you think of the processes / parameters that are likely contributing to the differences?
  • -
  • What would be your next steps towards evaluating or improving model performance?
  • -
- -
-
-
-

5.5.4 State-Variable Data Assimilation

-
-

5.5.4.1 Objectives:

-
    -
  • Assimilate tree ring estimated NPP & inventory AGB within the SIPNET model in order to:
  • -
  • Reconcile data and model NPP & AGB estimates
  • -
  • Constrain inferences about other ecosystem responses.
  • -
-
-
-

5.5.4.2 Overview:

-
    -
  • Initial Run
  • -
  • Settings
  • -
  • Load and match plot and increment data
  • -
  • Estimate tree-level data uncertainties
  • -
  • Estimate allometric relationships
  • -
  • Estimate stand-level NPP
  • -
  • Sample initial conditions and parameters
  • -
  • Run Ensemble Kalman Filter
  • -
-
-
-

5.5.4.3 Initial Run

-

Perform a site-level SIPNET run using the following settings

-
    -
  • Site = UNDERC
  • -
  • Start = 01/01/1979
  • -
  • End = 12/31/2015
  • -
  • Met = NARR
  • -
  • Check Brown Dog
  • -
  • When the run is complete, open the pecan.xml and cut-and-paste the outdir for later use
  • -
-
-
-

5.5.4.4 Settings:

-
    -
  • Open the PEcAn RStudio environment back up.

  • -
  • Set your working directory to the outdir from above setwd(outdir) and shift the file browser to that location (Files > More > Go To Working Directory)

  • -
  • Open up the latest settings file pecan.CONFIG.xml.

  • -
  • At the top of the file add the following tags to set the ensemble size

  • -
-
   <state.data.assimilation>
-   <n.ensemble>35</n.ensemble>
-   <process.variance>FALSE</process.variance>
-   <sample.parameters>TRUE</sample.parameters>
-   <data>
-    <format_id>1000000040</format_id>
-    <input.id>1000013298</input.id>
-  </data>
-   <state.variables>
-   <variable>
-   <variable.name>NPP</variable.name>
-   <unit>MgC/ha/yr</unit>
-        <min_value>-9999</min_value>
-        <max_value>9999</max_value>
-   </variable>
-   <variable>
-   <variable.name>AbvGrndWood</variable.name>
-       <unit>KgC/m^2</unit>
-       <min_value>0</min_value>
-       <max_value>9999</max_value>
-   </variable>
-   <variable>
-   <variable.name>TotSoilCarb</variable.name>
-      <unit>KgC/m^2</unit>
-      <min_value>0</min_value>
-      <max_value>9999</max_value>
-   </variable>
-   <variable>
-   <variable.name>LeafC</variable.name>
-         <unit>m^2/m^2</unit>
-         <min_value>0</min_value>
-         <max_value>9999</max_value>
-   </variable>
-   <variable>
-   <variable.name>SoilMoistFrac</variable.name>
-         <unit></unit>
-         <min_value>0</min_value>
-         <max_value>9999</max_value>
-   </variable>
-   <variable>
-   <variable.name>SWE</variable.name>
-         <unit>cm</unit>
-         <min_value>0</min_value>
-         <max_value>9999</max_value>
-   </variable>
-   <variable>
-   <variable.name>Litter</variable.name>
-         <unit>gC/m^2</unit>
-         <min_value>0</min_value>
-         <max_value>9999</max_value>
-   </variable>
-   </state.variables>
-   <forecast.time.step>year</forecast.time.step>
-  <start.date>1980/01/01</start.date>
-  <end.date>2015/12/31</end.date>
-  </state.data.assimilation>
-
    -
  • Delete the <pfts> block from the settings

  • -
  • In the PEcAn History, go to your PDA run and open pecan.pda[UNIQUEID].xml (the one PEcAn saved for you AFTER you finished the PDA)

  • -
  • Cut-and-paste the PDA <pfts> block into the SDA settings file

  • -
  • Save the file as pecan.SDA.xml

  • -
-
-
-

5.5.4.5 Loading data

-
    -
  • If you have not done so already, clone (new) or pull (update) the PalEON Camp2016 repository

  • -
  • Open a shell under Tools > Shell

  • -
  • cd to go to your home directory

  • -
  • To clone: git clone git@github.com:PalEON-Project/Camp2016.git

  • -
  • To pull: cd Camp2016; git pull https://github.com/PalEON-Project/Camp2016.git master

  • -
  • Open the tree-ring data assimilation workflow under Home > pecan > scripts > workflow.treering.R

  • -
  • Run the script from the start up through the LOAD DATA section

  • -
-
-
-

5.5.4.6 Estimating tree-level data uncertainties

-

One thing that is critical for data assimilation, whether it is being used to estimate parameters or state variables, is the careful consideration and treatment of the uncertainties in the data itself. For this analysis we will be using a combination of forest plot and tree ring data in order to estimate stand-level productivity. The basic idea is that we will be using the plot-sample of measured DBHs as an estimate of the size structure of the forest, and will use the annual growth increments to project that forest backward in time. Tree biomass is estimated using empirical allometric equations relating DBH to aboveground biomass. There are a number of sources of uncertainty in this approach, and before moving you are encouraged to think about and write down a few:

-
-
-
-
-
-
-
-
-

Today we will use a statistical model based on the model developed by Clark et al 2007 that partitions out a number of sources of variability and uncertainty in tree ring and plot data (Fig 1). This model is a Bayesian statespace model that treats the true diameters (D) and increments (X) as latent variables that are connected through a fairly simple mixed effects process model

-

\[D_{ij,t+1} = D_{ij,t} + \mu + \alpha_{i} + \alpha_t + \epsilon_{ij,t}\]

-

where i = individual, j = plot, t = time (year). Each of these terms are represented at normal distributions, where \(\mu\) is a fixed effect (overall mean growth rate) and individual and year are random effects

-

\[\mu \sim N(0.5,0.5)\] -\[\alpha_{i} \sim N(0,\tau_{i})\] -\[\alpha_{t} \sim N(0,\tau_{t})\] -\[\epsilon_{ij,t} \sim N(0,\tau_{e})\]

-

The connection between the true (latent) variable and the observations is also represented as normal with these variances representing measurement error:

-

\[D_{ij,t}^O \sim N( D_{ij,t},\tau_D)\] -\[X_{ij,t}^O \sim N( X_{ij,t},\tau_r)\]

-

Finally, there are five gamma priors on the precisions, one for the residual process error (\(\tau_{e}\)), two for the random effects on individual (\(\tau_{i}\)) and time (\(\tau_t\)), -and two measurement errors or DBH (\(\tau_D\)) and tree rings (\(\tau_r\))

-

\[\tau_{e} \sim Gamma(a_e,r_e)\] -\[\tau_{i} \sim Gamma(a_i,r_i)\] -\[\tau_{t} \sim Gamma(a_t,r_t)\] -\[\tau_{D} \sim Gamma(a_D,r_D)\] -\[\tau_{r} \sim Gamma(a_r,r_r)\]

-

This model is encapsulated in the PEcAn function:

-
InventoryGrowthFusion(combined,n,iter)
-

where the first argument is the combined data set formatted for JAGS and the second is the number of MCMC interations. The model itself is written for JAGS and is embedded in the function. Running the above InventoryGrowthFusion will run a full MCMC algorithm, so it does take a while to run. The code returns the results as an mcmc.list object, and the next line in the script saves this to the outputs directory We then call the function InventoryGrowthFusionDiagnostics to print out a set of MCMC diagnostics and example time-series for growth and DBH.

-
-
-

5.5.4.7 Allometric equations

-

Aboveground NPP is estimated as the increment in annual total aboveground biomass. This estimate is imperfect, but not unreasonable for demonstration purposes. As mentioned above, we will take an allometric approach of scaling from diameter to biomass: Biomass = b0 * DBH b1 We will generate the allometric equation on a PFT level using another Bayesian model that synthesizes across a database of species-level allometric equations (Jenkins et al 2004). This model has two steps within the overall MCMC loop. First it simulates data from each equation, including both parameter and residual uncertainties, and then it updated the parameters of a single allometric relationship across all observations. The code also fits a second model, which includes a random site effect, but for simplicity we will not be using output from this version. Prior to running the model we have to first query the species codes for our pfts. Next we pass this PFT list to the model, AllomAve, which saves the results to the output directory in addition to returning a summary of the parameters and covariances.

-
-
-

5.5.4.8 Estimate stand-level NPP

-

If we have no uncertainty in our data or allometric equations, we could estimate the stand aboveground biomass (AGB) for every year by summing over the biomass of all the trees in the plot and then divide by the plot area. We would then estimate NPP by the difference in AGB between years. One approach to propagating uncertainties into NPP would be to transform the distribution of DBH for each individual tree and year into a distribution for biomass, then sum over those distributions to get a distribution for AGB and then subtract the distributions to get the distributions of NPP. However, if we do this we will greatly overestimate the uncertainty in NPP because we ignore the fact that our increment data has much lower uncertainty than our diameter data. In essence, if we take a random draw from a distribution of AGB in year and it comes back above average, the AGB is much more likely to also be above average the following year than if we were to do an independent draw from that distribution. Accounting for this covariance requires a fairly simple change in our approach and takes advantage of the nature of the MCMC output. The basic idea is that we are going to take a random draw from the full individual x year diameter matrix, as well as a random draw of allometric parameters, and perform the ‘zero-error’ calculation approach described above. We will then create a distribution of all the NPP estimates that comes out of repeated draws for the full diameter matrix. This approach is encapsulated in the function plot2AGB. The argument unit.conv is a factor that combines both the area of the plot and the unit conversion from tree biomass (kg/tree) to stand AGB (Mg/ha). There are two outputs from plot2AGB: a pdf depicting estimated NPP and AGB (mean and 95% CI) time series, with each page being a plot; and plot2AGB.Rdata, a binary record of the function output that is read into the data assimilation code. The latter is also returned from the fuction and assigned to the variable “state”. Finally, we calculate the mean and standard deviation of NPP and save this as obs.

-
-
-

5.5.4.9 Build Initial Conditions

-

The function sample.IC.SIPNET uses the AGB estimate from the previous function in order to initialize the data assimilation routine. Specifically it samples n.ensemble values from the first time step of the AGB estimate. Embedded in this function are also a number of prior distributions for other state variables, which are also samples in order to create a full set of initial conditions for SIPNET.

-
-
-

5.5.4.10 Load Priors

-

The function sample.parameters samples values from the most recent posterior parameter distributions. You can also specify a specific set of parameters so sample from by specifying the argument <prior> within <assim.sequential> as the posterior.id you want to use. This is useful to know if you want to go back and run with the Meta-analysis posteriors, or if you end up rerunning the meta-analysis and need to go back and specify the parameter data assimilation posteriors instead of the most recent.

-
-
-

5.5.4.11 Ensemble Kalman Filter

-

The function sda.enkf will run SIPNET in Ensemble Kalman Filter mode. The output of this function will be all the of run outputs, a PDF of diagnostics, and an Rdata object that includes three lists:

-
    -
  • FORECAST will be the ensemble forecasts for each year
  • -
  • ANALYSIS will be the updated ensemble sample given the NPP observations
  • -
  • enkf.params contains the prior and posterior mean vector and covariance matrix for each time step.
  • -
-

If you look within this function you will find that much of the format is similar to the pda.mcmc function, but in general is much simpler. The function begins by setting parameters, opening a database connection, and generating workflow and ensemble ID’s. Next we split the SIPNET clim meteorology file up into individual annual files since we will be running SIPNET for a year at a time between updates. Next we perform an initial set of runs starting from the initial states and parameters we described above. In doing so we create the run and output directories, the README file, and the runs.txt file that is read by start_model_runs. Worth noting is that the README and runs.txt don’t need to be updated within the forecast loop. Given this initial run we then enter the forecast loop. Within this loop over years we perform four basic steps. First, we read the output from the latest runs. Second, we calculate the updated posterior state estimates based on the model ensemble prior and observation likelihood. Third, we resample the state estimates based on these posterior parameters. Finally, we start a new set of runs based on this sample. The sda.enfk function then ends by saving the outputs and generating some diagnostic figures. The first set of these shows the data, forecast, analysis. The second set shows pairs plots of the covariance structure for the Forecast and Analysis steps. The final set shows the time-series plots for the Analysis of the over state variables produced by SIPNET.

-
-
-

5.5.4.12 Finishing up

-

The final bit of code in the script will register the workflow as complete in the database. After this is run you should be able to find all of the runs, and all of the outputs generated above, from within the PEcAn webpages.

- -
-
-
-

5.5.5 PEcAn: Testing the Sensitivity Analysis Against Observations”

-
-

5.5.5.1 Author: “Ankur Desai”

-
-
-

5.5.5.2 Flux Measurements and Modeling Course, Tutorial Part 2

-

This tutorial assumes you have successfully completed the Demo01, Demo02 and the modelVSdata tutorial.

-
-
-

5.5.5.3 Introduction

-

Now that you have successfully run PEcAn through the web interface and have learned how to do a simple comparison of flux tower observations to model output, let’s start looking at how data assimilation and parameter estimation would work with an ecosystem model.

-

Before we start a full data assimilation exercise, let’s try something simple – single parameter selection by hand.

- -

In Demo02, you have ran a sensitivity analysis of SIPNET model runs at Niwot Ridge sampling across quantiles of a parameter prior, while holding all others to the median value. The pecan.xml file told PEcAn to run an sensitivity analysis, which simply meant SIPNET was run multiple times with the same driver, but varying parameter values one at a time (while holding all others to their median), and the parameter range also specified in the pecan.xml file (as quantiles, which were then sampled against the BETY database of observed variation in the parameter for species within the specific plant functional type).

-

Let’s try to compare Ameriflux NEE to SIPNET NEE across all these runs to make a plot of parameter vs. goodness-of-fit. We’ll start with root mean square error (RMSE), but then discuss some other tests, too.

-
-
-

5.5.5.4 A. Read in settings object from a run xml

-

Open up a connection to the bety database and create a settings object from your xml, just like in the modelVSdata tutorial.

-
settings<-PEcAn.settings::read.settings("~/output/PEcAn_99000000002/pecan.CONFIGS.xml")
-
-con <- PEcan.DB::db.open(settings$database$bety)
-

We read in the pecan.CONFIG.xml instead of the pecan.xml because the pecan.CONFIG.xml has already incorperated some of the information from the database we would have to query again if we used the pecan.xml.

-
runid<-as.character(read.table(paste(settings$outdir, "/run/","runs.txt", sep=""))[1,1]) # Note: if you are using an xml from a run with multiple ensembles this line will provide only the first run id
-outdir<- paste(settings$outdir,"/out/",runid,sep= "")
-start.year<-as.numeric(lubridate::year(settings$run$start.date))
-end.year<-as.numeric(lubridate::year(settings$run$end.date))
-
-site.id<-settings$run$site$id
-

Back to the files pane, within the run/ folder, find a folder called pft/ and within that a folder with the pft name (such as temprature.coniferous). Within that is a PDF file that starts sensitivity.analysis. In Rstudio, just click on the PDF to view it. You discussed this PDF last tutorial, through the web interface. Here, we see how the model NEE in SIPNET changes with each parameter.

-

Let’s read that sensitivity output. Navigate back up (..) to the ~/output/RUNDIR/ folder. Find a series of files that end in “.RData”. These files contain the R variables used to make these plots. In particular, there is sensitivity.output..RData which contains the annual NEE as a function of each parameter quantile. Click on it to load a variable into your environment. There is sensitivity.results..RData which contains plotting functions and variance decomposition output, which we don’t need in this tutorial. And finally, there is **sensitivity.samples.*.RData** which contains the actual parameter values and the RunIDs associated with each sensitivity run.

-

Click on sensitivity.samples..RData* to load it into your environment, or run the {r}load() script below. You should see a set of five new variables (pft.names, trait.names, sa.ensemble.id, sa.run.ids, sa.samples).

-

Let’s extract a parameter and it’s sensitivity NEE output from the list sa.samples, which is organized by PFT, and then by parameter. First, let’s look at a list of PFTs and parameters available:

-
load(paste(settings$outdir,"/sensitivity.samples.", settings$sensitivity.analysis$ensemble.id,".Rdata", sep=""))
-
-names(sa.samples)
-names(sa.samples$temperate.coniferous)
-

Now to see the actual parameter values used by the runs, just pick a parameter and type:

-
sa.samples$temperate.coniferous$psnTOpt
-

Let’s store that value for future use:

-
psnTOpt <- sa.samples$temperate.coniferous$psnTOpt
-

Now, to see the annual NEE output from the model for a particular PFT and parameter range, try

-
load(paste(settings$outdir,paste("/sensitivity.output", settings$sensitivity.analysis$ensemble.id,settings$sensitivity.analysis$variable,start.year,end.year,"Rdata", sep="."), sep=""))
-
-sensitivity.output$temperate.coniferous$psnTOpt
-

You could even plot the two:

-
plot(psnTOpt,sensitivity.output$temperate.coniferous$psnTOpt)
-

What do you notice?

-

Let’s try to read the output from a single run id as you did in the earlier tutorial.

-
runids <- sa.run.ids$temperate.coniferous$psnTOpt
-arun <- PEcAn.utils::read.output(runids[1], paste(settings$outdir, "out", runids[1], sep="/"), start.year= start.year, end.year= end.year,"NEE", dataframe = TRUE)
-
-plot(arun$posix,arun$NEE)
-
-
-

5.5.5.5 B. Now let’s bring in the actual observations

-

Recall reading Ameriflux NEE in the modelVSdata tutorial.

-
File_path<-"~/output/dbfiles/AmerifluxLBL_site_0-772/AMF_US-NR1_BASE_HH_9-1.csv"
-
-File_format<-PEcAn.DB::query.format.vars(bety = con, format.id = 5000000002) #This matches the file with a premade "format" or a template that describes how the information in the file is organized
-site<-PEcAn.DB::query.site(site.id = site.id, con)
-
-obs<-PEcAn.benchmark::load_data(data.path = File_path, format= File_format, time.row = File_format$time.row,  site = site, start_year = start.year, end_year = end.year)
-
-obs$NEE[obs$UST<0.2]<-NA #Apply a U* filter
-
-plottable<-align_data(model.calc = arun, obvs.calc = obs, align_method = "match_timestep", var= "NEE")
-head(plottable)
-
-
-

5.5.5.6 C. Finally, we can finally compare model to data

-

In the modelVSdata, you also compared NEE to the ensemble model run. Here we will do the same except we include each sensitivity run.

-
plot(plottable$NEE.m,plottable$NEE.o)
-abline(0,1,col="red")
-

And remember the formula for RMSE:

-
sqrt(mean((plottable$NEE.o-plottable$NEE.m)^2,na.rm = TRUE))
-

All we need to do to go beyond this is to make a loop that reads in each sensitivity run NEE based on runids, calculates RMSE against the observations, and stores it in an array, by combining the steps above in a for loop. Make sure you change the directory names and year to your specific run.

-
rmses <- rep(0,length(runids))
-for(r in 1:length(runids)){
-arun <- read.output(runids[r],paste(settings$outdir, "out", runids[r], sep="/"),2004,2004,"NEE", dataframe= TRUE)
-plottable<-align_data(model.calc = arun, obvs.calc = obs, align_method = "match_timestep", var= "NEE")
-rmses[r] <- sqrt(mean((plottable$NEE.o-plottable$NEE.m)^2,na.rm = TRUE))
-}
-
-rmses
-

Let’s plot that array

-
plot(psnTOpt,rmses)
-

Can you identify a minimum (if there is one)? If so, is there any reason to believe this is the “best” parameter? Why or why not? Think about all the other parameters.

-

Now that you have the hang of it, here are a few more things to try:

-
    -
  1. Try a different error functions, given actual NEE uncertainty. You learned earlier that uncertainty in half-hourly observed NEE is not Gaussian. This makes RMSE not the correct measure for goodness-of-fit. Go to ~/pecan/modules/uncertainty/R, open flux_uncertainty.R, and click on the source button in the program editing pane.
  2. -
-

Alternatively, you can source the function from the console using:

-
source("pecan/modules/uncertainty/R/flux_uncertainty.R")
-

Then you can run:

-
unc <- flux.uncertainty(plottable$NEE.o,QC=rep(0,17520))
-plot_flux_uncertainty(unc)
-

The figure shows you uncertainty (err) as a function of NEE magnitude (mag). How might you use this information to change the RMSE calculation?

-

Try a few other parameters. Repeat the above steps but with a different parameter. You might want to select one from the sensitivity PDF that has a large sensitivity or from the variance decomposition that is also poorly constrained.

- -
-
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/overview-1.html b/master/overview-1.html deleted file mode 100644 index b5ff61aec..000000000 --- a/master/overview-1.html +++ /dev/null @@ -1,863 +0,0 @@ - - - - - - - 23.1 Overview | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

23.1 Overview

-

Workflow inputs and outputs (click to open in new page, then zoom). Code used to generate this image is provided in qaqc/vignettes/module_output.Rmd

-

PEcAn Workflow

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/package-dependencies.html b/master/package-dependencies.html deleted file mode 100644 index a3867d137..000000000 --- a/master/package-dependencies.html +++ /dev/null @@ -1,861 +0,0 @@ - - - - - - - 31 Package Dependencies | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

31 Package Dependencies

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/paleon.html b/master/paleon.html deleted file mode 100644 index 4c84022e9..000000000 --- a/master/paleon.html +++ /dev/null @@ -1,864 +0,0 @@ - - - - - - - 15.9 PalEON | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

15.9 PalEON

-

Scale: -100 to -60 W Lon, 35 to 50 N Latitude \(US northern hardwoods + buffer\)

-

Resolution: 6hr, 0.5 degree

-

Availability: 850-2010

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/pecan-api.html b/master/pecan-api.html deleted file mode 100644 index c204786e7..000000000 --- a/master/pecan-api.html +++ /dev/null @@ -1,916 +0,0 @@ - - - - - - - 25.9 The PEcAn Docker API | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

25.9 The PEcAn Docker API

-

If you have a running instance of Dockerized PEcAn (or other setup where PEcAn workflows are submitted via RabbitMQ), -you have the option of running and managing PEcAn workflows using the pecanapi package.

-

For more details, see the pecanapi package vignette and function-level documentation. -What follows is a lightning introduction.

-
-

25.9.0.1 Installation

-

The package can be installed directly from GitHub via devtools::install_github:

-
devtools::install_github("pecanproject/pecan/api@develop")
-
-
-

25.9.0.2 Creating and submitting a workflow

-

With pecanapi, creating a workflow, submitting it to RabbitMQ, monitoring its progress, and processing its output can all be accomplished via an R script.

-

Start by loading the package (and the magrittr package, for the %>% pipe operator).

-
library(pecanapi)
-library(magrittr)
-

Set your PEcAn database user ID, and create a database connection object, which will be used for database operations throughout the workflow.

-
options(pecanapi.user_id = 99000000002)
-con <- DBI::dbConnect(
-  drv = RPostgres::Postgres(),
-  user = "bety",
-  password = "bety",
-  host = "localhost",
-  port = 5432
-)
-

Find model and site IDs for the site and model you want to run.

-
model_id <- get_model_id(con, "SIPNET", "136")
-all_umbs <- search_sites(con, "umbs%disturbance")
-site_id <- subset(all_umbs, !is.na(mat))[["id"]]
-

Insert a new workflow into the PEcAn database, and extract its ID.

-
workflow <- insert_new_workflow(con, site_id, model_id,
-                                start_date = "2004-01-01",
-                                end_date = "2004-12-31")
-workflow_id <- workflow[["id"]]
-

Pull all of this information together into a settings list object.

-
settings <- list() %>%
-  add_workflow(workflow) %>%
-  add_database() %>%
-  add_pft("temperate.deciduous") %>%
-  add_rabbitmq(con = con) %>%
-  modifyList(list(
-    meta.analysis = list(iter = 3000, random.effects = list(on = FALSE, use_ghs = TRUE)),
-    run = list(inputs = list(met = list(source = "CRUNCEP", output = "SIPNET", method = "ncss"))),
-    ensemble = list(size = 1, variable = "NPP")
-  ))
-

Submit the workflow via RabbitMQ, and monitor its progress in the R process.

-
submit_workflow(settings)
-watch_workflow(workflow_id)
-

Use THREDDS to access and analyze the output.

-
sipnet_out <- ncdf4::nc_open(run_dap(workflow_id, "2004.nc"))
-gpp <- ncdf4::ncvar_get(sipnet_out, "GPP")
-time <- ncdf4::ncvar_get(sipnet_out, "time")
-ncdf4::nc_close(sipnet_out)
-plot(time, gpp, type = "l")
- -
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/pecan-docker.html b/master/pecan-docker.html deleted file mode 100644 index 806fcaa10..000000000 --- a/master/pecan-docker.html +++ /dev/null @@ -1,1486 +0,0 @@ - - - - - - - 25.4 PEcAn Docker Architecture | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

25.4 PEcAn Docker Architecture

- -
-

25.4.1 Overview

-

The PEcAn docker architecture consists of many containers (see figure below) that will communicate with each other. The goal of this architecture is to easily expand the PEcAn system by deploying new model containers and registering them with PEcAn. Once this is done the user can now use these new models in their work. The PEcAn framework will setup the configurations for the models, and send a message to the model containers to start execution. Once the execution is finished the PEcAn framework will continue. This is exactly as if the model is running on a HPC machine. Models can be executed in parallel by launching multiple model containers.

-

-As can be seen in the figure the architecture leverages of two standard containers (in orange). The first container is postgresql with postgis (mdillon/postgis) which is used to store the database used by both BETY and PEcAn. The second containers is a messagebus, more specifically RabbitMQ (rabbitmq).

-

The BETY app container (pecan/bety) is the front end to the BETY database and is connected to the postgresql container. A http server can be put in front of this container for SSL termination as well to allow for load balancing (by using multiple BETY app containers).

-

The PEcAn framework containers consist of multiple unique ways to interact with the PEcAn system (none of these containers will have any models installed):

-
    -
  • PEcAn shiny hosts the shiny applications developed and will interact with the database to get all information necessary to display
  • -
  • PEcAn rstudio is a rstudio environment with the PEcAn libraries preloaded. This allows for prototyping of new algorithms that can be used as part of the PEcAn framework later.
  • -
  • PEcAn web allows the user to create a new PEcAn workflow. The workflow is stored in the database, and the models are executed by the model containers.
  • -
  • PEcAn cli will allow the user to give a pecan.xml file that will be executed by the PEcAn framework. The workflow created from the XML file is stored in the database, and the models are executed by the model containers.
  • -
-

The model containers contain the actual models that are executed as well as small wrappers to make them work in the PEcAn framework. The containers will run the model based on the parameters received from the message bus and convert the outputs back to the standard PEcAn output format. Once the container is finished processing a message it will immediatly get the next message and start processing it.

-
-
-

25.4.2 PEcAn’s docker-compose

-

The PEcAn Docker architecture is described in full by the PEcAn docker-compose.yml file. -For full docker-compose syntax, see the official documentation.

-

This section describes the top-level structure and each of the services, which are as follows:

- -

For reference, the complete docker-compose file is as follows:

-
version: '3.2'
-services:
-  traefik:
-    image: traefik:v2.9
-    command:
-    - --log.level=INFO
-    - --api=true
-    - --api.dashboard=true
-    - --entrypoints.web.address=:80
-    - --providers.docker=true
-    - --providers.docker.endpoint=unix:///var/run/docker.sock
-    - --providers.docker.exposedbydefault=false
-    - --providers.docker.watch=true
-    restart: unless-stopped
-    networks: pecan
-    security_opt: no-new-privileges:true
-    ports: ${TRAEFIK_HTTP_PORT-80}:80
-    volumes:
-    - traefik:/config
-    - /var/run/docker.sock:/var/run/docker.sock:ro
-    labels:
-    - traefik.enable=true
-    - traefik.http.routers.traefik.entrypoints=web
-    - traefik.http.routers.traefik.rule=Host(`traefik.pecan.localhost`)
-    - traefik.http.routers.traefik.service=api@internal
-  rabbitmq:
-    image: rabbitmq:3.8-management
-    restart: unless-stopped
-    networks: pecan
-    environment:
-    - RABBITMQ_DEFAULT_USER=${RABBITMQ_DEFAULT_USER:-guest}
-    - RABBITMQ_DEFAULT_PASS=${RABBITMQ_DEFAULT_PASS:-guest}
-    labels:
-    - traefik.enable=true
-    - traefik.http.services.rabbitmq.loadbalancer.server.port=15672
-    - traefik.http.routers.rabbitmq.entrypoints=web
-    - traefik.http.routers.rabbitmq.rule=Host(`rabbitmq.pecan.localhost`)
-    volumes: rabbitmq:/var/lib/rabbitmq
-  postgres:
-    image: mdillon/postgis:9.5
-    restart: unless-stopped
-    networks: pecan
-    volumes: postgres:/var/lib/postgresql/data
-  bety:
-    image: pecan/bety:${BETY_VERSION:-latest}
-    restart: unless-stopped
-    networks: pecan
-    environment:
-    - UNICORN_WORKER_PROCESSES=1
-    - SECRET_KEY_BASE=${BETY_SECRET_KEY:-notasecret}
-    - RAILS_RELATIVE_URL_ROOT=/bety
-    - LOCAL_SERVER=${BETY_LOCAL_SERVER:-99}
-    depends_on: postgres
-    labels:
-    - traefik.enable=true
-    - traefik.http.services.bety.loadbalancer.server.port=8000
-    - traefik.http.routers.bety.rule=Host(`${TRAEFIK_HOST:-pecan.localhost}`) && PathPrefix(`/bety/`)
-  rstudio:
-    image: pecan/base:${PECAN_VERSION:-latest}
-    command: /work/rstudio.sh
-    restart: unless-stopped
-    networks: pecan
-    depends_on:
-    - rabbitmq
-    - postgres
-    environment:
-    - KEEP_ENV=RABBITMQ_URI RABBITMQ_PREFIX RABBITMQ_PORT FQDN NAME
-    - RABBITMQ_URI=${RABBITMQ_URI:-amqp://guest:guest@rabbitmq/%2F}
-    - RABBITMQ_PREFIX=/
-    - RABBITMQ_PORT=15672
-    - FQDN=${PECAN_FQDN:-docker}
-    - NAME=${PECAN_NAME:-docker}
-    - USER=${PECAN_RSTUDIO_USER:-carya}
-    - PASSWORD=${PECAN_RSTUDIO_PASS:-illinois}
-    - USERID=${UID:-1001}
-    - GROUPID=${GID:-1001}
-    volumes:
-    - pecan:/data
-    - rstudio:/home
-    labels:
-    - traefik.enable=true
-    - traefik.http.routers.rstudio.rule=Host(`${TRAEFIK_HOST:-pecan.localhost}`) &&
-      PathPrefix(`/rstudio/`)
-    - traefik.http.routers.rstudio.service=rstudio
-    - traefik.http.routers.rstudio.middlewares=rstudio-stripprefix,rstudio-headers
-    - traefik.http.services.rstudio.loadbalancer.server.port=8787
-    - traefik.http.middlewares.rstudio-headers.headers.customrequestheaders.X-RStudio-Root-Path=/rstudio
-    - traefik.http.middlewares.rstudio-stripprefix.stripprefix.prefixes=/rstudio
-    - traefik.http.routers.rstudio-local.entrypoints=web
-    - traefik.http.routers.rstudio-local.rule=Host(`rstudio.pecan.localhost`)
-    - traefik.http.routers.rstudio-local.service=rstudio-local
-    - traefik.http.services.rstudio-local.loadbalancer.server.port=8787
-  docs:
-    image: pecan/docs:${PECAN_VERSION:-latest}
-    restart: unless-stopped
-    networks: pecan
-    labels:
-    - traefik.enable=true
-    - traefik.http.services.docs.loadbalancer.server.port=80
-    - traefik.http.routers.docs.rule=Host(`${TRAEFIK_HOST:-pecan.localhost}`) && PathPrefix(`/`)
-  pecan:
-    user: ${UID:-1001}:${GID:-1001}
-    image: pecan/web:${PECAN_VERSION:-latest}
-    restart: unless-stopped
-    networks: pecan
-    environment:
-    - RABBITMQ_URI=${RABBITMQ_URI:-amqp://guest:guest@rabbitmq/%2F}
-    - FQDN=${PECAN_FQDN:-docker}
-    - NAME=${PECAN_NAME:-docker}
-    - SECRET_KEY_BASE=${BETY_SECRET_KEY:-thisisnotasecret}
-    depends_on:
-    - postgres
-    - rabbitmq
-    labels:
-    - traefik.enable=true
-    - traefik.http.services.pecan.loadbalancer.server.port=8080
-    - traefik.http.routers.pecan.rule=Host(`${TRAEFIK_HOST:-pecan.localhost}`) &&
-      PathPrefix(`/pecan/`)
-    volumes:
-    - pecan:/data
-    - pecan:/var/www/html/pecan/data
-  monitor:
-    user: ${UID:-1001}:${GID:-1001}
-    image: pecan/monitor:${PECAN_VERSION:-latest}
-    restart: unless-stopped
-    networks: pecan
-    environment:
-    - RABBITMQ_URI=${RABBITMQ_URI:-amqp://guest:guest@rabbitmq/%2F}
-    - FQDN=${PECAN_FQDN:-docker}
-    depends_on: rabbitmq
-    labels:
-    - traefik.enable=true
-    - traefik.http.routers.monitor.rule=Host(`${TRAEFIK_HOST:-pecan.localhost}`) &&
-      PathPrefix(`/monitor/`)
-    - traefik.http.routers.monitor.middlewares=monitor-stripprefix
-    - traefik.http.middlewares.monitor-stripprefix.stripprefix.prefixes=/monitor
-    volumes: pecan:/data
-  executor:
-    user: ${UID:-1001}:${GID:-1001}
-    image: pecan/executor:${PECAN_VERSION:-latest}
-    restart: unless-stopped
-    networks: pecan
-    environment:
-    - RABBITMQ_URI=${RABBITMQ_URI:-amqp://guest:guest@rabbitmq/%2F}
-    - RABBITMQ_PREFIX=/
-    - RABBITMQ_PORT=15672
-    - FQDN=${PECAN_FQDN:-docker}
-    depends_on:
-    - postgres
-    - rabbitmq
-    volumes: pecan:/data
-  basgra:
-    user: ${UID:-1001}:${GID:-1001}
-    image: pecan/model-basgra-basgra_n_v1.0:${PECAN_VERSION:-latest}
-    restart: unless-stopped
-    networks: pecan
-    environment: RABBITMQ_URI=${RABBITMQ_URI:-amqp://guest:guest@rabbitmq/%2F}
-    depends_on: rabbitmq
-    volumes: pecan:/data
-  sipnet:
-    user: ${UID:-1001}:${GID:-1001}
-    image: pecan/model-sipnet-git:${PECAN_VERSION:-latest}
-    restart: unless-stopped
-    networks: pecan
-    environment: RABBITMQ_URI=${RABBITMQ_URI:-amqp://guest:guest@rabbitmq/%2F}
-    depends_on: rabbitmq
-    volumes: pecan:/data
-  ed2:
-    user: ${UID:-1001}:${GID:-1001}
-    image: pecan/model-ed2-2.2.0:${PECAN_VERSION:-latest}
-    restart: unless-stopped
-    networks: pecan
-    environment: RABBITMQ_URI=${RABBITMQ_URI:-amqp://guest:guest@rabbitmq/%2F}
-    depends_on: rabbitmq
-    volumes: pecan:/data
-  maespa:
-    user: ${UID:-1001}:${GID:-1001}
-    image: pecan/model-maespa-git:${PECAN_VERSION:-latest}
-    restart: unless-stopped
-    networks: pecan
-    environment: RABBITMQ_URI=${RABBITMQ_URI:-amqp://guest:guest@rabbitmq/%2F}
-    depends_on: rabbitmq
-    volumes: pecan:/data
-  biocro:
-    user: ${UID:-1001}:${GID:-1001}
-    image: pecan/model-biocro-0.95:${PECAN_VERSION:-latest}
-    restart: unless-stopped
-    networks: pecan
-    environment: RABBITMQ_URI=${RABBITMQ_URI:-amqp://guest:guest@rabbitmq/%2F}
-    depends_on: rabbitmq
-    volumes: pecan:/data
-  dbsync:
-    image: pecan/shiny-dbsync:${PECAN_VERSION:-latest}
-    restart: unless-stopped
-    networks: pecan
-    depends_on: postgres
-    labels:
-    - traefik.enable=true
-    - traefik.http.routers.dbsync.rule=Host(`${TRAEFIK_HOST:-pecan.localhost}`) &&
-      PathPrefix(`/dbsync/`)
-    - traefik.http.routers.dbsync.middlewares=dbsync-stripprefix
-    - traefik.http.middlewares.dbsync-stripprefix.stripprefix.prefixes=/monitor
-  api:
-    user: ${UID:-1001}:${GID:-1001}
-    image: pecan/api:${PECAN_VERSION:-latest}
-    restart: unless-stopped
-    networks: pecan
-    environment:
-    - PGHOST=${PGHOST:-postgres}
-    - HOST_ONLY=${HOST_ONLY:-FALSE}
-    - AUTH_REQ=${AUTH_REQ:-FALSE}
-    - RABBITMQ_URI=${RABBITMQ_URI:-amqp://guest:guest@rabbitmq/%2F}
-    - DATA_DIR=${DATA_DIR:-/data/}
-    - DBFILES_DIR=${DBFILES_DIR:-/data/dbfiles/}
-    - SECRET_KEY_BASE=${BETY_SECRET_KEY:-thisisnotasecret}
-    labels:
-    - traefik.enable=true
-    - traefik.http.routers.api.rule=Host(`${TRAEFIK_HOST:-pecan.localhost}`) && PathPrefix(`/api/`)
-    - traefik.http.services.api.loadbalancer.server.port=8000
-    depends_on: postgres
-    volumes: pecan:/data/
-networks:
-  pecan: ~
-volumes:
-  traefik: ~
-  postgres: ~
-  rabbitmq: ~
-  pecan: ~
-  rstudio: ~
-

There are two ways you can override different values in the docker-compose.yml file. The first method is to create a file called .env that is placed in the same folder as the docker-compose.yml file. This file can override some of configuration variables used by docker-compose. For example the following is an example of the env file

-
# This file will override the configuration options in the docker-compose
-# file. Copy this file to the same folder as docker-compose as .env
-
-# ----------------------------------------------------------------------
-# GENERAL CONFIGURATION
-# ----------------------------------------------------------------------
-
-# project name (-p flag for docker-compose)
-#COMPOSE_PROJECT_NAME=pecan
-
-# ----------------------------------------------------------------------
-# TRAEFIK CONFIGURATION
-# ----------------------------------------------------------------------
-
-# hostname of server
-#TRAEFIK_HOST=pecan-docker.ncsa.illinois.edu
-
-# Run traffik on port 80 (http) and port 443 (https)
-#TRAEFIK_HTTP_PORT=80
-#TRAEFIK_HTTPS_PORT=443
-
-# Use you real email address here to be notified if cert expires
-#TRAEFIK_ACME_EMAIL=pecanproj@gmail.com
-
-# ----------------------------------------------------------------------
-# PEcAn CONFIGURATION
-# ----------------------------------------------------------------------
-
-# what version of pecan to use
-#PECAN_VERSION=develop
-
-# the fully qualified hostname used for this server
-#PECAN_FQDN=pecan-docker.ncsa.illinois.edu
-
-# short name shown in the menu
-#PECAN_NAME=pecan-docker
-
-# ----------------------------------------------------------------------
-# BETY CONFIGURATION
-# ----------------------------------------------------------------------
-
-# what version of BETY to use
-#BETY_VERSION=develop
-
-# what is our server number, 99=vm, 98=docker
-#BETY_LOCAL_SERVER=98
-
-# secret used to encrypt cookies in BETY
-#BETY_SECRET_KEY=1208q7493e8wfhdsohfo9ewhrfiouaho908ruq30oiewfdjspadosuf08q345uwrasdy98t7q243
-
-# ----------------------------------------------------------------------
-# MINIO CONFIGURATION
-# ----------------------------------------------------------------------
-
-# minio username and password
-#MINIO_ACCESS_KEY=carya
-#MINIO_SECRET_KEY=illinois
-
-# ----------------------------------------------------------------------
-# PORTAINER CONFIGURATION
-# ----------------------------------------------------------------------
-
-# password for portainer admin account
-# use docker run --rm httpd:2.4-alpine htpasswd -nbB admin <password> | cut -d ":" -f 2
-#PORTAINER_PASSWORD=$2y$05$5meDPBtS3NNxyGhBpYceVOxmFhiiC3uY5KEy2m0YRbWghhBr2EVn2
-
-# ----------------------------------------------------------------------
-# RABBITMQ CONFIGURATION
-# ----------------------------------------------------------------------
-
-# RabbitMQ username and password
-#RABBITMQ_DEFAULT_USER=carya
-#RABBITMQ_DEFAULT_PASS=illinois
-
-# create the correct URI with above username and password
-#RABBITMQ_URI=amqp://carya:illinois@rabbitmq/%2F
-
-# ----------------------------------------------------------------------
-# RSTUDIO CONFIGURATION
-# ----------------------------------------------------------------------
-
-# Default RStudio username and password for startup of container
-#PECAN_RSTUDIO_USER=carya
-#PECAN_RSTUDIO_PASS=illinois
-

You can also extend the docker-compose.yml file with a docker-compose.override.yml file (in the same directory), allowing you to add more services, or for example to change where the volumes are stored (see official documentation). For example the following will change the volume for postgres to be stored in your home directory:

-
version: "3"
-
-volumes:
-  postgres:
-    driver_opts:
-      type: none
-      device: ${HOME}/postgres
-      o: bind
-
-
-

25.4.3 Top-level structure

-

The root of the docker-compose.yml file contains three sections:

-
    -
  • services – This is a list of services provided by the application, with each service corresponding to a container. -When communicating with each other internally, the hostnames of containers correspond to their names in this section. -For instance, regardless of the “project” name passed to docker-compose up, the hostname for connecting to the PostgreSQL database of any given container is always going to be postgres (e.g. you should be able to access the PostgreSQL database by calling the following from inside the container: psql -d bety -U bety -h postgres). -The services comprising the PEcAn application are described below.

  • -
  • networks – This is a list of networks used by the application. -Containers can only communicate with each other (via ports and hostnames) if they are on the same Docker network, and containers on different networks can only communicate through ports exposed by the host machine. -We just provide the network name (pecan) and resort to Docker’s default network configuration. -Note that the services we want connected to this network include a networks: ... - pecan tag. -For more details on Docker networks, see the official documentation.

  • -
  • volumes – Similarly to networks, this just contains a list of volume names we want. -Briefly, in Docker, volumes are directories containing files that are meant to be shared across containers. -Each volume corresponds to a directory, which can be mounted at a specific location by different containers. -For example, syntax like volumes: ... - pecan:/data in a service definition means to mount the pecan “volume” (including its contents) in the /data directory of that container. -Volumes also allow data to persist on containers between restarts, as normally, any data created by a container during its execution is lost when the container is re-launched. -For example, using a volume for the database allows data to be saved between different runs of the database container. -Without volumes, we would start with a blank database every time we restart the containers. -For more details on Docker volumes, see the official documentation. -Here, we define three volumes:

    -
      -
    • postgres – This contains the data files underlying the PEcAn PostgreSQL database (BETY). -Notice that it is mounted by the postgres container to /var/lib/postgresql/data. -This is the data that we pre-populate when we run the Docker commands to initialize the PEcAn database. -Note that these are the values stored directly in the PostgreSQL database. -The default files to which the database points (i.e. dbfiles) are stored in the pecan volume, described below.

    • -
    • rabbitmq – This volume contains persistent data for RabbitMQ. -It is only used by the rabbitmq service.

    • -
    • pecan – This volume contains PEcAn’s dbfiles, which include downloaded and converted model inputs, processed configuration files, and outputs. -It is used by almost all of the services in the PEcAn stack, and is typically mounted to /data.

    • -
  • -
-
-
-

25.4.4 traefik

-

Traefik manages communication among the different PEcAn services and between PEcAn and the web. -Among other things, traefik facilitates the setup of web access to each PEcAn service via common and easy-to-remember URLs. -For instance, the following lines in the web service configure access to the PEcAn web interface via the URL http://pecan.localhost/pecan/ :

-
~
-

(Further details in the works…)

-

The traefik service configuration looks like this:

-
traefik:
-  image: traefik:v2.9
-  command:
-  - --log.level=INFO
-  - --api=true
-  - --api.dashboard=true
-  - --entrypoints.web.address=:80
-  - --providers.docker=true
-  - --providers.docker.endpoint=unix:///var/run/docker.sock
-  - --providers.docker.exposedbydefault=false
-  - --providers.docker.watch=true
-  restart: unless-stopped
-  networks: pecan
-  security_opt: no-new-privileges:true
-  ports: ${TRAEFIK_HTTP_PORT-80}:80
-  volumes:
-  - traefik:/config
-  - /var/run/docker.sock:/var/run/docker.sock:ro
-  labels:
-  - traefik.enable=true
-  - traefik.http.routers.traefik.entrypoints=web
-  - traefik.http.routers.traefik.rule=Host(`traefik.pecan.localhost`)
-  - traefik.http.routers.traefik.service=api@internal
-
-
-

25.4.5 portainer

-

portainer is lightweight management UI that allows you to manage the docker host (or swarm). You can use this service to monitor the different containers, see the logfiles, and start and stop containers.

-

The portainer service configuration looks like this:

-
NA: ~
-

Portainer is accessible by browsing to pecan.localhost/portainer/. You can either set the password in the .env file (for an example see env.example) or you can use the web browser and go to the portainer url. If this is the first time it will ask for your password.

-
-
-

25.4.6 minio

-

Minio is a service that provides access to the a folder on disk through a variety of protocols, including S3 buckets and web-based access. -We mainly use Minio to facilitate access to PEcAn data using a web browser without the need for CLI tools.

-

Our current configuration is as follows:

-
NA: ~
-

The Minio interface is accessible by browsing to minio.pecan.localhost. -From there, you can browse directories and download files. -You can also upload files by clicking the red “+” in the bottom-right corner.

-

Note that it is currently impossible to create or upload directories using the Minio interface (except in the /data root directory – those folders are called “buckets” in Minio). -Therefore, the recommended way to perform any file management tasks other than individual file uploads is through the command line, e.g.

-
docker run -it --rm --volumes pecan_pecan:/data --volumes /path/to/local/directory:/localdir ubuntu
-
-# Now, you can move files between `/data` and `/localdir`, create new directories, etc.
-
-
-

25.4.7 thredds

-

This service allows PEcAn model outputs to be accessible via the THREDDS data server (TDS). -When the PEcAn stack is running, the catalog can be explored in a web browser at http://pecan.localhost/thredds/catalog.html. -Specific output files can also be accessed from the command line via commands like the following:

-

Note that everything after outputs/ exactly matches the directory structure of the workflows directory.

-

Which files are served, which subsetting services are available, and other aspects of the data server’s behavior are configured in the docker/thredds_catalog.xml file. -Specifically, this XML tells the data server to use the datasetScan tool to serve all files within the /data/workflows directory, with the additional filter that only files ending in .nc are served. -For additional information about the syntax of this file, see the extensive THREDDS documentation.

-

Our current configuration is as follows:

-
NA: ~
-
-
-

25.4.8 postgres

-

This service provides a working PostGIS database. -Our configuration is fairly straightforward:

-
postgres:
-  image: mdillon/postgis:9.5
-  restart: unless-stopped
-  networks: pecan
-  volumes: postgres:/var/lib/postgresql/data
-

Some additional details about our configuration:

-
    -
  • image – This pulls a container with PostgreSQL + PostGIS pre-installed. -Note that by default, we use PostgreSQL version 9.5. -To experiment with other versions, you can change 9.5 accordingly.

  • -
  • networks – This allows PostgreSQL to communicate with other containers on the pecan network. -As mentioned above, the hostname of this service is just its name, i.e. postgres, so to connect to the database from inside a running container, use a command like the following: psql -d bety -U bety -h postgres

  • -
  • volumes – Note that the PostgreSQL data files (which store the values in the SQL database) are stored on a volume called postgres (which is not the same as the postgres service, even though they share the same name).

  • -
-
-
-

25.4.9 rabbitmq

-

RabbitMQ is a message broker service. -In PEcAn, RabbitMQ functions as a task manager and scheduler, coordinating the execution of different tasks (such as running models and analyzing results) associated with the PEcAn workflow.

-

Our configuration is as follows:

-
rabbitmq:
-  image: rabbitmq:3.8-management
-  restart: unless-stopped
-  networks: pecan
-  environment:
-  - RABBITMQ_DEFAULT_USER=${RABBITMQ_DEFAULT_USER:-guest}
-  - RABBITMQ_DEFAULT_PASS=${RABBITMQ_DEFAULT_PASS:-guest}
-  labels:
-  - traefik.enable=true
-  - traefik.http.services.rabbitmq.loadbalancer.server.port=15672
-  - traefik.http.routers.rabbitmq.entrypoints=web
-  - traefik.http.routers.rabbitmq.rule=Host(`rabbitmq.pecan.localhost`)
-  volumes: rabbitmq:/var/lib/rabbitmq
-

Note that the traefik.http.routers.rabbitmq.rule indicates that browsing to http://rabbitmq.pecan.localhost/ leads to the RabbitMQ management console.

-

By default, the RabbitMQ management console has username/password guest/guest, which is highly insecure. -For production instances of PEcAn, we highly recommend changing these credentials to something more secure, and removing access to the RabbitMQ management console via Traefik.

-
-
-

25.4.10 bety

-

This service operates the BETY web interface, which is effectively a web-based front-end to the PostgreSQL database. -Unlike the postgres service, which contains all the data needed to run PEcAn models, this service is not essential to the PEcAn workflow. -However, note that certain features of the PEcAn web interface do link to the BETY web interface and will not work if this container is not running.

-

Our configuration is as follows:

-
bety:
-  image: pecan/bety:${BETY_VERSION:-latest}
-  restart: unless-stopped
-  networks: pecan
-  environment:
-  - UNICORN_WORKER_PROCESSES=1
-  - SECRET_KEY_BASE=${BETY_SECRET_KEY:-notasecret}
-  - RAILS_RELATIVE_URL_ROOT=/bety
-  - LOCAL_SERVER=${BETY_LOCAL_SERVER:-99}
-  depends_on: postgres
-  labels:
-  - traefik.enable=true
-  - traefik.http.services.bety.loadbalancer.server.port=8000
-  - traefik.http.routers.bety.rule=Host(`${TRAEFIK_HOST:-pecan.localhost}`) && PathPrefix(`/bety/`)
-

The BETY container Dockerfile is located in the root directory of the BETY GitHub repository (direct link).

-
-
-

25.4.11 docs

-

This service will show the documentation for the version of PEcAn running as well as a homepage with links to all relevant endpoints. You can access this at http://pecan.localhost/. You can find the documentation for PEcAn at http://pecan.localhost/docs/pecan/.

-

Our current configuration is as follows:

-
docs:
-  image: pecan/docs:${PECAN_VERSION:-latest}
-  restart: unless-stopped
-  networks: pecan
-  labels:
-  - traefik.enable=true
-  - traefik.http.services.docs.loadbalancer.server.port=80
-  - traefik.http.routers.docs.rule=Host(`${TRAEFIK_HOST:-pecan.localhost}`) && PathPrefix(`/`)
-
-
-

25.4.12 web

-

This service runs the PEcAn web interface. -It is effectively a thin wrapper around a standard Apache web server container from Docker Hub that installs some additional dependencies and copies over the necessary files from the PEcAn source code.

-

Our configuration is as follows:

-
NA: ~
-

Its Dockerfile ships with the PEcAn source code, in docker/web/Dockerfile.

-

In terms of actively developing PEcAn using Docker, this is the service to modify when making changes to the web interface (i.e. PHP, HTML, and JavaScript code located in the PEcAn web directory).

-
-
-

25.4.13 executor

-

This service is in charge of running the R code underlying the core PEcAn workflow. -However, it is not in charge of executing the models themselves – model binaries are located on their own dedicated Docker containers, and model execution is coordinated by RabbitMQ.

-

Our configuration is as follows:

-
executor:
-  user: ${UID:-1001}:${GID:-1001}
-  image: pecan/executor:${PECAN_VERSION:-latest}
-  restart: unless-stopped
-  networks: pecan
-  environment:
-  - RABBITMQ_URI=${RABBITMQ_URI:-amqp://guest:guest@rabbitmq/%2F}
-  - RABBITMQ_PREFIX=/
-  - RABBITMQ_PORT=15672
-  - FQDN=${PECAN_FQDN:-docker}
-  depends_on:
-  - postgres
-  - rabbitmq
-  volumes: pecan:/data
-

Its Dockerfile is ships with the PEcAn source code, in docker/executor/Dockerfile. -Its image is built on top of the pecan/base image (docker/base/Dockerfile), which contains the actual PEcAn source. -To facilitate caching, the pecan/base image is itself built on top of the pecan/depends image (docker/depends/Dockerfile), a large image that contains an R installation and PEcAn’s many system and R package dependencies (which usually take ~30 minutes or longer to install from scratch).

-

In terms of actively developing PEcAn using Docker, this is the service to modify when making changes to the PEcAn R source code. -Note that, unlike changes to the web image’s PHP code, changes to the R source code do not immediately propagate to the PEcAn container; instead, you have to re-compile the code by running make inside the container.

-
-
-

25.4.14 monitor

-

This service will show all models that are currently running http://pecan.localhost/monitor/. This list returned is JSON and shows all models (grouped by type and version) that are currently running, or where seen in the past. This list will also contain a list of all current active containers, as well as how many jobs are waiting to be processed.

-

This service is also responsible for registering any new models with PEcAn so users can select it and execute the model from the web interface.

-

Our current configuration is as follows:

-
monitor:
-  user: ${UID:-1001}:${GID:-1001}
-  image: pecan/monitor:${PECAN_VERSION:-latest}
-  restart: unless-stopped
-  networks: pecan
-  environment:
-  - RABBITMQ_URI=${RABBITMQ_URI:-amqp://guest:guest@rabbitmq/%2F}
-  - FQDN=${PECAN_FQDN:-docker}
-  depends_on: rabbitmq
-  labels:
-  - traefik.enable=true
-  - traefik.http.routers.monitor.rule=Host(`${TRAEFIK_HOST:-pecan.localhost}`) &&
-    PathPrefix(`/monitor/`)
-  - traefik.http.routers.monitor.middlewares=monitor-stripprefix
-  - traefik.http.middlewares.monitor-stripprefix.stripprefix.prefixes=/monitor
-  volumes: pecan:/data
-
-
-

25.4.15 Model-specific containers

-

Additional models are added as additional services. -In general, their configuration should be similar to the following configuration for SIPNET, which ships with PEcAn:

-
sipnet:
-  user: ${UID:-1001}:${GID:-1001}
-  image: pecan/model-sipnet-git:${PECAN_VERSION:-latest}
-  restart: unless-stopped
-  networks: pecan
-  environment: RABBITMQ_URI=${RABBITMQ_URI:-amqp://guest:guest@rabbitmq/%2F}
-  depends_on: rabbitmq
-  volumes: pecan:/data
-

The PEcAn source contains Dockerfiles for ED2 (models/ed/Dockerfile) and SIPNET (models/sipnet/Dockerfile) that can serve as references. -For additional tips on constructing a Dockerfile for your model, see Dockerfiles for Models.

- -
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/pecan-git.html b/master/pecan-git.html deleted file mode 100644 index 39e9f232f..000000000 --- a/master/pecan-git.html +++ /dev/null @@ -1,1261 +0,0 @@ - - - - - - - 8.2 Git and GitHub Workflow | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

8.2 Git and GitHub Workflow

-

Using Git

- -
-

8.2.1 Using Git

-

This document describes the steps required to download PEcAn, make changes to code, and submit your changes.

-
    -
  • If you are new to GitHub or to PEcAn, start with the one-time set-up instructions under Before any work is done. Also see the excellent tutorials and references in the Git) section right below this list and at the bootom in References.
  • -
  • To make trivial changes, see [Quick and Easy].
  • -
  • To make a few changes to the code, start with the [Basic Workflow].
  • -
  • To make substantial changes and/or if plan to contribute over time see [Recommended Workflow: A new branch for each change].
  • -
-
-

8.2.1.1 Git

-

Git is a free & open source, distributed version control system designed -to handle everything from small to very large projects with speed and -efficiency. Every Git clone is a full-fledged repository with complete -history and full revision tracking capabilities, not dependent on -network access or a central server. Branching and merging are fast and -easy to do.

-

A good place to start is the GitHub 5 minute illustrated tutorial. -In addition, there are three fun tutorials for learning git:

- -

URLs In the rest of the document will use specific URL’s to clone the code. -There a few URL’s you can use to clone a project, using https, ssh and -git. You can use either https or git to clone a repository and write to -it. The git protocol is read-only. -This document describes the steps required to download PEcAn, make changes to code, and submit your changes.

-

If during above process you want to work on something else, commit all -your code, create a new branch, and work on new branch.

-
-
-

8.2.1.2 PEcAn Project and Github

- -

These instructions apply to other repositories too.

-
-
-

8.2.1.3 PEcAn Project Branches

-

We follow branch organization laid out on this page.

-

In short, there are three main branches you must be aware of:

-
    -
  • develop - Main Branch containing the latest code. This is the main branch you will make changes to.
  • -
  • master - Branch containing the latest stable code. DO NOT MAKE CHANGES TO THIS BRANCH.
  • -
  • release/vX.X.X - Named branches containing code specific to a release. Only make changes to this branch if you are fixing a bug on a release branch.
  • -
-
-
-

8.2.1.4 Milestones, Issues, Tasks

-

The Milestones, issues, and tasks can be used to organize specific features or research projects. In general, there is a heirarchy:

-
    -
  • milestones (Big picture, “Epic”): contains many issues, organized by release.
  • -
  • issues (Specific features / bugs, “Story”): may contain a list of tasks; represent
  • -
  • task list (to do list, “Tasks”): list of steps required to close an issue, e.g.:
  • -
- - - - - - - - - - - - -
* [ ] first do this
* [ ] then this
* [ ] completed when x and y
-
-
-

8.2.1.5 Editing files on GitHub

-

The easiest approach is to use GitHub’s browser based workflow. This is useful when your change is a few lines, if you are editing a wiki, or if the edit is trivial (and won’t break the code). The GitHub documentation is here but it is simple: finding the page or file you want to edit, click “edit” and then the GitHub web application will automatically forking and branch, then allow you to submit a pull request. However, it should be noted that unless you are a member of the PEcAn project that the “edit” button will not be active and you’ll want to follow the workflow described below for forking and then submitting a pull request.

-
-
- -
-

8.2.3 Useful Git tools

-
-

8.2.3.1 GitHub Desktop

-

The easiest way to get working with GitHub is by installing the GitHub -client. For instructions for your specific OS and download of the -GitHub client, see https://help.github.com/articles/set-up-git. -This will help you set up an SSH key to push code back to GitHub. To -check out a project you do not need to have an ssh key and you can use -the https or git url to check out the code.

-
-
-

8.2.3.2 Git + Rstudio

-

Rstudio is nicely integrated with many development tools, including git and GitHub. -It is quite easy to check out source code from within the Rstudio program or browser. -The Rstudio documentation includes useful overviews of version control -and R package development.

-

Once you have git installed on your computer (see the Rstudio version control documentation for instructions), you can use the following steps to install the PEcAn source code in Rstudio.

-
-
-
-

8.2.4 Advanced

-
-

8.2.4.1 Fixing a release Branch

-

If you would like to make changes to a release branch, you must follow a different workflow, as the release branch will not contain the latest code on develop and must remain seperate.

-
    -
  1. Fetch upstream remote branches
  2. -
-

git fetch upstream

-
    -
  1. Checkout the correct release branch
  2. -
-

git checkout -b release/vX.Y.Z

-
    -
  1. Compile Code with make
  2. -
-

make

-
    -
  1. Make changes and commit them
  2. -
-

git add <changed_file.R> -git commit -m "Describe changes"

-
    -
  1. Compile and make roxygen changes -make -make document

  2. -
  3. Commit and push any files that were changed by make document

  4. -
  5. Make a pull request. It is essential that you compare your pull request to the remote release branch, NOT the develop branch.

  6. -
-
-
-

8.2.4.2 Tags

-

Git supports two types of tags: lightweight and annotated. For more information see the Tagging Chapter in the Git documentation.

-

Lightweight tags are useful, but here we discuss the annotated tags that are used for marking stable versions, major releases, and versions associated with published results.

-

The basic command is git tag. The -a flag means ‘annotated’ and -m is used before a message. Here is an example:

-

git tag -a v0.6 -m "stable version with foo and bar features, used in the foobar publication by Bob"

-

Adding a tag to the a remote repository must be done explicitly with a push, e.g.

-

git push v0.6

-

To use a tagged version, just checkout:

-

git checkout v0.6

-

To tag an earlier commit, just append the commit SHA to the command, e.g. 

-

git tag -a v0.99 -m "last version before 1.0" 9fceb02

-
-
-
-

8.2.5 References

-
-

8.2.5.1 Git Documentation

- -
-
-

8.2.5.2 GitHub Documentation

-

When in doubt, the first step is to click the “Help” button at the top of the page.

- - -
-
-
-

8.2.6 GitHub use with PEcAn

-

In this section, development topics are introduced and discussed. PEcAn code lives within the If you are looking for an issue to work on, take a look through issues labled “good first issue”. To get started you will want to review

-

We use GitHub to track development.

-

To learn about GitHub, it is worth taking some time to read through the FAQ. When in doubt, the first step is to click the “Help” button at the top of the page.

-
    -
  • To address specific people, use a github feature called @mentions e.g. write @dlebauer, @robkooper, @mdietze, or @serbinsh … in the issue to alert the user as described in the GitHub documentation on notifications
  • -
-
-

8.2.6.1 Bugs, Issues, Features, etc.

-
-
-

8.2.6.2 Reporting a bug

-
    -
  1. (For developers) work through debugging.
  2. -
  3. Once you have identified a problem, that you can not resolve, you can write a bug report
  4. -
  5. Write a bug report
  6. -
  7. submit the bug report
  8. -
  9. If you do find the answer, explain the resolution (in the issue) and close the issue
  10. -
-
-
-

8.2.6.3 Required content

-

Note:

-
    -
  • a bug is only a bug if it is reproducible
  • -
  • clear bug reports save time
  • -
-
    -
  1. Clear, specific title
  2. -
  3. Description -
  4. -
-
    -
  • What you did
  • -
  • What you expected to happen
  • -
  • What actually happened
  • -
  • What does work, under what conditions does it fail?
  • -
  • Reproduction steps - minimum steps required to reproduce the bug
  • -
-
    -
  1. additional materials that could help identify the cause:
  2. -
-
    -
  • screen shots
  • -
  • stack traces, logs, scripts, output
  • -
  • specific code and data / settings / configuration files required to reproduce the bug
  • -
  • environment (operating system, browser, hardware)
  • -
-
-
-

8.2.6.4 Requesting a feature

-

(from The Pragmatic Programmer, available as -ebook -through UI libraries, hardcopy on David’s bookshelf)
-

-
    -
  • focus on “user stories”, e.g. specific use cases

  • -
  • Be as specific as possible,

  • -
  • Here is an example:

  • -
-
    -
  1. Bob is at www.mysite.edu/maps
  2. -
  3. map of the the region (based on user location, e.g. US, Asia, etc)
  4. -
  5. option to “use current location” is provided, if clicked, map zooms in to, e.g. state or county level
  6. -
  7. for site run: -
      -
    1. option to select existing site or specify point by lat/lon
    2. -
    3. option to specify a bounding box and grid resolution in -either lat/lon or polar stereographic.
    4. -
  8. -
  9. asked to specify start and end times in terms of year, month, day, hour, minute. Time is recorded in UTC not local time, this should be indicated.
  10. -
-
-
-

8.2.6.5 Closing an issue

-
    -
  1. Definition of “Done”
  2. -
-
    -
  • test
  • -
  • documentation
  • -
-
    -
  1. when issue is resolved:
  2. -
-
    -
  • status is changed to “resolved”
  • -
  • assignee is changed to original author
  • -
-
    -
  1. if original author agrees that issue has been resolved
  2. -
-
    -
  • original author changes status to “closed”
  • -
-
    -
  1. except for trivial issues, issues are only closed by the author
  2. -
-
-
-

8.2.6.6 When to submit an issue?

-

Ideally, non-trivial code changes will be linked to an issue and a commit.

-

This requires creating issues for each task, making small commits, and referencing the issue within your commit message. Issues can be created on GitHub. These issues can be linked to commits by adding text such as fixes gh-5).

-

Rationale: This workflow is a small upfront investment that reduces error and time spent re-creating and debugging errors. Associating issues and commits, makes it easier to identify why a change was made, and potential bugs that could arise when the code is changed. In addition, knowing which issue you are working on clarifies the scope and objectives of your current task.

- -
-
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/pecan-in-a-nutshell.html b/master/pecan-in-a-nutshell.html deleted file mode 100644 index d3c509343..000000000 --- a/master/pecan-in-a-nutshell.html +++ /dev/null @@ -1,863 +0,0 @@ - - - - - - - 5.1 How PEcAn Works in a nutshell | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

5.1 How PEcAn Works in a nutshell

-

PEcAn provides an interface to a variety of ecosystem models and attempts to standardize and automate the processes of model parameterization, execution, and analysis. First, you choose an ecosystem model, then the time and location of interest (a site), the plant community (or crop) that you are interested in simulating, and a source of atmospheric data from the BETY database (LeBauer et al, 2010). These are set in a “settings” file, commonly named pecan.xml which can be edited manually if desired. From here, PEcAn will take over and set up and execute the selected model using your settings. The key is that PEcAn uses models as-is, and all of the translation steps are done within PEcAn so no modifications are required of the model itself. Once the model is finished it will allow you to create graphs with the results of the simulation as well as download the results. It is also possible to see all past experiments and simulations.

-

There are two ways of using PEcAn, via the web interface and directly within R. Even for users familiar with R, using the web interface is a good place to start because it provides a high level overview of the PEcAn workflow. The quickest way to get started is to download the virtual machine or use an AWS instance.

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/pecan-manual-setup.html b/master/pecan-manual-setup.html deleted file mode 100644 index 333dcd041..000000000 --- a/master/pecan-manual-setup.html +++ /dev/null @@ -1,870 +0,0 @@ - - - - - - - 4 Install PEcAn | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

4 Install PEcAn

-

These instructions are provided to document how to install and setup PEcAn. It includes:

- -

The PEcAn code and necessary infrastructure can be obtained and compiled in different ways. -This set of instructions will help facilitate your path and the steps necessary to move forward to have a fully a functioning PEcAn environment.

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/pecan-models.html b/master/pecan-models.html deleted file mode 100644 index 173088ebb..000000000 --- a/master/pecan-models.html +++ /dev/null @@ -1,1022 +0,0 @@ - - - - - - - 14 PEcAn Models | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

14 PEcAn Models

-

This section will contain information about all models and output variables that are supported by PEcAn.

- ------- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Model NameAvailable in the VMPrescribed InputsInput Functions/ValuesRestart Function
BioCroYesYesYesNo
CLMNoNoNoNo
DALECYesYesYesNo
ED2YesYesYesYes
FATESNoYesNo
GDAYNoNoNoNo
LDNDCNoYesNoNo
LINKAGESYesYesYesYes
LPJ-GUESSNoYesNoNo
MAESPAYesYesNoNo
PRELESYesYesPartiallyNo
SiPNETYesYesYesYes
STICSYesYesNoNo
-

Available in the VM - Denotes if a model is publicly available with PEcAn.

-

Prescribed Inputs - Denotes whether or not PEcAn can prescribe inputs.

-

Input Functions/Values - Denotes whether or not PEcAn has functions to fully produce a model’s Input values.

-

Restart Function - Denotes status of model data assimilation capabilities.

-

Output Variables

-

PEcAn converts all model outputs to a single Output Standards. This standard evolved out of MsTMIP project, which is itself based on NACP, LBA, and other model-intercomparison projects. This standard was expanded for the PalEON MIP and the needs of the PEcAn modeling community to support variables not in these standards.

-

Model developers: do not add variables to your PEcAn output without first adding them to the PEcAn standard table! Also, do not create new variables equivalent to existing variables but just with different names or units.

- - - -
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/pecan-project-api.html b/master/pecan-project-api.html deleted file mode 100644 index 6c799c960..000000000 --- a/master/pecan-project-api.html +++ /dev/null @@ -1,861 +0,0 @@ - - - - - - - 16 PEcAn Project API | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

16 PEcAn Project API

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/pecan-project-used-in-courses.html b/master/pecan-project-used-in-courses.html deleted file mode 100644 index 2c4b6d07e..000000000 --- a/master/pecan-project-used-in-courses.html +++ /dev/null @@ -1,861 +0,0 @@ - - - - - - - 30 PEcAn Project Used in Courses | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

30 PEcAn Project Used in Courses

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/pecan-remote.html b/master/pecan-remote.html deleted file mode 100644 index 256c297ee..000000000 --- a/master/pecan-remote.html +++ /dev/null @@ -1,886 +0,0 @@ - - - - - - - 26 Remote execution with PEcAn | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

26 Remote execution with PEcAn

-

Remote execution allows the user to leverage the power and storage of high performance computing clusters, AWS instances, or specially configured virtual machines, but without leaving their local working environment. -PEcAn uses remote execution primarily to run ecosystem models.

-

The infrastructure for remote execution lives in the PEcAn.remote package (base/remote in the PEcAn repository).

-

This section describes the following:

-
    -
  1. Checking capabilities to connect to the remote machine correctly:
  2. -
-
    -
  • Basics of command line SSH
  • -
  • SSH authentication with keys and passwords
  • -
  • Basics of SSH tunnels, and how they are used in PEcAn
  • -
-
    -
  1. Description of PEcAn related tools that control remote execution
  2. -
-
    -
  • Basic remote execution R functions in PEcAn.remote
  • -
-
    -
  1. SETUP- Configuration Files and settings
  2. -
-
    -
  • Remote model execution configuration in the pecan.xml and config.php
  • -
  • Additional information about preparing remote servers for execution
  • -
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/pecan-standards.html b/master/pecan-standards.html deleted file mode 100644 index a23b237fe..000000000 --- a/master/pecan-standards.html +++ /dev/null @@ -1,861 +0,0 @@ - - - - - - - 11 PEcAn standard formats | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

11 PEcAn standard formats

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/pecanXML.html b/master/pecanXML.html deleted file mode 100644 index a4d4e0d7b..000000000 --- a/master/pecanXML.html +++ /dev/null @@ -1,966 +0,0 @@ - - - - - - - 12 The PEcAn XML | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

12 The PEcAn XML

-

The PEcAn system is configured using a XML file, often called pecan.xml. -It contains the following major sections (“nodes”):

- -

A basic example looks like this:

-
<?xml version="1.0" encoding="UTF-8"?>
-<pecan>
-  <info>
-    <notes>Example run</notes>
-    <userid>-1</userid>
-    <username>guestuser</username>
-    <date>2018/09/18 19:12:28 +0000</date>
-  </info>
-  <outdir>/data/workflows/PEcAn_99000000006</outdir>
-  <database>
-    <bety>
-      <user>bety</user>
-      <password>bety</password>
-      <host>postgres</host>
-      <dbname>bety</dbname>
-      <driver>PostgreSQL</driver>
-      <write>true</write>
-    </bety>
-    <dbfiles>/data/dbfiles</dbfiles>
-  </database>
-  <pfts>
-    <pft>
-      <name>tundra.grasses</name> 
-      <constants>
-        <num>1</num>
-      </constants>
-    </pft>
-  </pfts>
-  <meta.analysis>
-    <iter>3000</iter>
-    <random.effects>
-     <on>FALSE</on>
-     <use_ghs>TRUE</use_ghs>
-    </random.effects>
-  </meta.analysis>
-  <ensemble>
-   <size>1</size>
-   <variable>NPP</variable>
-   <samplingspace>
-   <parameters>
-    <method>uniform</method>
-   </parameters>
-   <met>
-    <method>sampling</method>
-    </met>
-   </samplingspace>
-  </ensemble>
-  <model>
-    <id>5000000002</id>
-  </model>
-  <workflow>
-    <id>99000000006</id>
-  </workflow>
-  <run>
-    <site>
-      <id>1000000098</id>
-      <met.start>2004/01/01</met.start>
-      <met.end>2004/12/31</met.end>
-    </site>
-    <inputs>
-      <met>
-        <source>CRUNCEP</source>
-        <output>SIPNET</output>
-      </met>
-    </inputs>
-    <start.date>2004/01/01</start.date>
-    <end.date>2004/12/31</end.date>
-  </run>
-  <host>
-    <name>localhost</name>
-    <rabbitmq>
-      <uri>amqp://guest:guest@rabbitmq:5672/%2F</uri>
-      <queue>SIPNET_136</queue>
-    </rabbitmq>
-  </host>
-</pecan>
-

In the following sections, we step through each of these sections in detail.

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/pecanvm.html b/master/pecanvm.html deleted file mode 100644 index 2d962dcb5..000000000 --- a/master/pecanvm.html +++ /dev/null @@ -1,896 +0,0 @@ - - - - - - - 24.1 PEcAn Virtual Machine | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

24.1 PEcAn Virtual Machine

-

See also other VM related documentation sections:

- -

The PEcAn virtual machine consists of all of PEcAn pre-compiled within a Linux operating system and saved in a “virtual machine” (VM). Virtual machines allow for running consistent set-ups without worrying about differences between operating systems, library dependencies, compiling the code, etc.

-
    -
  1. Install VirtualBox This is the software that runs the virtual machine. You can find the download link and instructions at http://www.virtualbox.org. NOTE: On Windows you may see a warning about Logo testing, it is okay to ignore the warning.

  2. -
  3. Download the PEcAn VM You can find the download link at http://opensource.ncsa.illinois.edu/projects/artifacts.php?key=PECAN, under the “Files” header. Click the “.ova” file to begin the download. Note that the file is ~7 GB, so this download can take several minutes to hours depending on your connection speed. Also, the VM requires >4 GB of RAM to operate correctly. Please check current usage of RAM and shutdown processes as needed.

  4. -
  5. Import the VM Once the download is complete, open VirtualBox. In the VirtualBox menus, go to “File” → “Import Appliance” and locate the downloaded “.ova” file.

  6. -
-

For Virtualbox version 5.x: In the Appliance Import Settings, make sure you select “Reinitialize the MAC address of all network cards” (picture below). This is not selected by default and can result in networking issues since multiple machines might claim to have the same network MAC Address.

-

-

For Virtualbox versions starting with 6.0, there is a slightly different interface (see figure). Select “Generate new MAC addresses for all network adapters” from the MAC Address Policy:

-

-

NOTE: If you experience network connection difficulties in the VM with this enabled, try re-importing the VM without this setting selected).

-

Finally, click “Import” to build the Virtual Machine from its image.

-
    -
  1. Launch PEcAn Double click the icon for the PEcAn VM. A terminal window will pop up showing the machine booting up which may take a minute. It is done booting when you get to the pecan login: prompt. You do not need to login as the VM behaves like a server that we will be accessing through you web browser. Feel free to minimize the VM window.
  2. -
-
    -
  • If you do want to login to the VM, the credentials are as follows: username: carya, password: illinois (after the pecan tree, [Carya illinoinensis][pecan-wikipedia]).
  • -
-
    -
  1. Open the PEcAn web interface With the VM running in the background, open any web browser on the same machine and navigate to localhost:6480/pecan/ to start the PEcAn workflow. (NOTE: The trailing backslash may be necessary depending on your browser)
  2. -
-
    -
  • To ssh into the VM, open up a terminal on your machine and execute ssh -l carya -p 6422 localhost. Username and password are the same as when you log into the machine.
  • -
- -
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/project-overview.html b/master/project-overview.html deleted file mode 100644 index 4eb7a8cd7..000000000 --- a/master/project-overview.html +++ /dev/null @@ -1,922 +0,0 @@ - - - - - - - 1 Project Overview | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

1 Project Overview

-

The Predictive Ecosystem Analyzer (PEcAn) is an integrated informatics toolbox for ecosystem modeling (Dietze et al. 2013, LeBauer et al. 2013). PEcAn consists of:

-
    -
  1. An application program interface (API) that encapsulates an ecosystem model, providing a common interface, inputs, and output.
  2. -
  3. Core utilities for handling and tracking model runs and the flows of information and uncertainties into and out of models and analyses
  4. -
  5. An accessible web-based user interface and visualization tools
  6. -
  7. An extensible collection of modules to handle specific types of analyses (sensitivity, uncertainty, ensemble), model-data syntheses (benchmarking, parameter data assimilation, state data assimilation), and data processing (model inputs and data constraints)
  8. -
-

-

This project is motivated by the fact that many of the most pressing questions about global change are limited by our ability to synthesize existing data and strategically prioritize the collection of new data. This project seeks to improve this ability by developing a framework for integrating multiple data sources in a sensible manner.

-

The workflow system allows ecosystem modeling to be more reproducible, automated, and transparent in terms of operations applied to data, and thus ultimately more comprehensible to both peers and the public. It reduces the redundancy of effort among modeling groups, facilitate collaboration, and make models more accessible the rest of the research community.

-

PEcAn is not itself an ecosystem model, and it can be used to with a variety of different ecosystem models; integrating a model involves writing a wrapper to convert inputs and outputs to and from the standards used by PEcAn. Currently, PEcAn supports multiple models listed PEcAn Models.

-

Acknowledgements

-

The PEcAn project is supported financially by the following:

- -

BETYdb is a product of the Energy Biosciences Institute at the University of Illinois at Urbana-Champaign. We gratefully acknowledge the great effort of other researchers who generously made their own data available for further study.

-

PEcAn is a collaboration among research groups at the Department of Earth And Environment at Boston University, the Energy Biosciences Institute at the University of Illinois, the Image Spatial Data Analysis group at NCSA, the Department of Atmospheric & Oceanic Sciences at the University Wisconsin-Madison, the Terrestrial Ecosystem Science & Technology (TEST) Group at Brookhaven National Laboratory, and the Joint Global Change Research Institute (JGCRI) at the Pacific Northwest National Laboratory.

-

Any opinions, findings, and conclusions or recommendations expressed in this material are those of the author(s) and do not necessarily reflect the views of the NSF, NASA, Boston University, University of Illinois, Brookhaven National Lab, Pacific National Lab, Battelle, the US Department of Defense, or the US Department of Energy.

-

PEcAn Publications

-
    -
  • Fer I, R Kelly, P Moorcroft, AD Richardson, E Cowdery, MC Dietze. 2018. Linking big models to big data: efficient ecosystem model calibration through Bayesian model emulation. Biogeosciences Discussions doi:10.5194/bg-15-5801-2018

  • -
  • Feng X, Uriarte M, González G, et al. Improving predictions of tropical forest response to climate change through integration of field studies and ecosystem modeling. Glob Change Biol. 2018;24:e213–e232.doi:10.1111/gcb.13863

  • -
  • Dietze, M. C. (2017), Prediction in ecology: a first-principles framework. Ecol Appl, 27: 2048-2060. doi:10.1002/eap.1589

  • -
  • Fisher RA, Koven CD, Anderegg WRL, et al. 2017. Vegetation demographics in Earth System Models: A review of progress and priorities. Glob Change Biol. doi:10.1111/gcb.13910

  • -
  • Rollinson, C. R., Liu, Y., Raiho, A., Moore, D. J.P., McLachlan, J., Bishop, D. A., Dye, A., Matthes, J. H., Hessl, A., Hickler, T., Pederson, N., Poulter, B., Quaife, T., Schaefer, K., Steinkamp, J. and Dietze, M. C. (2017), Emergent climate and CO2 sensitivities of net primary productivity in ecosystem models do not agree with empirical data in temperate forests of eastern North America. Glob Change Biol. Accepted Author Manuscript. doi:10.1111/gcb.13626

  • -
  • LeBauer, D., Kooper, R., Mulrooney, P., Rohde, S., Wang, D., Long, S. P. and Dietze, M. C. (2017), betydb: a yield, trait, and ecosystem service database applied to second-generation bioenergy feedstock production. GCB Bioenergy. doi:10.1111/gcbb.12420

  • -
  • Rogers A, BE Medlyn, J Dukes, G Bonan, S von Caemmerer, MC Dietze, J Kattge, ADB Leakey, LM Mercado, U Niinemets, IC Prentice, SP Serbin, S Sitch, DA Way, S Zaehle. 2017. “A Roadmap for Improving the Representation of Photosynthesis in Earth System Models” New Phytologist 213(1):22-42 doi:10.1111/nph.14283

  • -
  • Shiklomanov. A, MC Dietze, T Viskari, PA Townsend, SP Serbin. 2016 “Quantifying the influences of spectral resolution on uncertainty in leaf trait estimates through a Bayesian approach to RTM inversion” Remote Sensing of the Environment 183: 226-238. doi:10.1016/j.rse.2016.05.023

  • -
  • Viskari et al. 2015 Model-data assimilation of multiple phenological observations to constrain and forecast leaf area index. Ecological Applications 25(2): 546-558. doi:10.1890/14-0497.1

  • -
  • Dietze, M. C., S. P. Serbin, C. Davidson, A. R. Desai, X. Feng, R. Kelly, R. Kooper, D. LeBauer, J. Mantooth, K. McHenry, and D. Wang (2014) A quantitative assessment of a terrestrial biosphere model’s data needs across North American biomes. Journal of Geophysical Research-Biogeosciences doi:10.1002/2013jg002392

  • -
  • LeBauer, D.S., D. Wang, K. Richter, C. Davidson, & M.C. Dietze. (2013). Facilitating feedbacks between field measurements and ecosystem models. Ecological Monographs. doi:10.1890/12-0137.1

  • -
  • Wang, D, D.S. LeBauer, and M.C. Dietze(2013) Predicting yields of short-rotation hybrid poplar (Populus spp.) for the contiguous US through model-data synthesis. Ecological Applications doi:10.1890/12-0854.1

  • -
  • Dietze, M.C., D.S LeBauer, R. Kooper (2013) On improving the communication between models and data. Plant, Cell, & Environment doi:10.1111/pce.12043

  • -
  • PEcAn Project Google Scholar page

  • -
  • Longer / auto-updated list of publications that mention PEcAn’s full name in Google Scholar

  • -
- -
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/query-database.html b/master/query-database.html deleted file mode 100644 index 0209a6a84..000000000 --- a/master/query-database.html +++ /dev/null @@ -1,865 +0,0 @@ - - - - - - - 23.3 Query Database | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

23.3 Query Database

-
-

23.3.1 get.trait.data()

-

Queries the database for both the trait data and prior distributions associated with the PFTs specified in the settings file. The list of variables that are queried is determined by what variables have priors associated with them in the definition of the pft. Likewise, the list of species that are associated with a PFT determines what subset of data is extracted out of all data matching a given variable name.

-
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/r-universe.html b/master/r-universe.html deleted file mode 100644 index a5736e1ea..000000000 --- a/master/r-universe.html +++ /dev/null @@ -1,870 +0,0 @@ - - - - - - - 4.3 Installation From r-universe | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

4.3 Installation From r-universe

-

PEcAn.all and all it’s dependencies can be installed from r-universe with the following code:

-
# Enable repository from pecanproject
-options(repos = c(
-  pecanproject = 'https://pecanproject.r-universe.dev',
-  CRAN = 'https://cloud.r-project.org'))
-# Download and install PEcAn.all in R
-install.packages('PEcAn.all')
-

If you are planning on working on PEcAn development with a local install, consider adding the above options() to a project-level .Rprofile as well. For example, by using usethis::edit_r_profile("project"). This will allow devtools to install dependencies from r-universe, for example devtools::install_deps("models/ed") should work when “https://pecanproject.r-universe.dev” is set as a repo.

-

NOTE: functionality of a local install will be limited without a connection to a BETYdb instance. Instructions to install BETY.

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/rabbitmq.html b/master/rabbitmq.html deleted file mode 100644 index 05fecb6f2..000000000 --- a/master/rabbitmq.html +++ /dev/null @@ -1,983 +0,0 @@ - - - - - - - 25.10 RabbitMQ | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

25.10 RabbitMQ

-

This section provides additional details about how PEcAn uses RabbitMQ to manage communication between its Docker containers.

-

In PEcAn, we use the Python pika client to retrieve messages from RabbitMQ. The PEcAn.remote library has convenience functions that wrap the API to post and read messages. The executor and models use the python version of the RabbitMQ scripts to retrieve messages, and launch the appropriate code.

-
-

25.10.1 Producer – PEcAn.remote::rabbitmq_post_message

-

The PEcAn.remote::rabbitmq_post_message function allows you to post messages to RabbitMQ from R. In the RabbitMQ documentation, it is known as a “producer”. It takes the body of the message to be posted and will return any output generated when the message is posted to the approriate queue.

-

The function has three required arguments and two optional ones:

-
    -
  • uri – This is the URI used to connect to RabbitMQ, it will have the form amqp://username:password\@server:5672/vhost. Most containers will have this injected using the environment variable RABBITMQ_URI.
  • -
  • queue – The queue to post the message on, this is either pecan for a workflow to be exected, the name of the model and version to be executed, for example SIPNET_r136.
  • -
  • message – The actual message to be send, this is of type list and will be converted to a json string representation.
  • -
  • prefix – The code will talk to the rest api, this is the prefix of the rest api. In the case of the default docker-compse file, this will be /rabbitmq and will be injected as RABBITMQ_PREFIX.
  • -
  • port – The code will talk to the rest api, this is the port of the rest api. In the case of the default docker-compse file, this will be 15672 and will be injected as RABBITMQ_PORT.
  • -
-

The PEcAn.remote::start_rabbitmq function is a wrapper for this function that provides an easy way to post a folder message to RabbitMQ.

-
-
-

25.10.2 Consumer – receiver.py

-

The receiver.py script runs like a daemon, constantly listening for messages. -In the RabbitMQ documentation, it is known as a “consumer”. -In PEcAn, you can tell that it is ready to receive messages if the corresponding logs (e.g. docker-compose logs executor) show the following message:

-
[*] Waiting for messages. To exit press CTRL+C.
-

Our reciever is configured by three environment variables:

-
    -
  • RABBITMQ_URI – This defines the URI where RabbitMQ is running. -See corresponding argument in the producer

  • -
  • RABBITMQ_QUEUE – This is the name of the queue on which the consumer will listen for messages, just as in the producer.

  • -
  • APPLICATION – This specifies the name (including the path) of the default executable to run when receiving a message. -At the moment, it should be an executable that runs in the directory specified by the message’s folder variable. -In the case of PEcAn models, this is usually ./job.sh, such that the folder corresponds to the run directory associated with a particular runID (i.e. where the job.sh is located). -For the PEcAn workflow itself, this is set to R CMD BATCH workflow.R, such that the folder is the root directory of the workflow (in the executor Docker container, something like /data/workflows/PEcAn_<workflowID>). -This default executable is overridden if the message contains a custom_application key. -If included, the string specified by the custom_application key will be run as a command exactly as is on the container, from the directory specified by folder. -For instance, in the example below, the container will print “Hello there!” instead of running its default application.

    -
    {"custom_application": "echo 'Hello there!'", "folder": "/path/to/my/dir"}
    -

    NOTE that in RabbitMQ messages, the folder key is always required.

  • -
-
-
-

25.10.3 RabbitMQ and the PEcAn web interface

-

RabbitMQ is configured by the following variables in config.php:

-
    -
  • $rabbitmq_host – The RabbitMQ server hostname (default: rabbitmq, because that is the name of the rabbitmq service in docker-compose.yml)
  • -
  • $rabbitmq_port – The port on which RabbitMQ listens for messages (default: 5672)
  • -
  • $rabbitmq_vhost – The path of the RabbitMQ Virtual Host (default: /).
  • -
  • $rabbitmq_queue – The name of the RabbitMQ queue associated with the PEcAn workflow (default: pecan)
  • -
  • $rabbitmq_username – The RabbitMQ username (default: guest)
  • -
  • $rabbitmq_password – The RabbitMQ password (default: guest)
  • -
-

In addition, for running models via RabbitMQ, you will also need to add an entry like the following to the config.php $hostlist:

-
$hostlist=array($fqdn => array("rabbitmq" => "amqp://guest:guest@rabbitmq/%2F"), ...)
-

This will set the hostname to the name of the current machine (defined by the $fqdn variable earlier in the config.php file) to an array with one entry, whose key is rabbitmq and whose value is the RabbitMQ URI (amqp://...).

-

These values are converted into the appropriate entries in the pecan.xml in web/04-runpecan.php.

-
-
-

25.10.4 RabbitMQ in the PEcAn XML

-

RabbitMQ is a special case of remote execution, so it is configured by the host node. -An example RabbitMQ configuration is as follows:

-
<host>
-  <rabbitmq>
-    <uri>amqp://guest:guest@rabbitmq/%2F</uri>
-    <queue>sipnet_136</queue>
-  </rabbitmq>
-</host>
-

Here, uri and queue have the same general meanings as described in “producer”. -Note that queue here refers to the target model. -In PEcAn, RabbitMQ model queues are named as MODELTYPE_REVISION, -so the example above refers to the SIPNET model version 136. -Another example is ED2_git, referring to the latest git version of the ED2 model.

-
-
-

25.10.5 RabbitMQ configuration in Dockerfiles

-

As described in the “consumer” section, our standard RabbitMQ receiver script is configured using three environment variables: RABBITMQ_URI, RABBITMQ_QUEUE, and APPLICATION. -Therefore, configuring a container to work with PEcAn’s RabbitMQ instance requires setting these three variables in the Dockerfile using an ENV statement.

-

For example, this excerpt from docker/base/Dockerfile.executor (for the pecan/executor image responsible for the PEcAn workflow) sets these variables as follows:

-
ENV RABBITMQ_URI="amqp://guest:guest@rabbitmq/%2F" \
-    RABBITMQ_QUEUE="pecan" \
-    APPLICATION="R CMD BATCH workflow.R"
-

Similarly, this excerpt from docker/models/Dockerfile.sipnet (which builds the SIPNET model image) is a typical example for a model image. -Note the use of ARG here to specify a default version model version of 136 while allowing this to be configurable (via --build-arg MODEL_VERSION=X) at build time:

-
ARG MODEL_VERSION=136
-
-ENV APPLICATION="./job.sh" \
-    MODEL_TYPE="SIPNET" \
-    MODEL_VERSION="${MODEL_VERSION}"
-
-ENV RABBITMQ_QUEUE="${MODEL_TYPE}_${MODEL_VERSION}"
-

WARNING: Dockerfile environment variables set via ENV are assigned all at once; they do not evaluate successively, left to right. -Consider the following block:

-
# Don't do this!
-ENV MODEL_TYPE="SIPNET" \
-    MODEL_VERSION=136 \
-    RABBITMQ_QUEUE=${MODEL_TYPE}_${MODEL_VERSION}   # <- Doesn't know about MODEL_TYPE or MODEL_VERSION!
-

In this block, the expansion for setting RABBITMQ_QUEUE is not aware of the current values of MODEL_TYPE or MODEL_VERSION, and will therefore be set incorrectly to just _ (unless they have been set previously, in which case it will be aware only of their earlier values). -As such, variables depending on other variables must be set in a separate, subsequent ENV statement than the variables they depend on.

-
-
-

25.10.6 Case study: PEcAn web interface

-

The following describes in general terms what happens during a typical run of the PEcAn web interface with RabbitMQ.

-
    -
  1. The user initializes all containers with docker-compose up. -All the services that interact with RabbitMQ (executor and all models) run receiver.py in the foreground, waiting for messages to tell them what to do.

  2. -
  3. The user browses to http://pecan.localhost/pecan/ and steps through the web interface. -All the pages up to the 04-runpecan.php run on the web container, and are primarily for setting up the pecan.xml file.

  4. -
  5. Once the user starts the PEcAn workflow at 04-runpecan.php, the underlying PHP code connects to RabbitMQ (based on the URI provided in config.php) and posts the following message to the pecan queue:

  6. -
-
  {"folder": "/workflows/PEcAn_WORKFLOWID", "workflowid": "WORKFLOWID"}
-
    -
  1. The executor service, which is listening on the pecan queue, hears this message and executes its APPLICATION (R CMD BATCH workflow.R) in the working directory specified in the message’s folder. -The executor service then performs the pre-execution steps (e.g. trait meta-analysis, conversions) itself. -Then, to actually execute the model, executor posts the following message to the target model’s queue:
  2. -
-
  {"folder": "/workflows/PEcAn_WORKFLOWID/run/RUNID"}
-
    -
  1. The target model service, which is listening on its dedicated queue, hears this message and runs its APPLICATION, which is job.sh, in the directory indicated by the message. -Upon exiting (normally), the model service writes its status into a file called rabbitmq.out in the same directory.

  2. -
  3. The executor container continuously looks for the rabbitmq.out file as an indication of the model run’s status. -Once it sees this file, it reads the status and proceeds with the post-execution parts of the workflow. -(NOTE that this isn’t perfect. If the model running process exits abnormally, the rabbitmq.out file may not be created, which can cause the executor container to hang. If this happens, the solution is to restart the executor container with docker-compose restart executor).

  4. -
- -
-
- -
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/reference-keys.txt b/master/reference-keys.txt deleted file mode 100644 index 7538210b7..000000000 --- a/master/reference-keys.txt +++ /dev/null @@ -1,744 +0,0 @@ -project-overview -contributor-covenant-code-of-conduct -about-the-pecan-book -general-feedbackcommentssuggestions -bookediting -how-to-create-your-own-version-of-documentation -pecan-manual-setup -install-vm -install-docker -r-universe -install-native -user-section -pecan-in-a-nutshell -demo-table -demo-1 -objective -url-def -start-pecan -site-selection -host -model -site-group -conversion -site -run-specification -pft-plant-functional-type -startend-date -weather-data -optional-settings -data-use-policies -if-you-get-an-error-in-your-run -model-run-workflow -met-process -trait-meta -config -model-1 -output -ensemble-sensitivity -output-and-visualization -graphs -alternative-visualization-r-shiny -model-run-archive -next-steps -analyzing-model-output -demo-02 -demo-2 -run-specification-1 -additional-outputs -run-id -inputs -outputs -pfts -pecan-files -global-sensitivity-shiny -next-steps-1 -assimilation-by-hand -mcmc-concepts -more-info-about-tools-analyses-and-specific-tasks -othervignettes -simple-model-data-comparisons -author-istem-fer-tess-mccabe -starting-rstudio-server -read-in-settings-from-an-xml-file -read-in-model-output-from-specific-variables -compare-model-to-flux-observations -data-assimilation-concepts -fitting-the-model -whats-going-on -evaluating-the-model-output -additional-information -citations -parameter-data-assimilation -objectives -larger-context -connect-to-rstudio -defining-variables -initial-ensemble-analysis -questions -choosing-parameters -questions-1 -editing-pecan-settings -investigating-pecan-function-pda.emulator-optional -running-a-demo-pda -outputs-from-pecans-parameter-data-assimilation -questions-2 -post-pda-analyses -questions-3 -state-variable-data-assimilation -objectives-1 -overview -initial-run -settings -loading-data -estimating-tree-level-data-uncertainties -allometric-equations -estimate-stand-level-npp -build-initial-conditions -load-priors -ensemble-kalman-filter -finishing-up -pecan-testing-the-sensitivity-analysis-against-observations -author-ankur-desai -flux-measurements-and-modeling-course-tutorial-part-2 -introduction -a.-read-in-settings-object-from-a-run-xml -b.-now-lets-bring-in-the-actual-observations -c.-finally-we-can-finally-compare-model-to-data -advanced-user -web-curl-submission -basic-web-workflow -web-site-model -selecting-a-model -selecting-a-site -site-groups -using-existing-sites -adding-a-new-site -troubleshooting -my-site-shows-up-when-i-dont-have-any-model-selected-but-disappears-once-i-select-the-model-i-want-to-run -web-model-config -choosing-meteorology -met-workflow -troubleshooting-meteorological-conversions -could-not-do-gapfill-the-following-variables-have-nas -could-not-get-information-about-.-is-this-an-ameriflux-site -could-not-download-data-for-for-the-year -i-could-not-find-the-requested-var-or-dimvar-in-the-file -selecting-plant-functional-types-pfts-and-other-parameter-groupings. -using-existing-pfts -creating-new-pfts -choosing-initial-vegetation -us-fia -spin-up -selecting-a-soils-product -soil-texture-depth-and-physical-parameters -other-model-inputs -intermediate-user -additional-web-configuration -intermediate-web-setup -browndog -intermediate-advanced-setup -intermediate-model-config -settings-configured-analyses -pda -pda.mcmc.r -pda.mcmc.bs.r -pda.emulator -pda.mcmc.recover.r -pda.utils.r -get.da.data..r-plot.da.r -sda -sda.enkf.r-description -sda.enkf.r-arguments -state-data-assimilation-workflow -state-data-assimilation-tags-example -state-data-assimilation-tags-descriptions -model-specific-functions-for-sda-workflow -read.restart.model.r -write.restart.model.r -split.inputs.model.r -sample.ic.model.r -analysis-options -the-generalized-ensemble-filter -multi-site-state-data-assimilation. -sda.enkf.multisite.r-description -obs.mean-and-obs.cov-description -anlysis-sda-workflow -example-of-multi-settings-pecan-xml-file -running-sda-on-remote -restart-functionality-in-sda -state-data-assimilation-methods -data-products -tree-rings -pollen -variance-inflation -current-models -model-calibration -initial-conditions -drivers -sequential-state-data-assimilation -general-description -enkf -generalized-ensemble-filter -mapping-ensemble-output-to-tobit-space -generalized-ensemble-filter-model-description -ensemble-adjustment -diagnostics -multisettings -benchmarking -data-preparation -model-runs -the-benchmarking-shiny-app -create-a-reference-run-record -setup-benchmarks-and-metrics -benchmarking-output -benchmarking-in-pecan.xml -developer-guide -updatebety -pecan-make -pecan-git -using-git -git -pecan-project-and-github -pecan-project-branches -milestones-issues-tasks -editing-files-on-github -recommended-git-workflow -before-any-work-is-done -hint-keeping-your-fork-in-sync -using-branching -after-pull-request-is-merged -link-commits-to-issues -useful-git-tools -github-desktop -git-rstudio -advanced -fixing-a-release-branch -tags -references -git-documentation -github-documentation -github-use-with-pecan -bugs-issues-features-etc. -reporting-a-bug -required-content -requesting-a-feature -closing-an-issue -when-to-submit-an-issue -coding-practices -developer-codestyle -dplyr -developer-logging -developer-packagedata -summary -accessing-data -examples-of-data-in-pecan-packages -developer-roxygen -updating-to-a-new-roxygen-version -developer-testing -developer-testing-unit -developer-testing-integration -continuous-integration -download-and-compile-pecan -download-compile-and-install-pecan-from-github -pecan-testrun -directory-structure -overview-of-pecan-repository-as-of-pecan-1.5.3 -generic-r-package-structure -working-with-vm -maintain-vm -ssh-vm -ssh-vm-bety -awsvm -createvm -pecan-standards -defining-new-input-formats -time-standard -input-standards -meterology-standards -dimensions -the-variable-names-should-be-standard_name -soils-and-vegetation-inputs -soil-data -vegetation-data -output-standards -pecanXML -xml-core-config -xml-structure -xml-info -xml-outdir -xml-database -xml-bety -xml-dbfiles -xml-fia -xml-pft -xml-meta-analysis -xml-model -xml-model-specific -xml-ed -xml-run -xml-run-site -xml-run-inputs -xml-run-inputs-met -xml-run-inputs-soil -xml-run-inputs-veg -xml-run-inputs-poolinitcond -pft.site-multi-site-site-pft-mapping -start.date-and-end.date -other-tags -xml-host -xml-advanced -xml-ensemble -xml-sensitivity-analysis -xml-parameter-data-assimilation -xml-multi-settings -xml-state-data-assimilation -xml-state-variables -xml-observation-preparation -xml-browndog -xml-benchmarking -xml-remote_process -workflow -workflow-readsettings -workflow-input -workflow-input-data -workflow-input-initial -conus-neonfiabadm-initial-conditions. -north-america-na-initial-conditions. -workflow-met -workflow-met-download -workflow-met-standard -workflow-met-downscale -workflow-met-model -workflow-input-phenology -workflow-traits -workflow-metaanalysis -workflow-modelconfig -workflow-modelrun -workflow-postrun -pecan-models -models-biocro -introduction-1 -pecan-configuration-file-additions -model-specific-input-files -model-configuration-files -installation-notes -models-clm -models-dalec -models-ed -introduction-2 -pecan-configuration-file-additions-1 -models-ed-pft-configuration -model-specific-input-files-1 -model-configuration-files-1 -installation-notes-1 -vm -bu-geo -tacc-lonestar -tacc-stampede -models-gday -models-ldndc -introduction-3 -model-specific-input-files-2 -model-configuration-files-2 -installation-notes-2 -models-linkages -models-lpjguess -models-maespa -models-preles -models-sipnet -models-stics -met-drivers -ameriflux -amerifluxlbl -fluxnet2015 -narr -cruncep -cmip5 -nldas -gldas -paleon -fluxnetlathuile -geostreams -era5 -icos-drought-2018 -icos-ecosystem-archive -download-gfdl -cm3 -esm2m-esm2g -pecan-project-api -introduction-4 -authentication -restful-api-endpoints -examples -prerequisites-to-interact-with-the-pecan-api-server -r-packages -python-packages -get-apiping -r-snippet -python-snippet -get-apistatus -r-snippet-1 -python-snippet-1 -get-apimodels -r-snippet-2 -python-snippet-2 -get-apimodelsmodel_id -r-snippet-3 -python-snippet-3 -get-apisites -r-snippet-4 -python-snippet-4 -get-apisitessite_id -r-snippet-5 -python-snippet-5 -get-apipfts -r-snippet-6 -python-snippet-6 -get-apipftspft_id -r-snippet-7 -python-snippet-7 -get-apiformats -r-snippet-8 -python-snippet-8 -get-apiformatsformat_id -r-snippet-9 -python-snippet-9 -get-apiinputs -r-snippet-10 -python-snippet-10 -get-apiinputsinput_id -r-snippet-11 -python-snippet-11 -get-apiworkflows -r-snippet-12 -python-snippet-12 -post-apiworkflows -r-snippet-13 -python-snippet-13 -get-apiworkflowsid -r-snippet-14 -python-snippet-14 -get-apiworkflowsidstatus -r-snippet-15 -python-snippet-15 -get-apiworkflowsidfilefilename -r-snippet-16 -python-snippet-16 -get-apiruns -r-snippet-17 -python-snippet-17 -get-apirunsrun_id -r-snippet-18 -python-snippet-18 -get-apirunsrun_idinputfilename -r-snippet-19 -python-snippet-19 -get-apirunsrun_idoutputfilename -r-snippet-20 -python-snippet-20 -get-apirunsrun_idgraphyeary_var -r-snippet-21 -python-snippet-21 -database-sync -how-does-it-work -set-up -fetch-latest-data -sharing-data -automation -database-maintentance -reindexing-the-database -vacuuming-the-database -troubleshooting-1 -username-and-password -db_hba.conf-file -network-status-map -tasks -standalone-tools-modules -LoadData -inputs-1 -output-1 -example -remote-data-module -google-earth-engine -appeears -lp-daac-data-pool -set-up-instructions-first-time-and-one-time-only -usage-guide -configuring-remote_process -creating-polygon-based-sites -example-use-gee -example-use-appeears -example-use-gedi-lp-daac-data-pool -adding-new-gee-image-collections -shiny -testing-the-shiny-server -debugging-shiny-apps -checking-log-files -adding-to-pecan -adding-model -using-pecan-database -define-model_type -machine -model-2 -formats -model_type---formats -inputs-2 -add-plant-functional-types-pfts -species -cultivars -adding-priors-for-each-variable -creating-new-prior-distributions -creating-new-variables -interface-modules -setting-up-the-module-directory-required -example-met-conversion-wrapper-function -description -namespace -building-the-package -write.config.model-required -output-conversions -met2model.model -commit-changes -NewInput -input-records-in-bety -create-a-database-file-record-for-the-input-data -creating-a-new-input-record-in-bety -InputConversions -meterological-data -adding-a-function-to-pecan-to-convert-a-met-data-source -adding-single-site-specific-meteorological-data -processing-met-data-outside-of-the-workflow-using-pecan-functions -example-1-processing-data-from-a-database -example-2-processing-data-from-data-already-in-hand -vegetation-data-1 -example-1-processing-veg-data-from-data-in-hand. -example-3-pool-initial-condition-files -soil-data-1 -example-1-converting-data-in-hand -example-2-converting-paleon-data -example-3-extracting-soil-properties-from-gssurgo-database -adding-data-web -loading-data-1 -selecting-ingest-method -dataone-upload-example -local-upload-example -creating-a-format-record -NewFormat -formats-in-bety -creating-a-new-format-in-bety -formats---variables -name-and-unit -storage-type -column-number -retrieving-format-information -inputs-3 -output-2 -NewBenchmark -editing-records -troubleshooting-and-debugging-pecan -cookies-and-pecan-web-pages -warning-mkdir-function.mkdir-no-such-file-or-directory -after-creating-a-new-pft-the-tag-for-pft-not-passed-to-config.xml-in-ed -debugging -using-testsworkflow.r -useful-scripts -database -database-setup -backup-of-bety-database -restore-of-bety-database -workflow-modules -overview-1 -load-settings -read.settingshomepecanpecan.xml -query-database -get.trait.data -meta-analysis -run.meta.analysis -write-configuration-files -write.configsmodel -start-runs -start.runsmodel -get-model-output -get.model.outputmodel -ensemble-analysis -run.ensemble.analysis -sensitivity-analysis-variance-decomposition -run.sensitivity.analysis -glossary -installation-details -pecanvm -aws-setup -convert-pecan-vm -set-up-an-account-on-aws -install-ec2-command-line-tools -create-an-aws-s3-bucket-to-upload-vm-to -upload -configuring-the-vm -set-up-multiple-instances-optional -booting-the-vm -shiny-setup -install-the-shiny-r-package-and-shiny-server -modify-the-shiny-configuration-file -set-the-apache-proxy -ubuntu-only-enable-the-new-shiny-configuration -enable-and-start-the-shiny-server-and-restart-apache -on-centos -on-ubuntu -troubleshooting-2 -further-reading -thredds-setup -install-the-tomcat-8-and-thredds-webapp -customize-the-thredds-server -update-the-catalog -troubleshooting-3 -further-reading-1 -osinstall -ubuntu -install-build-environment -install-postgres -apache-configuration-pecan -apache-configuration-bety -rstudio-server -additional-packages -centosredhat -install-build-environment-1 -install-and-configure-postgresql-udunits2-netcdf -apache-configuration-pecan-1 -apache-configuration-bety-1 -rstudio-server-1 -install-and-configure-rstudio-server -install-ruby-netcdf-gem -additional-packages-1 -macosx -install-build-environment-2 -install-postgres-1 -additional-installs -install-jags -install-udunits -apache-configuration -ruby -rstudio-server-2 -install-bety -install-database-data -installing-betydb-web-application -php-version -ruby-version -install-models -inst-biocro -inst-clm45 -clm-test-run -inst-dalec -inst-ed2 -ed2.2-r46-used-in-pecan-manuscript -ed-2.2-r82 -ed-2.2-bleeding-edge -inst-fates -inst-gday -inst-jules -inst-linkages -r-installation -fortran-version -inst-lpj-guess -inst-maespa -solution-1 -solution-2 -sipnet-inst-sipnet -sipnet-testrun -install-data -site-information -fia-database -flux-camp -harvard-for-ed-tutorial -docker-index -docker-intro -what-is-docker -working-with-docker -docker-compose -docker-quickstart -the-pecan-docker-install-process-in-detail -pecan-setup-compose-configure -pecan-docker-quickstart-init -pecan-docker-quickstart-init-db -add-first-user-to-pecan-database -pecan-docker-quickstart-init-data -curl-model-runs -docker-quickstart-troubleshooting -pecan-docker -pecan-docker-overview -pecan-docker-compose -pecan-dc-structure -pecan-dc-traefik -pecan-dc-portainer -pecan-dc-minio -pecan-dc-thredds -pecan-dc-postgres -pecan-dc-rabbitmq -pecan-dc-bety -pecan-dc-docs -pecan-dc-web -pecan-dc-executor -pecan-dc-monitor -pecan-dc-models -model-docker -model-docker-json-file -model-docker-Dockerfile -common-docker-problems -debugging-missing-libraries -docker-build-images -docker-local-devel -docker-troubleshooting -package-not-available-while-building-images -docker-migrate -running-bety-as-a-docker-container -pecan-api -installation -creating-and-submitting-a-workflow -rabbitmq -rabbitmq-basics-sender -rabbitmq-basics-receiver -rabbitmq-web -rabbitmq-xml -rabbitmq-dockerfile -rabbitmq-case-study -pecan-remote -basics-of-ssh -ssh-authentication-password-vs.-ssh-key -ssh-tunneling -ssh-tunnels-and-pecan -basic-remote-execute-functions -remote-model-execution-with-pecan -xml-configuration -configuration-for-pecan-web-interface -running-pecan-code-for-remotely -special-case-geo.bu.edu -data-assimilation-with-dart -miscellaneous -todo -using-the-pecan-download_file-function -faq -pecan-project-used-in-courses -university-classes -ge-375---environmental-modeling---spring-2013-2014-mike-dietze-boston-university -summer-courses-workshops -annual-summer-course-in-flux-measurement-and-advanced-modeling-mike-dietze-ankur-desai-niwot-ridge-co -assimilating-long-term-data-into-ecosystem-models-paleo-ecological-observatory-network-paleon-project -integrating-evidence-on-forest-response-to-climate-change-physiology-to-regional-abundance -ecological-society-of-america-meetings -selected-publications -package-dependencies -executive-summary-what-to-usually-do -big-picture-whats-possible-to-do -declaring-dependencies-depends-suggests-imports -importing-functions-use-roxygen -loading-code-dont-but-use-requirenamespace-when-you-do -installing-dependencies-let-the-machines-do-it -appendix-testthat -list-of-expectations -basic-use-of-the-testthat-package -data-for-tests -settings-1 -helper-functions-for-unit-tests -developer-devtools -models_singularity -sibcasa diff --git a/master/remote-data-module.html b/master/remote-data-module.html deleted file mode 100644 index aa2f230e1..000000000 --- a/master/remote-data-module.html +++ /dev/null @@ -1,1111 +0,0 @@ - - - - - - - 18.2 Remote data module | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

18.2 Remote data module

-

Remote data module retrieves remote sensing data from MODISTools, Google Earth Engine and AppEEARS, as well as from the NASA’s Land Processes Distributed Active Archive Center (LP DAAC) data server. For currently available R functions see here, and for the Python functions see RpTools. The downloaded data can be used while performing further analyses in PEcAn.

-
-

18.2.0.1 Google Earth Engine

-

Google Earth Engine is a cloud-based platform for performing analysis on satellite data. It provides access to a large data catalog through an online JavaScript code editor and a Python API.

-

Datasets currently available for use in PEcAn via Google Earth Engine are,

- -
-
-

18.2.0.2 AppEEARS

-

AppEEARS (Application for Extracting and Exploring Analysis Ready Samples) is an online tool which provides an easy to use interface for downloading analysis ready remote sensing data. Products available on AppEEARS. Note: AppEEARS uses a task based system for processing the data request, it is possible for a task to run for long hours before it gets completed. The module checks the task status after every 60 seconds and saves the files when the task gets completed.

-
-
-

18.2.0.3 LP DAAC Data Pool

-

LP DAAC (Land Processes Distributed Active Archive Center) Data Pool is a NASA Earthdata login-enabled server located at the USGS Earth Resources Observation and Science (EROS) Center that archives and distributes land data products. Similar to AppEEARS, using this source also requires an Earthdata account (see below). Currently this pipeline is implemented and tested only for the GEDI dataset. For more information about the data you are downloading, including documentation and how to properly cite the data, please visit https://lpdaac.usgs.gov/.

-
-
-

18.2.0.4 Set-Up instructions (first time and one time only):

-
    -
  1. Sign up for the Google Earth Engine. Follow the instructions here to sign up for using GEE. You need to have your own GEE account for using the GEE download functions in this module.

  2. -
  3. Sign up for NASA Earthdata. Using AppEEARS and LP DAAC Data Pool requires an Earthdata account visit this page to create your own account.

  4. -
  5. Install the RpTools package. Python codes required by this module are stored in a Python package named “RpTools” using this requires Python3 and the package manager pip3 to be installed in your system. -To install the package,

  6. -
-
    -
  1. Navigate to pecan/modules/data.remote/inst/RpTools If you are inside the pecan directory, this can be done by,
  2. -
-
cd modules/data.remote/inst/RpTools
-
    -
  1. Use pip3 to install the package. “-e” flag is used to install the package in an editable or develop mode, so that changes made to the code get updated in the package without reinstalling.
  2. -
-
pip3 install -e .
-
    -
  1. Authenticate GEE. The GEE API needs to be authenticated using your credentials. The credentials will be stored locally on your system. This can be done by,
  2. -
-
#this will open a browser and ask you to sign in with the Google account registered for GEE
-earthengine authenticate
-

Alternate way,

-
python3
-
-import ee
-ee.Authenticate()
-
    -
  1. Save the Earthdata credentials. If you wish to use AppEEARS or LP DAAC data pool you will have to store your username and password inside a JSON file and then pass its file path as an argument in remote_process
  2. -
-
-
-

18.2.0.5 Usage guide:

-

This module is accesible using the R function remote_process which uses the Python package “RpTools” (located at data.remote/inst/RpTools) for downloading and processing data. RpTools has a function named rp_control which controls two other functions,

-
    -
  1. get_remote_data which controls the scripts which are used for downloading data from the source. For example, gee2pecan_s2 downloads bands from Sentinel 2 using GEE.

  2. -
  3. process_remote_data which controls the scripts responsible for processing the raw data. For example, bands2lai_snap uses the downloaded bands to compute LAI using the SNAP algorithm.

  4. -
-
- -

Workflow of the module

-
-
-
-

18.2.1 Configuring remote_process

-

remote_process is configured using remote data tags in the pecan.xml. The required tags are described below,

-
  <remotedata>
-  <out_get_data>...</out_get_data>
-  <source>...</source>
-  <collection>...</collection>
-  <scale>...</scale>
-  <projection>...</projection>
-  <qc>...</qc>
-  <algorithm>...</algorithm>
-  <credfile>...</credfile>
-  <out_process_data>...</out_process_data>
-  <overwrite>...</overwrite>
-  </remotedata>
-
    -
  • out_get_data: (required) type of raw output requested, e.g, bands, smap
  • -
  • source: (required) source of remote data, e.g., gee or appeears
  • -
  • collection: (required) dataset or product name as it is provided on the source, e.g. “COPERNICUS/S2_SR” for gee or “SPL3SMP_E.003” for appeears
  • -
  • scale: (optional) pixel resolution required for some gee collections, recommended to use 10 for Sentinel 2 scale Information about how GEE handles scale can be found out here
  • -
  • projection: (optional) type of projection. Only required for appeears polygon AOI type
  • -
  • qc: (optional) quality control parameter, required for some gee collections
  • -
  • overwrite: (optional) if TRUE database checks will be skipped and existing data of same type will be replaced entirely. When processed data is requested, the raw data required for creating it will also be replaced. By default FALSE
  • -
-

If you don’t want to enter your Earthdata credentials everytime you use AppEEARS or LP DAAC use the following tag too:

-
    -
  • credfile: (optional) absolute path to JSON file containing Earthdata username and password, only required when using AppEEARS and LP DAAC data pool. The contents of this file could be as simple as the following:
  • -
-
{
-  "username": "yourEARTHDATAusername",
-  "password": "yourEARTHDATApassword"
-}
-

These tags are only required if processed data (i.e. further processing after downloading the data) is requested:

-
    -
  • out_process_data: (optional) type of processed output requested, e.g, lai
  • -
  • algorithm: (optional) algorithm used for processing data, currently only SNAP is implemented to estimate LAI from Sentinel-2 bands
  • -
-

Additional information are taken from the registration files located at pecan/modules/data.remote/inst/registration, each source has its own registration file. This is so because there isn’t a standardized way to retrieve all image collections from GEE and each image collection may require its own way of performing quality checks, etc whereas all of the products available on AppEEARS can be retrieved using its API in a standardized way.

-

GEE registration file (register.GEE.xml) :

-
    -
  • collection -
      -
    • original_name original name of the image collection, e.g. COPERNICUS/S2_SR
    • -
    • pecan_name short form of original name using which the collection is represented in PEcAn, e.g. s2
    • -
  • -
  • coord -
      -
    • coord_type coordinate type supported by the collection
    • -
  • -
  • scale the default value of the scale can be specified here
  • -
  • qc the default value of the qc parameter can be specified here
  • -
  • raw_format format details of the raw file -
      -
    • id id of the format
    • -
    • name name of the format
    • -
    • mimetype MIME type
    • -
  • -
  • pro_format format details of the processed file when the collection is used to create a processed file -
      -
    • id id of the format
    • -
    • name name of the format
    • -
    • mimetype MIME type
    • -
  • -
-

AppEEARS and LP DAAC Data Pool registration files (register.APPEEARS.xml and register.LPDAACDATAPOOL.xml) :

-
    -
  • coord -
      -
    • coord_type coordinate type supported by the product
    • -
  • -
  • raw_format format details of the output file -
      -
    • id id of the format
    • -
    • name name of the format
    • -
    • mimetype MIME type
    • -
  • -
-

Remaining input data:

-
    -
  • start date, end date: these are taken from the run tag in pecan.xml
  • -
  • outdir: from the outdir tag in pecan.xml
  • -
  • Area of interest: the coordinates and site name are found out from BETY using siteid present in the run tag. These are then used to create a GeoJSON file which is used by the download functions.
  • -
-

The output data from the module are returned in the following tags:

-
    -
  • raw_id: input id of the raw file
  • -
  • raw_path: absolute path to the raw file
  • -
  • pro_id: input id of the processed file
  • -
  • pro_path: absolute path to the processed file
  • -
-

Output files:

-

The output files are of netCDF type and are stored in a directory inside the specified outdir with the following naming convention: source_site_siteid

-

The output files are created with the following naming convention: source_collection_scale_projection_qc_site_siteid_TimeStampOfFileCreation

-

Whenever a data product is requested the output files are stored in the inputs table of BETYdb. Subsequently when the same product is requested again with a different date range but with the same qc, scale, projection the previous file in the db would be extended. The DB would always contain only one file of the same type. -As an example, if a file containing Sentinel 2 bands for start date: 2018-01-01, end date: 2018-06-30 exists in the DB and the same product is requested again for a different date range one of the following cases would happen,

-
    -
  1. New dates are ahead of the existing file: For example, if the requested dates are start: 2018-10-01, end: 2018-12-31 in this case the previous file will be extended forward meaning the effective start date of the file to be downloaded would be the day after the end date of the previous file record, i.e. 2018-07-01. The new and the previous file would be merged and the DB would now be having data for 2018-01-01 to 2018-12-31.

  2. -
  3. New dates are preceding of the existing file: For example, if the requested dates are start: 2017-01-01, end: 2017-06-30 in this case the effective end date of the new download would be the day before the start date of the existing file, i.e., 2017-12-31. The new and the previous file would be merged and the file in the DB would now be having data for 2017-01-01 to 2018-06-30.

  4. -
  5. New dates contain the date range of the existing file: For example, if the requested dates are start: 2016-01-01, end: 2019-06-30 here the existing file would be replaced entirely with the new file. A more efficient way of doing this could be to divide your request into two parts, i.e, first request for 2016-01-01 to 2018-01-01 and then for 2018-06-30 to 2019-06-30.

  6. -
-

When a processed data product such as SNAP-LAI is requested, the raw product (here Sentinel 2 bands) used to create it would also be stored in the DB. If the raw product required for creating the processed product already exists for the requested time period, the processed product would be created for the entire time period of the raw file. For example, if Sentinel 2 bands are present in the DB for 2017-01-01 to 2017-12-31 and SNAP-LAI is requested for 2017-03-01 to 2017-07-31, the output file would be containing LAI for 2017-01-01 to 2017-12-31.

-
-

18.2.1.1 Creating Polygon based sites

-

A polygon site can be created in the BETYdb using the following way,

-
PEcAn.DB::db.query("insert into sites (country, sitename, geometry) values ('country_name', 'site_name', ST_SetSRID(ST_MakePolygon(ST_GeomFromText('LINESTRING(lon lat elevation)')), crs));", con)
-

Example,

-
db.query("insert into sites (country, sitename, geometry) values ('FI', 'Qvidja_ca6cm', ST_SetSRID(ST_MakePolygon(ST_GeomFromText('LINESTRING(22.388957339620813 60.287395608412218 14.503780364990234, 22.389600591651835 60.287182336733203 14.503780364990234,
-22.38705422266651  60.285516177775868 14.503780364990234,      
-22.386575219445195 60.285763643883932 14.503780364990234,
-22.388957339620813 60.287395608412218 14.503780364990234 )')), 4326));", con)
-
-
-

18.2.1.2 Example use (GEE)

-

This example will download Sentinel 2 bands and then use the SNAP algorithm to compute Leaf Area Index.

-
    -
  1. Add remotedata tag to pecan.xml and configure it.
  2. -
-
  <remotedata>
-  <out_get_data>bands</out_get_data>
-  <source>gee</source>
-  <collection>COPERNICUS/S2_SR</collection>
-  <scale>10</scale>
-  <qc>1</qc>
-  <algorithm>snap</algorithm>
-  <out_process_data>LAI</out_process_data>
-  </remotedata>
-
    -
  1. Store the contents of pecan.xml in a variable named settings and pass it to remote_process.
  2. -
-
PEcAn.data.remote::remote_process(settings)
-

The output netCDF files(bands and LAI) will be saved at outdir and their records would be kept in the inputs table of BETYdb.

-
-
-

18.2.1.3 Example use (AppEEARS)

-

This example will download the layers of a SMAP product(SPL3SMP_E.003)

-
    -
  1. Add remotedata tag to pecan.xml and configure it.
  2. -
-
  <remotedata>
-  <out_get_data>smap</out_get_data>
-  <source>appeears</source>
-  <collection>SPL3SMP_E.003</collection>
-  <projection>native</projection>
-  <algorithm></algorithm>
-  <credfile>path/to/jsonfile/containingcredentials</credfile>
-  </remotedata>
-
    -
  1. Store the contents of pecan.xml in a variable named settings and pass it to remote_process.
  2. -
-
PEcAn.data.remote::remote_process(settings)
-

The output netCDF file will be saved at outdir and its record would be kept in the inputs table of BETYdb.

-
-
-

18.2.1.4 Example use GEDI (LP DAAC data pool)

-
  <remotedata>
-  <out_get_data>gedi</out_get_data>
-  <source>lpdaacdatapool</source>
-  <collection>GEDI02_B.002</collection>
-  <credfile>path/to/jsonfile/containingcredentials</credfile>
-  </remotedata>
-
    -
  1. Store the contents of pecan.xml in a variable named settings and pass it to remote_process.
  2. -
-
PEcAn.data.remote::remote_process(settings)
-
-
-

18.2.1.5 Adding new GEE image collections

-

Once you have the Python script for downloading the collection from GEE, please do the following to integrate it with this module.

-
    -
  1. Make sure that the function and script names are same and named in the following way: gee2pecan_pecancodeofimagecollection -pecancodeofimagecollection can be any name which you want to use for representing the collection is an easier way. -Additionaly, ensure that the function accepts and uses the following arguments,

    -
      -
    • geofile - (str) GeoJSON file containing AOI information of the site
    • -
    • outdir - (str) path where the output file has to be saved
    • -
    • start - (str) start date in the form YYYY-MM-DD
    • -
    • end - (str) end date in the form YYYY-MM-DD
    • -
    • scale and qc if applicable.
    • -
  2. -
  3. Make sure the output file is of netCDF type and follows the naming convention described above.

  4. -
  5. Store the Python script at pecan/modules/data.remote/inst/RpTools/RpTools

  6. -
  7. Update the register.GEE.xml file.

  8. -
-

After performing these steps the script will be integrated with the remote data module and would be ready to use.

- -
-
-
- -
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/remote-model-execution-with-pecan.html b/master/remote-model-execution-with-pecan.html deleted file mode 100644 index 7135f12c9..000000000 --- a/master/remote-model-execution-with-pecan.html +++ /dev/null @@ -1,869 +0,0 @@ - - - - - - - 26.6 Remote model execution with PEcAn | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

26.6 Remote model execution with PEcAn

-

The workhorse of remote model execution is the PEcAn.workflow::start_model_runs function, which distributes execution of each run in a list of runs (e.g. multiple runs in an ensemble) to the local machine or a remote based on the configuration in the PEcAn settings.

-

Broadly, there are three major types of model execution:

-
    -
  • Serialized (PEcAn.remote::start_serial) – This runs models one at a time, directly on the local machine or remote (i.e. same as calling the executables one at a time for each run).
  • -
  • Via a queue system, (PEcAn.remote::start_qsub) – This uses a queue management system, such as SGE (e.g. qsub, qstat) found on the BU SCC machines, to submit jobs. -For computationally intensive tasks, this is the recommended way to go.
  • -
  • Via a model launcher script (PEcAn.remote::setup_modellauncher) – This is a highly customizable approach where task submission is controlled by a user-provided script (launcher.sh).
  • -
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/restful-api-endpoints.html b/master/restful-api-endpoints.html deleted file mode 100644 index 5d4bdeba3..000000000 --- a/master/restful-api-endpoints.html +++ /dev/null @@ -1,913 +0,0 @@ - - - - - - - 16.3 RESTful API Endpoints | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

16.3 RESTful API Endpoints

-

This page contains the high-level overviews & the functionalities offered by the different RESTful endpoints of the PEcAn API.

-

For the most up-to-date documentation, you can visit the PEcAn API Documentation.

-

The currently implemented functionalities include:

- -

* indicates that the particular API is under development & may not be ready for use

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/restore-of-bety-database.html b/master/restore-of-bety-database.html deleted file mode 100644 index f2873dfba..000000000 --- a/master/restore-of-bety-database.html +++ /dev/null @@ -1,873 +0,0 @@ - - - - - - - 22.3 Restore of BETY database | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

22.3 Restore of BETY database

-

Hopefully this section will never need to be used. Following are 5 steps that have been used to restore the database. Before you start it is worth it to read up online a bit on restoring the database as well as join the slack channel and ask any of the people there for help.

-
    -
  1. stop apache (BETY/PEcAn web apps) service httpd stop or service apache2 stop
  2. -
  3. backup database (you know just incase) pg_dump -d bety > baddb.sql
  4. -
  5. drop database sudo -u postgres psql -c 'drop database bety'
  6. -
  7. create database sudo -u postgres psql -c 'create database bety with owner bety'
  8. -
  9. load database (assuming dump is called bety.sql.gz) zcat bety.sql.gz | grep -v search_path | sudo -u postgres psql -d bety
  10. -
  11. start apache again service httpd start or service apache2 start
  12. -
-

If during step 5 there is a lot of errors, it is helpful to add -v ON_ERROR_STOP=1 to the end of the command. This will stop the restore at the first error and will help with debugging the issue.

- -
- -
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/running-pecan-code-for-remotely.html b/master/running-pecan-code-for-remotely.html deleted file mode 100644 index 29f748cc3..000000000 --- a/master/running-pecan-code-for-remotely.html +++ /dev/null @@ -1,873 +0,0 @@ - - - - - - - 26.9 Running PEcAn code for remotely | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

26.9 Running PEcAn code for remotely

-

You do not need to download PEcAn fully on your remote machine. You can compile and install the model specific code pieces of -PEcAn on the cluster easily without having to install the -full code base of PEcAn (and all OS dependencies). Use the git clone command to:

-
devtools::install_github("pecanproject/pecan", subdir = 'base/utils')
-

Next we need to install the model specific pieces, this is done -almost the same (example for ED2):

-
devtools::install_github("pecanproject/pecan", subdir = 'models/ed')
-

This should install dependencies required.

-
    -
  • The following are some notes on how to install the model specifics on different HPC -clusters*
  • -
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/search_index.json b/master/search_index.json deleted file mode 100644 index 008263c18..000000000 --- a/master/search_index.json +++ /dev/null @@ -1 +0,0 @@ -[["index.html", "The Predictive Ecosystem Analyzer Welcome", " The Predictive Ecosystem Analyzer By: PEcAn Team 2024-07-13 Welcome Ecosystem science, policy, and management informed by the best available data and models Our Mission: Develop and promote accessible tools for reproducible ecosystem modeling and forecasting PEcAn Website Public Chat Room Github Repository .page-inner{max-width:80% !important;} "],["project-overview.html", "1 Project Overview", " 1 Project Overview The Predictive Ecosystem Analyzer (PEcAn) is an integrated informatics toolbox for ecosystem modeling (Dietze et al. 2013, LeBauer et al. 2013). PEcAn consists of: An application program interface (API) that encapsulates an ecosystem model, providing a common interface, inputs, and output. Core utilities for handling and tracking model runs and the flows of information and uncertainties into and out of models and analyses An accessible web-based user interface and visualization tools An extensible collection of modules to handle specific types of analyses (sensitivity, uncertainty, ensemble), model-data syntheses (benchmarking, parameter data assimilation, state data assimilation), and data processing (model inputs and data constraints) This project is motivated by the fact that many of the most pressing questions about global change are limited by our ability to synthesize existing data and strategically prioritize the collection of new data. This project seeks to improve this ability by developing a framework for integrating multiple data sources in a sensible manner. The workflow system allows ecosystem modeling to be more reproducible, automated, and transparent in terms of operations applied to data, and thus ultimately more comprehensible to both peers and the public. It reduces the redundancy of effort among modeling groups, facilitate collaboration, and make models more accessible the rest of the research community. PEcAn is not itself an ecosystem model, and it can be used to with a variety of different ecosystem models; integrating a model involves writing a wrapper to convert inputs and outputs to and from the standards used by PEcAn. Currently, PEcAn supports multiple models listed PEcAn Models. Acknowledgements The PEcAn project is supported financially by the following: National Science Foundation (NSF): 1062547 1062204 1241894 1261582 1318164 1346748 1458021 1638577 1655095 1702996 National Aeronautics and Space Administration (NASA) NNX14AH65G NNX16AO13H 80NSSC17K0711 Advanced Research Projects Agency-Energy (ARPA-E) DE-AR0000594 Department of Defense, Strategic Environmental Research and Development Program (DOD-SERDP), grant RC2636 Energy Biosciences Institute, University of Illinois Amazon Web Services (AWS) Google Summer of Code BETYdb is a product of the Energy Biosciences Institute at the University of Illinois at Urbana-Champaign. We gratefully acknowledge the great effort of other researchers who generously made their own data available for further study. PEcAn is a collaboration among research groups at the Department of Earth And Environment at Boston University, the Energy Biosciences Institute at the University of Illinois, the Image Spatial Data Analysis group at NCSA, the Department of Atmospheric & Oceanic Sciences at the University Wisconsin-Madison, the Terrestrial Ecosystem Science & Technology (TEST) Group at Brookhaven National Laboratory, and the Joint Global Change Research Institute (JGCRI) at the Pacific Northwest National Laboratory. Any opinions, findings, and conclusions or recommendations expressed in this material are those of the author(s) and do not necessarily reflect the views of the NSF, NASA, Boston University, University of Illinois, Brookhaven National Lab, Pacific National Lab, Battelle, the US Department of Defense, or the US Department of Energy. PEcAn Publications Fer I, R Kelly, P Moorcroft, AD Richardson, E Cowdery, MC Dietze. 2018. Linking big models to big data: efficient ecosystem model calibration through Bayesian model emulation. Biogeosciences Discussions doi:10.5194/bg-15-5801-2018 Feng X, Uriarte M, González G, et al. Improving predictions of tropical forest response to climate change through integration of field studies and ecosystem modeling. Glob Change Biol. 2018;24:e213–e232.doi:10.1111/gcb.13863 Dietze, M. C. (2017), Prediction in ecology: a first-principles framework. Ecol Appl, 27: 2048-2060. doi:10.1002/eap.1589 Fisher RA, Koven CD, Anderegg WRL, et al. 2017. Vegetation demographics in Earth System Models: A review of progress and priorities. Glob Change Biol. doi:10.1111/gcb.13910 Rollinson, C. R., Liu, Y., Raiho, A., Moore, D. J.P., McLachlan, J., Bishop, D. A., Dye, A., Matthes, J. H., Hessl, A., Hickler, T., Pederson, N., Poulter, B., Quaife, T., Schaefer, K., Steinkamp, J. and Dietze, M. C. (2017), Emergent climate and CO2 sensitivities of net primary productivity in ecosystem models do not agree with empirical data in temperate forests of eastern North America. Glob Change Biol. Accepted Author Manuscript. doi:10.1111/gcb.13626 LeBauer, D., Kooper, R., Mulrooney, P., Rohde, S., Wang, D., Long, S. P. and Dietze, M. C. (2017), betydb: a yield, trait, and ecosystem service database applied to second-generation bioenergy feedstock production. GCB Bioenergy. doi:10.1111/gcbb.12420 Rogers A, BE Medlyn, J Dukes, G Bonan, S von Caemmerer, MC Dietze, J Kattge, ADB Leakey, LM Mercado, U Niinemets, IC Prentice, SP Serbin, S Sitch, DA Way, S Zaehle. 2017. “A Roadmap for Improving the Representation of Photosynthesis in Earth System Models” New Phytologist 213(1):22-42 doi:10.1111/nph.14283 Shiklomanov. A, MC Dietze, T Viskari, PA Townsend, SP Serbin. 2016 “Quantifying the influences of spectral resolution on uncertainty in leaf trait estimates through a Bayesian approach to RTM inversion” Remote Sensing of the Environment 183: 226-238. doi:10.1016/j.rse.2016.05.023 Viskari et al. 2015 Model-data assimilation of multiple phenological observations to constrain and forecast leaf area index. Ecological Applications 25(2): 546-558. doi:10.1890/14-0497.1 Dietze, M. C., S. P. Serbin, C. Davidson, A. R. Desai, X. Feng, R. Kelly, R. Kooper, D. LeBauer, J. Mantooth, K. McHenry, and D. Wang (2014) A quantitative assessment of a terrestrial biosphere model’s data needs across North American biomes. Journal of Geophysical Research-Biogeosciences doi:10.1002/2013jg002392 LeBauer, D.S., D. Wang, K. Richter, C. Davidson, & M.C. Dietze. (2013). Facilitating feedbacks between field measurements and ecosystem models. Ecological Monographs. doi:10.1890/12-0137.1 Wang, D, D.S. LeBauer, and M.C. Dietze(2013) Predicting yields of short-rotation hybrid poplar (Populus spp.) for the contiguous US through model-data synthesis. Ecological Applications doi:10.1890/12-0854.1 Dietze, M.C., D.S LeBauer, R. Kooper (2013) On improving the communication between models and data. Plant, Cell, & Environment doi:10.1111/pce.12043 PEcAn Project Google Scholar page Longer / auto-updated list of publications that mention PEcAn’s full name in Google Scholar "],["contributor-covenant-code-of-conduct.html", "2 Contributor Covenant Code of Conduct", " 2 Contributor Covenant Code of Conduct Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. Our Standards Examples of behavior that contributes to creating a positive environment include: Using welcoming and inclusive language Being respectful of differing viewpoints and experiences Gracefully accepting constructive criticism Focusing on what is best for the community Showing empathy towards other community members Examples of unacceptable behavior by participants include: The use of sexualized language or imagery and unwelcome sexual attention or advances Trolling, insulting/derogatory comments, and personal or political attacks Public or private harassment Publishing others’ private information, such as a physical or electronic address, without explicit permission Other conduct which could reasonably be considered inappropriate in a professional setting Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. Scope This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at pecanproj[at]gmail.com. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project’s leadership. Attribution This Code of Conduct is adapted from the Contributor Covenant version 1.4, available at http://contributor-covenant.org/version/1/4. "],["about-the-pecan-book.html", "3 About the PEcAn Book", " 3 About the PEcAn Book This book serves as documentation for the PEcAn Project. It contains descriptions of topics necessary to inform a beginner and advanced user as well as requisite materials for developers. It does not contain low-level descriptions of functions within PEcAn. Our aim for this documentation is to educate you about the PEcAn software, the possibilities of its usage, and the standards,expectations, and core workflows for developers. This book is organized four main topics: Introduction - Brief explanation of PEcAn, how to obtain the PEcAn VM, and explanation of basic web interface functions. Tutorials/Demos/Workflows - All User and Developer tutorials/demos/workflows to explain how to use and add to PEcAn in different ways. Topical Pages - Explanation of main PEcAn components and how they fit together. Appendix - External documentation and sources of information and a FAQ section. "],["general-feedbackcommentssuggestions.html", "3.1 General Feedback/Comments/Suggestions", " 3.1 General Feedback/Comments/Suggestions We want your ideas, thoughts, comments, and suggestions! As a community we are committed to creating an inclusive and supportive atmosphere so we all to reach out to us in the following ways: Github: https://github.com/PecanProject/pecan This is the main hub of communication surrounding PEcAn development. Check out the issues section to see known bugs, upcoming features, and ideas for future development. Feel free to comment on existing issues or open new ones with questions, bug reports, feature requests, and/or ideas. Slack: https://pecanproject.slack.com/ Slack serves as our day to day mode of communication. To join us in slack you will need to create an account first. This is done in 3 steps: Request an inivitation to join Slack, this will be send by email to address you provided. Check your inbox for an email from Slack with subject “Rob Kooper has invited you to join a Slack workspace”. This email should have a link that you can click to join slack. When you click a webpage will open up that asks you to create an account, once that is done you can login into the slack chatrooms. Email: pecanproj[at]gmail.com If you do not wish your communication with the team to be public, send us an email at the address above and we will get back to you as soon as possible. "],["bookediting.html", "3.2 Editing this book", " 3.2 Editing this book The file organization of this documentation can be described simply as follows: Each chapter is in its own file (within the corresponding section). Each group of chapters (i.e. “part” in LaTeX) is in its own directory. Sections and chapters are rendered (and numbered) in alpha-numerical order of their corresponding file names. Therefore, each section directory and chapter file name should be prefixed with a two-digit (zero-padded) number. File and directory names should be as similar as possible to the name of the corresponding chapter or section. For instance, the file name for this chapter’s source file is 06_reference/10_editing_this_book.Rmd. This numbering means that if you need to create an additional chapter before an existing one, you will have to renumber all chapters following it. To ensure correct rendering, you should also make sure that each chapter starts with a level 1 heading (# heading). For instance, this chapter’s source starts with: # Editing this book {#bookediting} The file organization of this documentation can be described simply as follows: ... Furthermore, to keep the organization consistent, each chapter should have exactly one level 1 heading (i.e. do not combine multiple chapters into a single file). In other words, do not spread a single chapter across multiple files, and do not put multiple chapters in the same file. Each section directory has a file starting with 00 that contains only the section (or “Part”) title. This is used to create the greyed-out section headers in the rendered HTML. For instance, this section has a file called 00_introduction.Rmd which contains only the following: # (PART) Introduction {-} To cross-reference a different section, use that section’s unique tag (starts with #; appears next to the section heading surrounded in curly braces). For instance, the following Markdown contains two sections that cross-reference each other: ## Introduction {#intro} Here is the intro. This is a link to the [next section](#section-one). ## First section. {#section-one} As mentioned in the [previous section](#intro). If no header tag exists for a section you want to cross-reference, you should create one. We have no strict rules about this, but it’s useful to have tags that give some sense of their parent hierarchy and reference their parent sections (e.g. #models, #models-ed, and #models-ed-xml to refer to a chapter on models, with a subsection on ED and a sub-subsection on ED XML configuration). If section organization changes, it is fine to move header tags, but avoid altering existing tags as this will break all the links pointing to that tag. (Note that it is also possible to link to section headings by their exact title. However, this is not recommended because these section titles could change, which would break the links.) When referring to PEcAn packages or specific functions, it is a good idea to link to the rendered package documentation. For instance, here are links to the models/ed package, the PEcAn.ED2::modify_ed2in function, and the PEcAnRTM package vignette. If necessary, you can also link directly to specific lines or blocks in the source code on GitHub, like this. (To get a link to a line, click its line number. To then select a block, shift-click another line number.) To insert figures, use knitr::include_graphics(\"path/to/figure.png\") inside an R code chunk. For example: ```{r} knitr::include_graphics("04_advanced_user_guide/images/Input_ID_name.png") ``` Note that image file names are relative to the book_source directory, NOT to the markdown file. In other words, if myimage.png was in the same directory as this file, I would still have to reference it as 06_reference/myimage.png – I could not just do myimage.png. The size, caption, and other properties of the rendered image can be controlled via chunk options. For additional information about how bookdown works (including information about its syntax), see the Bookdown free online book. "],["how-to-create-your-own-version-of-documentation.html", "3.3 How to create your own version of Documentation", " 3.3 How to create your own version of Documentation To create your own version of documentation you’ll need to follow these steps: These procedures assume you have an github account, you forked pecan, you have cloned pecan locally, and have a TRAVIS account. 1. Create a repository under your github account with the name “pecan-documentation”. Clear it of any files. Set up the repository with Github Pages by going to the settings tab for that repository. 2. Create a personal access token for github: https://help.github.com/en/articles/creating-a-personal-access-token-for-the-command-line and copy it. 3. Create a TRAVIS environment variable called GITHUB_PAT and save the access token you made as a secret variable. 4. Create a branch from your local pecan repository with a name that starts with release/. (ie. Release/vtonydoc) 5. Make whichever changes you would like to the documentation and push it up to your fork. From here TRAVIS will build your documentation. The web version of your documentation will be rendered with the url following the structure: username.github.io/pecan-documentation/pattern_after_release/ "],["pecan-manual-setup.html", "4 Install PEcAn", " 4 Install PEcAn These instructions are provided to document how to install and setup PEcAn. It includes: Virtual machine (Recommended for students and new users) PEcAn Docker (Recommended for development and production deployment) Local installation from r-universe (Recommended for development only) PEcAn OS specific installation The PEcAn code and necessary infrastructure can be obtained and compiled in different ways. This set of instructions will help facilitate your path and the steps necessary to move forward to have a fully a functioning PEcAn environment. "],["install-vm.html", "4.1 Virtual Machine (VM)", " 4.1 Virtual Machine (VM) The PEcAn virtual machine consists of all of PEcAn pre-compiled within a Linux operating system and saved in a “virtual machine” (VM). Virtual machines allow for running consistent set-ups without worrying about differences between operating systems, library dependencies, compiling the code, etc. Install VirtualBox This is the software that runs the virtual machine. You can find the download link and instructions at https://www.virtualbox.org. NOTE: On Windows you may see a warning about Logo testing, it is okay to ignore the warning. Download the PEcAn VM You can find the download link at http://opensource.ncsa.illinois.edu/projects/artifacts.php?key=PECAN, under the “Files” header. Click the “.ova” file to begin the download. Note that the file is ~7 GB, so this download can take several minutes to hours depending on your connection speed. Also, the VM requires >4 GB of RAM to operate correctly. Please check current usage of RAM and shutdown processes as needed. Import the VM Once the download is complete, open VirtualBox. In the VirtualBox menus, go to “File” → “Import Appliance” and locate the downloaded “.ova” file. For Virtualbox version 5.x: In the Appliance Import Settings, make sure you select “Reinitialize the MAC address of all network cards” (picture below). This is not selected by default and can result in networking issues since multiple machines might claim to have the same network MAC Address. For Virtualbox versions starting with 6.0, there is a slightly different interface (see figure). Select “Generate new MAC addresses for all network adapters” from the MAC Address Policy: NOTE: If you experience network connection difficulties in the VM with this enabled, try re-importing the VM without this setting selected). Finally, click “Import” to build the Virtual Machine from its image. Launch PEcAn Double click the icon for the PEcAn VM. A terminal window will pop up showing the machine booting up which may take a minute. It is done booting when you get to the pecan login: prompt. You do not need to login as the VM behaves like a server that we will be accessing through you web browser. Feel free to minimize the VM window. If you do want to login to the VM, the credentials are as follows: username: carya, password: illinois (after the pecan tree, [Carya illinoinensis][pecan-wikipedia]). Open the PEcAn web interface With the VM running in the background, open any web browser on the same machine and navigate to localhost:6480/pecan/ to start the PEcAn workflow. (NOTE: The trailing backslash may be necessary depending on your browser) Advanced interaction with the VM is mostly done through the command line. You can perform these manipulations from inside the VM window. However, the VM is also configured for SSH access (username carya, hostname localhost, port 6422). For instance, to open an interactive shell inside the VM from a terminal on the host machine, use a command like ssh -l carya -p 6422 localhost (when prompted, the password is illinois, as above). These steps should be enough to get you started with running models and performing basic analyses with PEcAn. For advanced details on VM configuration and maintenance, see the Advanced VM section. "],["install-docker.html", "4.2 Docker", " 4.2 Docker This is a short documentation on how to start with Docker and PEcAn. This will not go into much detail about about how to use Docker – for more details, see the main Docker topical page. Install Docker. Follow the instructions for your operating system at https://www.docker.com/community-edition#/download. Once Docker is installed, make sure it is running. To test that Docker is installed and running, open a terminal and run the following commands: docker run hello-world If successful, this should return a message starting with \"Hello from Docker!\". If this doesn’t work, there is something wrong with your configuration. You may need to open the Docker desktop app to complete the installation. Refer to the Docker documentation for debugging. NOTE: Depending on how Docker is installed and configured, you may have to run this command as sudo. Try running the command without sudo first. If that fails, but running as sudo succeeds, see these instructions for steps to use Docker as a non-root user. Install docker compose. If you are running this on a Mac or Windows this might be already installed. On Linux you will need to install this it separately; see https://docs.docker.com/compose/install/. To see if docker compose is successfully installed, use the following shell command: docker compose version This should print the current version of docker-compose. We have tested the instruction below with versions of docker compose 1.22 and above. Download the PEcAn docker compose file. It is located in the root directory of the PEcAn source code. For reference, here are direct links to the latest stable version and the bleeding edge development version. (To download the files, you should be able to right click the link and select “Save link as”.) Make sure the file is saved as docker-compose.yml in a directory called pecan. Initialize the PEcAn database and data images. The following docker compose commands are used to download all the data PEcAn needs to start working. For more on how they work, see our Docker topical pages. Create and start the PEcAn database container (without any data) docker compose up -d postgres If this is successful, the end of the output should look like the following: Creating pecan-postgres-1 ... done “Initialize” the data for the PEcAn database. docker run --rm --network pecan_pecan pecan/db This should produce a lot of output describing the database operations happening under the hood. Some of these will look like errors, but this is normal. This command succeeded if the output ends with the following (the syntax for creating a new user for accessing BetyDB): docker compose run bety user 'login' 'password' 'full name' 'email' 1 1 Add a user to BetyDB using the example syntax provided as the last line of the output of the previous step: # guest user docker compose run --rm bety user guestuser guestuser "Guest User" guestuser@example.com 4 4 # example user docker compose run --rm bety user carya illinois "Carya Demo User" carya@example.com 1 1 Download and configure the core PEcAn database files. docker run -ti --rm --network pecan_pecan --volume pecan_pecan:/data --env FQDN=docker pecan/data:develop This will produce a lot of output describing file operations. This command succeeded if the output ends with the following: ###################################################################### Done! ###################################################################### Download the pecan/docker/env.example & save it as .env file. Now, open the .env file & uncomment the following lines: COMPOSE_PROJECT_NAME=pecan PECAN_VERSION=develop Setting PECAN_VERSION=develop indicates that you want to run the bleeding-edge develop branch, meaning it may have bugs. To go ahead with the stable version you may set PECAN_VERSION=latest or PECAN_VERSION=<release-number> (For example 1.7.0). You can look at the list of all the releases of PEcAn to see what options are availble. Start the PEcAn stack. Assuming all of the steps above completed successfully, start the full stack by running the following shell command: docker compose up -d If all of the containers started successfully, you should be able to access the various components from a browser via the following URLs (if you run these commands on a remote machine replace localhost with the actual hostname). PEcAn documentation and home page – http://pecan.localhost PEcAn web interface (running models) – http://pecan.localhost/pecan/ (NOTE: The trailing slash is necessary.) BETY web interface – http://pecan.localhost/bety/ (Default username: carya, default password: illinois) RStudio interface – http://pecan.localhost/rstudio/ (Default username: carya, default password: illinois) Monitor, service that monitors models and shows all models that are online as well as how many instances are online and the number of jobs waiting. The output is in JSON – http://pecan.localhost/monitor/ To shut down the docker images run docker-compose stop. For troubleshooting and advanced configuration, see our Docker topical pages. "],["r-universe.html", "4.3 Installation From r-universe", " 4.3 Installation From r-universe PEcAn.all and all it’s dependencies can be installed from r-universe with the following code: # Enable repository from pecanproject options(repos = c( pecanproject = 'https://pecanproject.r-universe.dev', CRAN = 'https://cloud.r-project.org')) # Download and install PEcAn.all in R install.packages('PEcAn.all') If you are planning on working on PEcAn development with a local install, consider adding the above options() to a project-level .Rprofile as well. For example, by using usethis::edit_r_profile(\"project\"). This will allow devtools to install dependencies from r-universe, for example devtools::install_deps(\"models/ed\") should work when “https://pecanproject.r-universe.dev” is set as a repo. NOTE: functionality of a local install will be limited without a connection to a BETYdb instance. Instructions to install BETY. "],["install-native.html", "4.4 (Advanced) Native install", " 4.4 (Advanced) Native install The full PEcAn system has a lot of dependencies, including R packages, compiled C and Fortran libraries, and system services and utilities. Installing all of these side by side, and getting them to work harmoniously, is very time-consuming and challenging, which is why we strongly encourage new users to use the VM or Docker if possible. In a nutshell, the process for manual installation is as follows: Download the PEcAn source code from GitHub. The recommended way to do this is with the shell command git clone, i.e. git clone https://github.com/pecanproject/pecan. Download the BETY source code from GitHub. Install the PEcAn R packages and their dependencies. This can be done by running the shell command make inside the PEcAn source code directory. Note that many of the R packages on which PEcAn depends have system dependencies that are not included by default on most operating systems, but almost all of which should be available via your operating system’s package manager (e.g. Homebrew for MacOS, apt for Ubuntu/Debian/Mint Linux, yum for RedHat Fedora/CentOS). Install and configure PostgreSQL Install and configure the Apache web server. For more details, see our notes about OS Specific Installations. "],["user-section.html", "5 Tutorials ", " 5 Tutorials "],["pecan-in-a-nutshell.html", "5.1 How PEcAn Works in a nutshell", " 5.1 How PEcAn Works in a nutshell PEcAn provides an interface to a variety of ecosystem models and attempts to standardize and automate the processes of model parameterization, execution, and analysis. First, you choose an ecosystem model, then the time and location of interest (a site), the plant community (or crop) that you are interested in simulating, and a source of atmospheric data from the BETY database (LeBauer et al, 2010). These are set in a “settings” file, commonly named pecan.xml which can be edited manually if desired. From here, PEcAn will take over and set up and execute the selected model using your settings. The key is that PEcAn uses models as-is, and all of the translation steps are done within PEcAn so no modifications are required of the model itself. Once the model is finished it will allow you to create graphs with the results of the simulation as well as download the results. It is also possible to see all past experiments and simulations. There are two ways of using PEcAn, via the web interface and directly within R. Even for users familiar with R, using the web interface is a good place to start because it provides a high level overview of the PEcAn workflow. The quickest way to get started is to download the virtual machine or use an AWS instance. "],["demo-table.html", "5.2 PEcAn Demos", " 5.2 PEcAn Demos The following Tutorials assume you have installed PEcAn. If you have not, please consult the PEcAn Installation Section. Type Title Web Link Source Rmd Demo Basic Run html Rmd Demo Uncertainty Analysis html Rmd Demo Output Analysis html Rmd Demo MCMC html Rmd Demo Parameter Assimilation html Rmd Demo State Assimilation html Rmd Demo Sensitivity html Rmd Vignette Allometries html Rmd Vignette MCMC html Rmd Vignette Meteorological Data html Rmd Vignette Meta-Analysis html Rmd Vignette Photosynthetic Response Curves html Rmd Vignette Priors html Rmd Vignette Leaf Spectra:PROSPECT inversion html Rmd "],["demo-1.html", "5.3 Demo 01: Basic Run PEcAn", " 5.3 Demo 01: Basic Run PEcAn 5.3.0.1 Objective We will begin by exploring a set of web-based tools that are designed to run single-site model runs. A lot of the detail about what’s going on under the hood, and all the outputs that PEcAn produces, are left to Demo 2. This demo will also demonstrate how to use PEcAn outputs in additional analyses outside of PEcAn. 5.3.0.2 PEcAn URL In the following demo, URL is the web address of a PEcAn server and will refer to one of the following: If you are doing a live demo with the PEcAn team, URL was provided If you are running the PEcAn virtual machine: URL = localhost:6480 If you are running PEcAn using Amazon Web Services (AWS), URL is the Public IP If you are running PEcAn using Docker, URL is pecan.localhost If you followed instructions found in Install PEcAn by hand, URL is your server’s IP 5.3.0.3 Start PEcAn: Enter URL in your web browser Click the link for the PEcAn web interface Click the ‘Next’ button in the sidebar to move to the “Site Selection” page. 5.3.0.4 Site Selection 5.3.0.5 Host Select the local machine “pecan”. Other options exist if you’ve read and followed instructions found in Remote execution with PEcAn. 5.3.0.6 Model Select SIPNET (r136) from the available models because it is quick & simple. Reference material can be found in Models in PEcAn 5.3.0.7 Site Group To filter sites, you can select a specific group of sites. For this tutorial we will use Ameriflux. 5.3.0.8 Conversion: Select the conversion check box, to show all sites that PEcAn is capable of generating model drivers for automatically. By default (unchecked), PEcAn only displays sites where model drivers already exist in the system database 5.3.0.9 Site: For this tutorial, type US-NR1 in the search box to display the Niwot Ridge Ameriflux site (US-NR1), and then click on the pin icon. When you click on a site’s flag on the map, it will give you the name and location of the site and put that site in the “Site:” box on the left hand site, indicating your current selection. Once you are finished with the above steps, click “Next”. 5.3.0.10 Run Specification Next we will specify settings required to run the model. Be aware that the inputs required for any particular model may vary somewhat so there may be addition optional or required input selections available for other models. 5.3.0.11 PFT (Plant Functional Type): Niwot Ridge is temperate coniferous. Available PFTs will vary by model and some models allow multiple competing PFTs to be selected. Also select soil to control the soil parameters 5.3.0.12 Start/End Date: Select 2003/01/01 to 2006/12/31. In general, be careful to select dates for which there is available driver data. 5.3.0.13 Weather Data: For Sipnet.climna select “Use AmerifluxLBL” from the Available Meteorological Drivers. 5.3.0.14 Optional Settings: Leave all blank for demo run Email sends a message when the run is complete. Use Brown Dog will use the Brown Dog web services in order to do input file conversions. (Note: Required if you select Use NARR for Weather Data) Edit pecan.xml allows you to configure advanced settings via the PEcAn settings file Edit model config pauses the workflow after PEcAn has written all model specific settings but before the model runs are called and allows users to configure any additional settings internal to the model. Advanced Setup controls ensemble and sensitivity run settings discussed in Demo 2. Finally, click “Next” to start the model run. 5.3.0.15 Data Use Policies The last step before the run starts is to read and agree to AmeriFlux’s data policy and give a valid username. If you don’t already have an Ameriflux username, click “register here” and create one. If you selected a different data source, this step may or may not be needed: you will need to agree to a data policy if your source has one, but if it doesn’t then the run will start immediately. 5.3.0.16 If you get an error in your run If you get an error in your run as part of a live demo or class activity, it is probably simplest to start over and try changing options and re-running (e.g. with a different site or PFT), as time does not permit detailed debugging. If the source of the error is not immediately obvious, you may want to take a look at the workflow.Rout to see the log of the PEcAn workflow or the logfile.txt to see the model execution output log and then refer to the Documentation or the Chat Room for help. 5.3.0.17 Model Run Workflow 5.3.0.18 MET Process: First, PEcAn will download meteorological data based on the type of the Weather Data you chose, and process it into the specific format for the chosen model 5.3.0.19 TRAIT / META: PEcAn then estimates model parameters by performing a meta-analysis of the available trait data for a PFT. TRAIT will extract relevant trait data from the database. META performs a hierarchical Bayes meta-analysis of available trait data. The output of this analysis is a probability distribution for each model parameter. PEcAn selects the median value of this parameter as the default, but in Demo 2 we will see how PEcAn can use this parameter uncertainty to make probabilistic forecasts and assess model sensitivity and uncertainty. Errors at this stage usually indicate errors in the trait database or incorrectly specified PFTs (e.g. defining a variable twice). 5.3.0.20 CONFIG: writes model-specific settings and parameter files 5.3.0.21 MODEL: runs model. 5.3.0.22 OUTPUT: All model outputs are converted to standard netCDF format 5.3.0.23 ENSEMBLE & SENSITIVITY: If enabled post-process output for these analyses If at any point a Stage Name has the Status “ERROR” please notify the PEcAn team member that is administering the demo or feel free to do any of the following: Refer to the PEcAn Documentation for documentation Post the end of your workflow log on our Slack Channel chat Post an issue on Github. The entire PEcAn team welcomes any questions you may have! If the Finished Stage has a Status of “DONE”, congratulations! If you got this far, you have managed to run an ecosystem model without ever touching a line of code! Now it’s time to look at the results click Finished. FYI, adding a new model to PEcAn does not require modification of the model’s code, just the implementation of a wrapper function. 5.3.0.24 Output and Visualization For now focus on graphs, we will explore all of PEcAn’s outputs in more detail in Demo 02. 5.3.0.25 Graphs Select a Year and Y-axis Variable, and then click ‘Plot run/year/variable’. Initially leave the X-axis as time. Within this figure the points indicate the daily mean for the variable while the envelope encompasses the diurnal variability (max and min). Variable names and units are based on a standard netCDF format. Try looking at a number of different output variables over different years. Try changing the X-axis to look at bivariate plots of how different output variables are related to one another. Be aware that PEcAn currently runs a moving min/mean/max through bivariate plots, just as it does with time series plots. In some cases this makes more sense than others. 5.3.0.26 Alternative Visualization: R Shiny Click on Open SHINY, which will open a new browser window. The shiny app will automatically access your run’s output files and allow you to visualize all output variables as a function of time. Use the pull down menu under Variable Name to choose whichever output variable you wish to plot. 5.3.0.27 Model Run Archive Return to the output window and Click on the HISTORY button. Click on any previous run in the “ID” column to go to the current state of that run’s execution – you can always return to old runs and runs in-progress this way. The run you just did should be the more recent entry in the table. For the next analysis, make note of the ID number from your run. 5.3.0.28 Next steps 5.3.0.28.1 Analyzing model output Follow this tutorial, [Analyze Output] to learn how to open model output in R and compare to observed data 5.3.0.29 DEMO 02 Demo 02: Sensitivity and Uncertainty Analysis will show how to perform Ensemble & Sensitivity Analyses through the web interface and explore the PEcAn outputs in greater detail, including the trait meta-analysis "],["demo-2.html", "5.4 Demo 02: Sensitivity and Uncertainty Analysis", " 5.4 Demo 02: Sensitivity and Uncertainty Analysis In Demo 2 we will be looking at how PEcAn can use information about parameter uncertainty to perform three automated analyses: Ensemble Analysis: Repeat numerous model runs, each sampling from the parameter uncertainty, to generate a probability distribution of model projections. Allows us to put a confidence interval on the model Sensitivity Analysis: Repeats numerous model runs to assess how changes in model parameters will affect model outputs. Allows us to identify which parameters the model is most sensitive to. Uncertainty Analysis: Combines information about model sensitivity with information about parameter uncertainty to determine the contribution of each model parameter to the uncertainty in model outputs. Allow us to identify which parameters are driving model uncertainty. 5.4.1 Run Specification Return to the main menu for the PEcAn web interface: Click the “Start Over” button or navigate back to URL/pecan/ Repeat the steps for site selection and run specification from Demo 01, but also click on “Advanced setup”, then click Next. By clicking Advanced setup, PEcAn will first show an Analysis Menu, where we are going to specify new settings. For an ensemble analysis, increase the number of runs in the ensemble, in this case set Runs to 50. In practice you would want to use a larger ensemble size (100-5000) than we are using in the demo. The ensemble analysis samples parameters from their posterior distributions to propagate this uncertainty into the model output. PEcAn’s sensitivity analysis holds all parameters at their median value and then varies each parameter one-at-a-time based on the quantiles of the posterior distribution. PEcAn also includes a handy shortcut, which is the default behavior for the web interface, that converts a specified standard deviation into its Normal quantile equivalent (e.g. 1 and -1 are converted to 0.157 and 0.841). In this example set Sensitivity to -2,-1,1,2 (the median value, 0, occurs by default). We also can tell PEcAn which variable to run the sensitivity on. Here, set Variables to NEE, so we can compare against flux tower NEE observations. Click Next 5.4.2 Additional Outputs: The PEcAn workflow will take considerably longer to complete since we have just asked for over a hundred model runs. Once the runs are complete you will return to the output visualization page were there will be a few new outputs to explore, as well as outputs that were present earlier that we’ll explore in greater details: 5.4.2.1 Run ID: While the sensitivity and ensemble analyses synthesize across runs, you can also select individual runs from the Run ID menu. You can use the Graphs menu to visualize each individual run, or open individual runs in Shiny 5.4.2.2 Inputs: This menu shows the contents of /run which lets you look at and download: A summary file (README.txt) describing each run: location, run ID, model, dates, whether it was in the sensitivity or ensemble analysis, variables modified, etc. The model-specific input files fed into the model The jobs.sh file used to submit the model run 5.4.2.3 Outputs: This menu shows the contents of /out. A number of files generated by the underlying ecosystem model are archived and available for download. These include: Output files in the standardized netCDF ([year].nc) that can be downloaded for visualization and analysis (R, Matlab, ncview, panoply, etc) Raw model output in model-specific format (e.g. sipnet.out). Logfile.txt contains job.sh & model error, warning, and informational messages 5.4.2.4 PFTs: This menu shows the contents of /pft. There is a wide array of outputs available that are related to the process of estimating the model parameters and running sensitivity/uncertainty analyses for a specific Plant Functional Type. TRAITS: The Rdata files trait.data.Rdata and jagged.data.Rdata are, respectively, the available trait data extracted from the database that was used to estimate the model parameters and that same data cleaned and formatted for the statistical code. The list of variables that are queried is determined by what variables have priors associated with them in the definition of the PFTs. Priors are output into prior.distns.Rdata. Likewise, the list of species that are associated with a PFT determines what subset of data is extracted out of all data matching a given variable name. Demo 3 will demonstrate how a PFT can be created or modified. To look at these files in RStudio click on these files to load them into your workspace. You can further examine them in the Environment window or accessing them at the command line. For example, try typing names(trait.data) as this will tell you what variables were extracted, names(trait.data$Amax) will tell you the names of the columns in the Amax table, and summary(trait.data$Amax) will give you summary data about the Amax values. META-ANALYSIS: *.bug: The evaluation of the meta-analysis is done using a Bayesian statistical software package called JAGS that is called by the R code. For each trait, the R code will generate a [trait].model.bug file that is the JAGS code for the meta-analysis itself. This code is generated on the fly, with PEcAn adding or subtracting the site, treatment, and greenhouse terms depending upon the presence of these effects in the data itself. If the <random.effects> tag is set to FALSE then all random effects will be turned off even if there are multiple sites. meta-analysis.log contains a number of diagnostics, including the summary statistics of the model, an assessment of whether the posterior is consistent with the prior, and the status of the Gelman-Brooks-Rubin convergence statistic (which is ideally 1.0 but should be less than 1.1). ma.summaryplots.*.pdf are collections of diagnostic plots produced in R after the above JAGS code is run that are useful in assessing the statistical model. Open up one of these pdfs to evaluate the shape of the posterior distributions (they should generally be unimodal), the convergence of the MCMC chains (all chains should be mixing well from the same distribution), and the autocorrelation of the samples (should be low). traits.mcmc.Rdata contains the raw output from the statistical code. This includes samples from all of the parameters in the meta-analysis model, not just those that feed forward to the ecosystem, but also the variances, fixed effects, and random effects. post.distns.Rdata stores a simple tables of the posterior distributions for all model parameters in terms of the name of the distribution and its parameters. posteriors.pdf provides graphics showing, for each model parameter, the prior distribution, the data, the smoothed histogram of the posterior distribution (labeled post), and the best-fit analytical approximation to that smoothed histogram (labeled approx). Open posteriors.pdf and compare the posteriors to the priors and data SENSITIVITY ANALYSIS sensitivity.analysis.[RunID].[Variable].[StartYear].[EndYear].pdf shows the raw data points from univariate one-at-a-time analyses and spline fits through the points. Open this file to determine which parameters are most and least sensitive UNCERTAINTY ANALYSIS variance.decomposition.[RunID].[Variable].[StartYear].[EndYear].pdf, contains three columns, the coefficient of variation (normalized posterior variance), the elasticity (normalized sensitivity), and the partial standard deviation of each model parameter. Open this file for BOTH the soil and conifer PFTS and answer the following questions: The Variance Decomposition graph is sorted by the variable explaining the largest amount of variability in the model output (right hand column). From this graph identify the top-tier parameters that you would target for future constraint. A parameter can be important because it is highly sensitive, because it is highly uncertain, or both. Identify parameters in your output that meet each of these criteria. Additionally, identify parameters that are highly uncertain but unimportant (due to low sensitivity) and those that are highly sensitive but unimportant (due to low uncertainty). Parameter constraints could come from further literature synthesis, from direct measurement of the trait, or from data assimilation. Choose the parameter that you think provides the most efficient means of reducing model uncertainty and propose how you might best reduce uncertainty in this process. In making this choice remember that not all processes in models can be directly observed, and that the cost-per-sample for different measurements can vary tremendously (and thus the parameter you measure next is not always the one contributing the most to model variability). Also consider the role of parameter uncertainty versus model sensitivity in justifying your choice of what parameters to constrain. 5.4.2.5 PEcAn Files: This menu shows the contents of the root workflow folder that are not in one of the folders indicated above. It mostly contains log files from the PEcAn workflow that are useful if the workflow generates an error, and as metadata & provenance (a detailed record of how data was generated). STATUS gives a summary of the steps of the workflow, the time they took, and whether they were successful pecan.*.xml are PEcAn settings files workflow.R is the workflow script workflow.Rout is the corresponding log file samples.Rdata contains the parameter values used in the runs. This file contains two data objects, sa.samples and ensemble.samples, that are the parameter values for the sensitivity analysis and ensemble runs respectively sensitivity.output.[RunID].[Variable].[StartYear].[EndYear].Rdata contains the object sensitivity.output which is the model outputs corresponding to the parameter values in sa.samples. ENSEMBLE ANALYSIS ensemble.Rdata contains contains the object ensemble.output, which is the model predictions at the parameter values given in ensemble.samples. ensemble.analysis.[RunID].[Variable].[StarYear].[EndYear].pdf contains the ensemble prediction as both a histogram and a boxplot. ensemble.ts.[RunID].[Variable].[StartYear].[EndYear].pdf contains a time-series plot of the ensemble mean, median, and 95% CI 5.4.2.6 Global Sensitivity: Shiny Navigate to URL/shiny/global-sensitivity. This app uses the output from the ENSEMBLE runs to perform a global Monte Carlo sensitivity analysis. There are three modes controlled by Output type: Pairwise looks at the relationship between a specific parameter (X) and output (Y) All parameters looks at how all parameters affect a specific output (Y) All variables looks at how all outputs are affected by a specific parameter(X) In all of these analyses, the app also fits a linear regression to these scatterplots and reports a number of summary statistics. Among these, the slope is an indicator of global sensitivity and the R2 is an indicator of the contribution to global uncertainty 5.4.2.7 Next Steps The next set of tutorials will focus on the process of data assimilation and parameter estimation. The next two steps are in “.Rmd” files which can be viewed online. 5.4.2.8 Assimilation ‘by hand’ Explore how model error changes as a function of parameter value (i.e. data assimilation ‘by hand’) 5.4.2.9 MCMC Concepts Explore Bayesian MCMC concepts using the photosynthesis module 5.4.2.10 More info about tools, analyses, and specific tasks… Additional information about specific tasks (adding sites, models, data; software updates; etc.) and analyses (e.g. data assimilation) can be found in the PEcAn documentation If you encounter a problem with PEcAn that’s not covered in the documentation, or if PEcAn is missing functionality you need, please search known bugs and issues, submit a bug report, or ask a question in our chat room. Additional questions can be directed to the project manager "],["othervignettes.html", "5.5 Other Vignettes", " 5.5 Other Vignettes 5.5.1 Simple Model-Data Comparisons 5.5.1.1 Author: Istem Fer, Tess McCabe In this tutorial we will compare model outputs to data outside of the PEcAn web interface. The goal of this is to demonstrate how to perform additional analyses using PEcAn’s outputs. To do this you can download each of the Output files, and then perform the analyses using whatever software you prefer, or you can perform analyses directly on the PEcAn server itself. Here we’ll be analyzing model outputs in R using a browser-based version of RStudio that’s installed on the server 5.5.1.2 Starting RStudio Server Open RStudio Server in a new window at URL/rstudio The username is carya and the password is illinois. To open a new R script click File > New File > R Script Use the Files browser on the lower right pane to find where your run(s) are located All PEcAn outputs are stored in the output folder. Click on this to open it up. Within the outputs folder, there will be one folder for each workflow execution. For example, click to open the folder PEcAn_99000000001 if that’s your workflow ID A workflow folder will have a few log and settings files (e.g. pecan.xml) and the following subfolders run contains all the inputs for each run out contains all the outputs from each run pft contains the parameter information for each PFT Within both the run and out folders there will be one folder for each unique model run, where the folder name is the run ID. Click to open the out folder. For our simple case we only did one run so there should be only one folder (e.g. 99000000001). Click to open this folder. Within this folder you will find, among other things, files of the format .nc. Each of these files contains one year of model output in the standard PEcAn netCDF format. This is the model output that we will use to compare to data. 5.5.1.3 Read in settings From an XML file ## Read in the xml settings<-PEcAn.settings::read.settings("~/output/PEcAn_99000000001/pecan.CONFIGS.xml") ## To read in the model output runid<-as.character(read.table(paste(settings$outdir, "/run/","runs.txt", sep=""))[1,1]) # Note: if you are using an xml from a run with multiple ensembles this line will provide only the first run id outdir<- paste(settings$outdir,"/out/",runid,sep= "") start.year<-as.numeric(lubridate::year(settings$run$start.date)) end.year<-as.numeric(lubridate::year(settings$run$end.date)) site.id<-settings$run$site$id File_path<-"~/output/dbfiles/AmerifluxLBL_site_0-772/AMF_US-NR1_BASE_HH_9-1.csv" ## Open up a connection to The Bety Database con <- PEcAn.DB::db.open(settings$database$bety) 5.5.1.4 Read in model output from specific variables model_vars<-c("time", "NEE") #varibles being read model <- PEcAn.utils::read.output(runid,outdir,start.year, end.year, model_vars,dataframe=TRUE) The arguments to read.output are the run ID, the folder where the run is located, the start year, the end year, and the variables being read. The README file in the Input file dropdown menu of any successful run lists the run ID, the output folder, and the start and end year. 5.5.1.5 Compare model to flux observations First load up the observations and take a look at the contents of the file File_format<-PEcAn.DB::query.format.vars(bety = con, format.id = 5000000002) #This matches the file with a premade "format" or a template that describes how the information in the file is organized site<-PEcAn.DB::query.site(site.id, con) #This tells PEcAn where the data comes from observations<-PEcAn.benchmark::load_data(data.path = File_path, format= File_format, time.row = File_format$time.row, site = site, start_year = start.year, end_year = end.year) #This will throw an error that not all of the units can be converted. That's ok, as the units of the varibles of interest (NEE) are being converted. File_Path refers to where you stored your observational data. In this example the default file path is an Ameriflux dataset from Niwot Ridge. File_format queries the database for the format your file is in. The default format ID “5000000002” is for csv files downloaded from the Ameriflux website. You could query for diffent kinds of formats that exist in bety or make your own. Here 772 is the database site ID for Niwot Ridge Forest, which tells pecan where the data is from and what time zone to assign any time data read in. Second apply a conservative u* filter to observations observations$NEE[observations$UST<0.2]<-NA Third align model output and observations aligned_dat = PEcAn.benchmark::align_data(model.calc = model, obvs.calc = observations, var ="NEE", align_method = "match_timestep") When we aligned the data, we got a dataframe with the variables we requested in a \\(NEE.m\\) and a \\(NEE.o\\) format. The \\(.o\\) is for observations, and the \\(.m\\) is for model. The posix column allows for easy plotting along a timeseries. Fourth, plot model predictions vs. observations and compare this to a 1:1 line ## predicted vs observed plot plot(aligned_dat$NEE.m, aligned_dat$NEE.o) abline(0,1,col="red") ## intercept=0, slope=1 Fifth, calculate the Root Mean Square Error (RMSE) between the model and the data rmse = sqrt(mean((aligned_dat$NEE.m-aligned_dat$NEE.o)^2,na.rm = TRUE)) na.rm makes sure we don’t include missing or screened values in either time series. Finally, plot time-series of both the model and data together ## plot aligned data plot(aligned_dat$posix, aligned_dat$NEE.o, type="l") lines(aligned_dat$posix,aligned_dat$NEE.m, col = "red") Bonus How would you compare aggregated data? Try RMSE against monthly NEE instead of half-hourly. In this case, first average the values up to monthly in the observations. Then, use align_data to match the monthly timestep in model output. NOTE: Align_data uses two seperate alignment function, match_timestep and mean_over_larger_timestep. Match_timestep will use only that data that is present in both the model and the observation. This is helpful for sparse observations. Mean_over_larger_timestep aggregates the values over the largest timestep present. If you were to look at averaged monthly data, you would use mean_over_larger_timestep. monthlyNEEobs<-aggregate(observations, by= list(month(observations$posix)), simplify=TRUE, FUN =mean, na.rm= TRUE) plottable<-align_data(model.calc = model, obvs.calc = monthlyNEEobs, align_method = "mean_over_larger_timestep", var= "NEE") head(plottable) 5.5.2 Data Assimilation Concepts The goal of this tutorial is to help you gain some hands-on familiarity with some of the concepts, tools, and techniques involved in Bayesian Calibration. As a warm-up to more advanced approaches to model-data fusion involving full ecosystem models, this example will focus on fitting the Farquhar, von Caemmerer, and Berry (1980) photosynthesis model [FvCB model] to leaf-level photosynthetic data. This is a simple, nonlinear model consisting of 3 equations that models net carbon assimilation, \\(A^{(m)}\\), at the scale of an individual leaf as a function of light and CO2. \\[A_j = \\frac{\\alpha Q}{\\sqrt{1+(\\alpha^2 Q^2)/(Jmax^2)}} \\frac{C_i- \\Gamma}{4 C_i + 8 \\Gamma}\\] \\[A_c = V_{cmax} \\frac{C_i - \\Gamma}{C_i+ K_C (1+[O]/K_O) }\\] \\[A^{(m)} = min(A_j,A_c) - r\\] The first equation \\(A_j\\) describes the RUBP-regeneration limited case. In this equation the first fraction is a nonrectangular hyperbola predicting \\(J\\), the electron transport rate, as a function of incident light \\(Q\\), quantum yield \\(\\alpha\\), and the assymptotic saturation of \\(J\\) at high light \\(J_{max}\\). The second equation, \\(A_c\\), describes the Rubisco limited case. The third equation says that the overall net assimilation is determined by whichever of the two above cases is limiting, minus the leaf respiration rate, \\(r\\). To keep things simple, as a Data Model (a.k.a. Likelihood or Cost Function) we’ll assume that the observed leaf-level assimilation \\(A^{(o)}\\) is Normally distributed around the model predictions with observation error \\(\\tau\\). \\[A^{(o)} \\sim N(A^{(m)},\\tau)\\] To fit this model to data we’re going to rely on a piece of statistical software known as JAGS. The above model would be written in JAGS as: model{ ## Priors Jmax ~ dlnorm(4.7,2.7) ## maximum electron transport rate prior alpha~dnorm(0.25,100) ##quantum yield (mol electrons/mole photon) prior vmax ~dlnorm(4.6,2.7) ## maximum rubisco capacity prior r ~ dlnorm(0.75,1.56) ## leaf respiration prior cp ~ dlnorm(1.9,2.7) ## CO2 compensation point prior tau ~ dgamma(0.1,0.1) for(i in 1:n){ ## electron transport limited Aj[i]<-(alpha*q[i]/(sqrt(1+(alpha*alpha*q[i]*q[i])/(Jmax*Jmax))))*(pi[i]-cp)/(4*pi[i]+8*cp) ## maximum rubisco limited without covariates Ac[i]<- vmax*(pi[i]-cp)/(pi[i]+Kc*(1+po/Ko)) Am[i]<-min(Aj[i], Ac[i]) - r ## predicted net photosynthesis Ao[i]~dnorm(Am[i],tau) ## likelihood } } The first chunk of code defines the prior probability distributions. In Bayesian inference every unknown parameter that needs to be estimated is required to have a prior distribution. Priors are the expression of our belief about what values a parameter might take on prior to observing the data. They can arise from many sources of information (literature survey, meta-analysis, expert opinion, etc.) provided that they do not make use of the data that is being used to fit the model. In this particular case, the priors were defined by Feng and Dietze 2013. Most priors are lognormal or gamma, which were choosen because most of these parameters need to be positive. After the priors is the Data Model, which in JAGS needs to be implemented as a loop over every observation. This is simply a codified version of the earlier equations. Table 1: FvCB model parameters in the statistical code, their symbols in equations, and definitions Parameter Symbol Definition alpha0 \\(\\alpha\\) quantum yield (mol electrons/mole photon) Jmax \\(J_{max}\\) maximum electron transport cp \\(\\Gamma\\) CO2 compensation point vmax0 \\(V_{cmax}\\) maximum Rubisco capacity (a.k.a Vcmax) r \\(R_d\\) leaf respiration tau \\(\\tau\\) residual precision q \\(Q\\) PAR pi \\(C_i\\) CO2 concentration 5.5.2.1 Fitting the model To begin with we’ll load up an example A-Ci and A-Q curve that was collected during the 2012 edition of the Flux Course at Niwot Ridge. The exact syntax below may be a bit confusing to those unaccustomed to R, but the essence is that the filenames line is looking up where the example data is stored in the PEcAn.photosynthesis package and the dat line is loading up two files (once A-Ci, the other A-Q) and concatanating them together. library(PEcAn.photosynthesis) ### Load built in data filenames <- system.file("extdata", paste0("flux-course-3",c("aci","aq")), package = "PEcAn.photosynthesis") dat<-do.call("rbind", lapply(filenames, read_Licor)) ## Simple plots aci = as.character(dat$fname) == basename(filenames[1]) plot(dat$Ci[aci],dat$Photo[aci],main="ACi") plot(dat$PARi[!aci],dat$Photo[!aci],main="AQ") In PEcAn we’ve written a wrapper function, \\(fitA\\), around the statistical model discussed above, which has a number of other bells and whistles discussed in the PEcAn Photosynthesis Vignette. For today we’ll just use the most basic version, which takes as arguments the data and the number of MCMC iterations we want to run. fit <- fitA(dat,model=list(n.iter=10000)) 5.5.2.2 What’s going on Bayesian numerical methods for model calibration are based on sampling parameter values from the posterior distribution. Fundamentally what’s returned is a matrix, with the number of iterations as rows and the number of parameters as columns, which are samples from the posterior distribution, from which we can approximate any quantity of interest (mean, median, variance, CI, etc.). The following plots follow the trajectory of two correlated parameters, Jmax and alpha. In the first figure, arrows show the first 10 iterations. Internally JAGS is choosing between a variety of different Bayesian sampling methods (e.g. Metropolis-Hasting, Gibbs sampling, slice sampling, rejection sampling, etc) to draw a new value for each parameter conditional on the current value. After just 10 steps we don’t have a good picture of the overall posterior, but it should still be clear that the sampling is not a complete random walk. params <- as.matrix(fit$params) xrng = range(fit$params[,"alpha0"]) yrng = range(fit$params[,"Jmax0"]) n = 1:10 plot(params[n,"alpha0"],params[n,"Jmax0"],type='n',xlim=xrng,ylim=yrng) arrows(params[n[-10],"alpha0"],params[n[-10],"Jmax0"],params[n[-1],"alpha0"],params[n[-1],"Jmax0"],length=0.125,lwd=1.1) After 100 steps, we can see a cloud start to form, with occassional wanderings around the periphery. n = 1:100 plot(params[n,"alpha0"],params[n,"Jmax0"],type='l',xlim=xrng,ylim=yrng) After \\(nrow(params)\\) steps what we see is a point cloud of samples from the joint posterior distribution. When viewed sequentially, points are not independent, but we are interested in working with the overall distribution, where the order of samples is not important. n = 1:nrow(params) plot(params[n,"alpha0"],params[n,"Jmax0"],type='p',pch="+",cex=0.5,xlim=xrng,ylim=yrng) 5.5.2.3 Evaluating the model output A really important aspect of Bayesian inference is that the output is the joint posterior probability of all the parameters. This is very different from an optimization approach, which tries to find a single best parameter value. It is also different from estimating the independent posterior probabilities of each parameter – Bayesian posteriors frequently have strong correlation among parameters for reasons having to do both with model structure and the underlying data. The model we’re fitting has six free parameters, and therefore the output matrix has 6 columns, of which we’ve only looked at two. Unfortunately it is impossible to visualize a 6 dimensional parameter space on a two dimensional screen, so a very common practice (for models with a small to medium number of parameters) is to look at all pairwise scatterplots. If parameters are uncorrelated we will typically see oval shaped clouds that are oriented in the same directions as the axes. For parameters with linear correlations those clouds will be along a diagonal. For parameters with nonlinear trade-offs the shapes of the parameter clouds can be more complex, such as the banana-shaped or triangular. For the FvCB model we see very few parameters that are uncorrelated or have simple linear correlations, a fact that we should keep in mind when interpreting individual parameters. pairs(params,pch=".") The three most common outputs that are performed on almost all Bayesian analyses are to look at the MCMC chains themselves, the marginal distributions of each parameter, and the overall summary statistics. The ‘trace’ diagrams below show the history of individual parameters during the MCMC sampling. There are different color lines that represent the fact that JAGS ran the MCMC multiple times, with each run (i.e. each color) being refered to as a different \\(chain\\). It is common to run multiple chains in order to assess whether the model, started from different points, consistently converges on the same answer. The ideal trace plot looks like white noise with all chains in agreement. The ‘density’ figures represent smoothed versions of the marginal distributions of each parameter. The tick marks on the x-axis are the actual samples. You will note that some posteriors will look approximately Normal, while others may be skewed or have clearly defined boundaries. On occassion there will even be posteriors that are multimodal. There is no assumption built into Bayesian statistics that the posteriors need be Normal, so as long as an MCMC has converged this diversity of shapes is valid. [note: the most common cause of multi-modal posteriors is a lack of convergence] Finally, the summary table reports, for each parameter, a mean, standard deviation, two variants of standard error, and standard quantile estimates (95% CI, interquartile, and median). The standard deviation of the posterior is a good summary statistic about how uncertain we are about a parameter. The Naive SE is the traditonal \\(\\frac{SD}{\\sqrt{n}}\\), which is an estimate of the NUMERICAL accuracy in our estimate of the mean. As we run the MCMC longer (i.e. take more samples), we get an answer that is numerically more precise (SE converges to 0) but the uncertainty in the parameter (i.e. SD) stays the same because that’s determined by the sample size of the DATA not the length of the MCMC. Finally, the Time-series SE is a variant of the SE calculation that accounts for the autocorrelation in the MCMC samples. In practice is is therefore more appropriate to use this term to assess numerical accuracy. plot(fit$params,auto.layout = FALSE) ## MCMC diagnostic plots summary(fit$params) ## parameter estimates Assessing the convergence of the MCMC is first done visually, but more generally the use of statistical diagnostics to assess convergence is highly encouraged. There are a number of metrics in the literature, but the most common is the Gelman-Brooks-Rubin statistic, which compare the variance within each chain to the variance across chains. If the chains have converged then this quantity should be 1. Values less than 1.05 are typically considered sufficient by most statisticians, but these are just rules-of-thumb. gelman.plot(fit$params,auto.layout = FALSE) gelman.diag(fit$params) As with any modeling, whether statistical or process-based, another common diagnostic is a predicted vs observed plot. In a perfect model the data would fall along the 1:1 line. The deviations away from this line are the model residuals. If observations lie along a line other than the 1:1 this indicates that the model is biased in some way. This bias is often assessed by fitting a linear regression to the points, though two important things are noteworthy about this practice. First, the \\(R^2\\) and residual error of this regression are not the appropriate statistics to use to assess model performance (though you will frequently find them reported incorrectly in the literature). The correct \\(R^2\\) and residual error (a.k.a Root Mean Square Error, RMSE) are based on deviations from the 1:1 line, not the regression. The code below shows these two terms calculated by hand. The second thing to note about the regression line is that the standard regression F-test, which assesses deviations from 0, is not the test you are actually interested in, which is whether the line differs from 1:1. Therefore, while the test on the intercept is correct, as this value should be 0 in an unbiased model, the test statistic on the slope is typically of less interest (unless your question really is about whether the model is doing better than random). However, this form of bias can easily be assessed by looking to see if the CI for the slope overlaps with 1. ## predicted vs observed plot par(mfrow=c(1,1)) mstats = summary(fit$predict) pmean = mstats$statistics[grep("pmean",rownames(mstats$statistics)),1] plot(pmean,dat$Photo,pch="+",xlab="Predicted A",ylab = "Observed A") abline(0,1,col=2,lwd=2) bias.fit = lm(dat$Photo~pmean) abline(bias.fit,col=3,lty=2,lwd=2) legend("topleft",legend=c("1:1","regression"),lwd=2,col=2:3,lty=1:2) summary(bias.fit) RMSE = sqrt(mean((pmean-dat$Photo)^2)) RMSE R2 = 1-RMSE^2/stats::var(dat$Photo) R2 confint(bias.fit) In the final set of plots we look at the actual A-Ci and A-Q curves themselves. Here we’ve added two interval estimates around the curves. The CI captures the uncertainty in the parameters and will asympotically shrink with more and more data. The PI (predictive interval) includes the parameter and residual error. If our fit is good then 95% PI should thus encompass at least 95% of the observations. That said, as with any statistical model we want to look for systematic deviations in the residuals from either the mean or the range of the PI. ## Response curve plot_photo(dat,fit) Note: on the last figure you will get warnings about “No ACi” and “No AQ” which can be ignored. These are occuring because the file that had the ACi curve didn’t have an AQ curve, and the file that had the AQ curve didn’t have an ACi curve. 5.5.2.4 Additional information There is a more detailed R Vignette on the use of the PEcAn photosynthesis module available in the PEcAn Repository. 5.5.2.5 Citations Dietze, M.C. (2014). Gaps in knowledge and data driving uncertainty in models of photosynthesis. Photosynth. Res., 19, 3–14. Farquhar, G., Caemmerer, S. & Berry, J.A. (1980). A biochemical model of photosynthetic CO2 assimilation in leaves of C3 species. Planta, 149, 78–90. Feng, X. & Dietze, M.C. (2013). Scale dependence in the effects of leaf ecophysiological traits on photosynthesis: Bayesian parameterization of photosynthesis models. New Phytol., 200, 1132–1144. 5.5.3 Parameter Data Assimilation 5.5.3.1 Objectives Gain hands-on experience in using Bayesian MCMC techniques to calibrate a simple ecosystem model using parameter data assimilation (PDA) Set up and run a PDA in PEcAn using model emulation technique, assimilating NEE data from Niwot Ridge Examine outputs from a PDA for the SIPNET model and evaluation of the calibrated model against i) data used to constrain model, ii) additional data for the same site 5.5.3.2 Larger Context Parameter data assimilation (PDA) occurs as one step in the larger process of model calibration, validation, and application. The goal of PDA is to update our estimates of the posterior distributions of the model parameters using data that correspond to model outputs. This differs from our previous use of PEcAn to constrain a simple model using data that map directly to the model parameters. Briefly, the recommended overall approach for model calibration and validation consists of the following steps: Assemble and process data sets required by the model as drivers Perform an initial test-run of the model as a basic sanity check Were there errors in drivers? (return to 1) Is the model in the same ballpark as the data? Construct priors for model parameters Collect/assemble the data that can be used to constrain model parameters and outputs Meta-analysis Sensitivity analysis (SA) Variance Decomposition (VD) Determine what parameters need further constraint Does this data exist in the literature? (repeat 4-8) Can I collect this data in the field? (repeat 4-8) Ensemble Analysis Is reality within the range of the uncertainty in the model? Evaluate/estimate uncertainties in the data Parameter Data Assimilation: Propose new parameter values Evaluate L(data | param) & prior(param) Accept or reject the proposed parameter values Repeat many times until a histogram of accepted parameter values approximates the true posterior distribution. Model evaluation [preferably ensemble based] Against data used to constrain model Against additional data for this site Same variable, different time Different variables Against data at a new site Do I need more data? Repeat 4-9 (direct data constraint) or 6-11 (parameter data assimilation). Application [preferably ensemble forecast or hindcast] 5.5.3.3 Connect to Rstudio Today, we’re again going to work mostly in Rstudio, in order to easily edit advanced PEcAn settings and browse files. So if you haven’t already, connect now to the Rstudio server on your VM ([URL]/rstudio). This tutorial assumes you have successfully completed an ensemble and a sensitivity analysis (Demo 2) before. 5.5.3.4 Defining variables The following variables need to be set specific to the site being run and the workflow being run workflow_id <- 99000000002 ## comes from the History table, your successful ensemble run's workflow ID ## from URL/bety/inputs. ## Search by Ameriflux ID (e.g. US-NR1) ## Find the "plain" site record (no CF or model name) that's on your server ## (probably last in the list) ## Click on the magnifying glass icon then look under "View Related Files" datadir <- "/home/carya/output/dbfiles/AmerifluxLBL_site_0-772/" ## where PEcAn is saving output (default OK on VM) outdir <- "/home/carya/output/" 5.5.3.5 Initial Ensemble Analysis A good place to start when thinking about a new PDA analysis is to look at the current model fit to observed data. In fact, we want to compare data to a full ensemble prediction from the model. This is important because our current parameter distributions will be the priors for PDA. While the analysis will translate these priors into more optimal (in terms of producing model output that matches observations) and more confident (i.e. narrower) posterior distributions, these results are inherently constrained by the current parameter distributions. Thus, if reality falls far outside the prior ensemble confidence interval (which reflects the current uncertainty of all model parameters), data assimilation will not be able to fix this. In such cases, the prior parameter estimates must already be over-constrained, or there are structural errors in the model itself that need fixing. To begin, let’s load up some NEE observations so that we can plot them along with our ensemble predictions. In the code below the elements in bold may vary depending on site and your previous runs. library(PEcAn.all) # read settings settings <- read.settings(file.path(outdir,paste0("PEcAn_",workflow_id),"pecan.CONFIGS.xml")) # open up a DB connection con <- PEcAn.DB::db.open(settings$database$bety) # Fill out the arguments needed by load_data function # read file format information format <- PEcAn.DB::query.format.vars(bety = con, format.id = 5000000002) start_year <- lubridate::year(settings$run$start.date) end_year <- lubridate::year(settings$run$end.date) vars.used.index <- which(format$vars$bety_name %in% c("NEE", "UST")) obs <-PEcAn.benchmark::load_data(data.path = file.path(datadir, "AMF_US-NR1_BASE_HH_9-1.csv"), format = format, start_year = start_year, end_year = end_year, site = settings$run$site, vars.used.index = vars.used.index, time.row = format$time.row) obs$NEE[obs$UST<0.4] <- NA ## U* filter NEEo <- obs$NEE Now let’s load up our ensemble outputs from the previous ensemble analysis (Demo 2) and plot our ensemble predictions against our NEE observations. # load outputs, try not to delete prePDA ensemble output filename from your environment prePDA_ensemble_output_file <- file.path(outdir,paste0("PEcAn_",workflow_id, "/ensemble.ts.", settings$ensemble$ensemble.id, ".NEE.2003.2006.Rdata")) load(prePDA_ensemble_output_file) # calculate CI pre_pda_ens <- ensemble.ts[["NEE"]] preCI <- apply(pre_pda_ens, 2, quantile, c(0.025, 0.5, 0.975), na.rm = TRUE) # plot model ensemble ymin <- min(min(c(preCI, NEEo), na.rm = TRUE)) ymax <- max(max(c(preCI, NEEo), na.rm = TRUE)) plot(preCI[2,], ylim = c(ymin, ymax), lwd = 2, xlab = "time", ylab = "NEE", main = "pre-PDA model ensemble vs data", type = "n") prepoly <- 1:dim(preCI)[2] polygon(c(prepoly, rev(prepoly)), c(preCI[3,], rev(preCI[1,])), col='khaki', border=NA) # add data points(NEEo, pch = ".", col= adjustcolor("purple",alpha.f=0.5)) legend("topright", legend=c("Data","Pre-PDA Model"), pch=c(15,15), col=c("purple","khaki")) When interpreting your results it is important to remember the difference between a confidence interval, which just includes parameter uncertainties, and a predictive interval, which includes parameter and residual uncertainties. Your ensemble analysis plot illustrates the former—i.e., the confidence in the mean NEE. By contrast, the data reflect both changes in mean NEE, and random variability. As such, we can’t expect all the data to fall within the CI; in fact, if we had unlimited data to constrain mean NEE, the CI would collapse to a single line and none of the data would be contained! However, your plot will give you an idea of how much uncertainty there is in your model currently, and help to identify systematic errors like bias (values consistently too high or low) or poorly represented seasonal patterns. 5.5.3.6 Questions: Does your ensemble agree well with the data? If so, how much room for improvement is there, in terms of tightening the CI? If not, what are the greatest discrepancies? What are some of the problems (with model, data, and/or PEcAn) that might explain the data-model disparity you see? 5.5.3.7 Choosing Parameters Beyond exploratory exercises, the first step of PDA analysis is to choose the model parameters you will target for optimization. PDA is computationally expensive (even when using an emulator), and the cost increases exponentially with the number of parameters targeted. The number you can handle in any given analysis completely depends on the complexity of the model and your available computational resources, but in practice it’s going to be rather small (~1–10) relative to the large number of parameters in a mechanistic ecosystem model (~10–100). Given this limitation, it is important to target parameters that can contribute substantially to improving model fit. If you recall, identifying those parameters was the goal of the uncertainty analysis you conducted previously, in the second PEcAn demo. Let’s revisit that analysis now. Open your variance decomposition graph from Demo 2 From this figure decide which variables you will target with PDA. As noted, an obvious criterion is that the parameter should be contributing a large amount of uncertainty to the current model, because otherwise it simply can’t change the model output much no matter how much you try to optimize it. But there are other considerations too. For example, if two parameters have similar or competing roles in the model, you may have trouble optimizing both simultaneously. In practice, there will likely be some guess-and-testing involved, though a good understanding of how the model works will help. It may also help to look at the shape of the Sensitivity responses and details of model fit to data (your ensemble analysis from the previous section). For the purposes of this demo, choose eight to ten parameters (in total, if you have more than one PFT) that contribute high uncertainty to model output and/or seem like good choices for some other rational reason. 5.5.3.8 Questions: Which parameters did you choose, and why? 5.5.3.9 Editing PEcAn settings Now let’s add settings to tell PEcAn how to run the PDA with emulator, we will come to the details of model emulation later. Open up the pecan.CONFIGS.xml file you located previously, and choose File > Save as... from the menu to save a new copy as pecan.PDA.xml. Now add the block of XML listed below to the file, immediately after the line. Check and fill in the parts corresponding to your run when necessary. In this block, use the <param.names><param> tags to identify the parameters you’ve chosen for PDA (it’s up to you to choose the number of parameters you want to constrain, then you can set the <n.knot> to be >= 10 per parameter you choose, e.g. 200 knots for 10 parameters). Here, you need to use PEcAn’s standard parameter names, which are generally not the same as what’s printed on your variance decomposition graph. To find your parameters look at the row names in the prior.distns.csv file for each PFT under the PFT pulldown menu. Insert the variable name (exactly, and case sensitive) into the <param> tags of the XML code below. In addition, you may need to edit <inputs><file><path>, depending on the site and year you ran previously. The rest of the settings control options for the PDA analysis (how long to run, etc.), and also identify the data to be used for assimilation. For more details, see the assim.batch vignette on the PEcAn GitHub page (https://goo.gl/9hYVPQ). <?xml version="1.0"?> <-- These lines are already in there. Don't duplicate them, <pecan> <-- just paste the <assim.batch> block below right after them. <assim.batch> <method>emulator</method> <n.knot>160</n.knot> <-- FILL IN <iter>25000</iter> <chain>3</chain> <param.names> <soil> <param>YOUR_PFT_1_PARAM_1</param> <-- FILL IN <param>YOUR_PFT_1_PARAM_2</param> <-- FILL IN </soil> <temperate.coniferous> <param>YOUR_PFT_2_PARAM_1</param> <-- FILL IN <param>YOUR_PFT_2_PARAM_2</param> <-- FILL IN <param>YOUR_PFT_2_PARAM_3</param> <-- FILL IN <param>YOUR_PFT_2_PARAM_4</param> <-- FILL IN <param>YOUR_PFT_2_PARAM_5</param> <-- FILL IN <param>YOUR_PFT_2_PARAM_6</param> <-- FILL IN </temperate.coniferous> </param.names> <jump> <adapt>100</adapt> <adj.min>0.1</adj.min> <ar.target>0.3</ar.target> </jump> <inputs> <file> <path> <path>/home/carya/output/dbfiles/AmerifluxLBL_site_0-772/AMF_US-NR1_BASE_HH_9-1.csv</path> </path> <format>5000000002</format> <input.id>1000011238</input.id> <-- FILL IN, from BETY inputs table, this is *NOT* the workflow ID <likelihood>Laplace</likelihood> <variable.name> <variable.name>NEE</variable.name> <variable.name>UST</variable.name> </variable.name> <variable.id>297</variable.id> </file> </inputs> </assim.batch> Once you’ve made and saved the changes to your XML, load the file and check that it contains the new settings: settings <- read.settings(file.path(outdir,paste0("PEcAn_",workflow_id),"pecan.PDA.xml")) settings$assim.batch If the printed list contains everything you just added to pecan.PDA.xml, you’re ready to proceed. 5.5.3.10 Investigating PEcAn function pda.emulator (optional) Before we run the data assimilation, let’s take a high-level look at the organization of the code. Use the Rstudio file browser to open up ~/pecan/modules/assim.batch/R/pda.emulator.R. This code works in much the same way as the pure statistical models that we learned about earlier in the week, except that the model being fit is a statistical model that emulates a complicated process-based computer simulation (i.e., an ecosystem model). We could have directly used the ecosystem model (indeed PEcAn’s other PDA functions perform MCMC by actually running the ecosystem model at each iteration, see pda.mcmc.R script as an example), however, this would require a lot more computational time than we have today. Instead here we will use a technique called model emulation. This technique allows us to run the model for a relatively smaller number of times with parameter values that have been carefully chosen to give a good coverage of parameter space. Then we can interpolate the likelihood calculated for each of those runs to get a surface that “emulates” the true likelihood and perform regular MCMC, except instead of actually running the model on every iteration to get a likelihood, this time we will just get an approximation from the likelihood emulator. The general algorithm of this method can be further expressed as: Propose initial parameter set sampling design Run full model for each parameter set Evaluate the likelihoods Construct emulator of multivariate likelihood surface Use emulator to estimate posterior parameter distributions (Optional) Refine emulator by proposing new design points, goto 2) For now, we just want you to get a glimpse at the overall structure of the code, which is laid out in the comment headers in pda.emulator(). Most of the real work gets done by the functions this code calls, which are all located in the file ~/pecan/modules/assim.batch/R/pda.utils.R and the MCMC will be performed by the mcmc.GP() function in ~/pecan/modules/emulator/R/minimize.GP.R. To delve deeper into how the code works, take a look at these files when you have the time. 5.5.3.11 Running a demo PDA Now we can go ahead and run a data assimilation MCMC with emulator. Since you’ve already loaded the settings containing your modified <assim.batch> XML block, all you need to do to start the PDA is run pda.emulator(settings). But, in the emulator workflow, there is a bit of a time consuming step where we calculate the effective sample size of the input data, and we have already done this step for you. You could load it up and pass it to the function explicitly in order to skip this step: # load input data load("/home/carya/pda/pda_externals.Rdata") postPDA.settings <- pda.emulator(settings, external.data = inputs_w_neff) After executing the code above, you will see print-outs to the console. The code begins with loading the prior values which in this case are the posterior distributions coming from your previous meta analysis. Then, normally, it loads the observational data and carries out necessary conversions and formatting to align it with model outputs, as we did separately above, but today it will skip this step as we are passing data externally. After this step, you will see a progress bar where the actual model is run n.knot times with the proposed parameter sets and then the outputs from these runs are read. Next, this model output is compared to the specified observational data, and the likelihood is calculated using the heteroskedastic Laplacian discussed previously. Once we calculate the likelihoods, we fit an emulator which interpolates the model output in parameter space between the points where the model has actually been run. Now we can put this emulator in the MCMC algorithm instead of the model itself. Within the MCMC loop the code proposes new parameter value from a multivariate normal jump distribution. The corresponding likelihood will be approximated by the emulator and the new parameter value is accepted or rejected based on its posterior probability relative to the current value. 5.5.3.12 Outputs from PEcAn’s Parameter Data Assimilation When the PDA is finished, a number of outputs are automatically produced that are either the same as or similar to posterior outputs that we’ve seen before. These are located in the PEcAn_[workflow_id]/pft/* output directory and are identified by pda.[PFT]_[workflow_id] in the filenames: posteriors.pda.[PFT]*.pdf shows the posterior distributions resulting from your PDA trait.mcmc.pda.[PFT]*.Rdata contains all the parameter samples contained in the PDA posterior mcmc.pda.[PFT]*.Rdata is essentially the same thing in a different format mcmc.diagnostics.pda.[PFT]*.pdf shows trace plots and posterior densities for each assimilated parameter, as well as pairs plots showing all pairwise parameter correlations. Together, these files allow you to evaluate whether a completed PDA analysis has converged and how the posterior distributions compare to the priors, and to use the posterior samples in further analyses, including additional PDA. If you haven’t done so already, take a look at all of the outputs described here. 5.5.3.13 Questions: Do the diagnostic figures indicate that your likelihood at least improved over the course of the analysis? Does the MCMC appear to have converged? Are the posterior distributions well resolved? 5.5.3.14 Post-PDA analyses In addition to the outputs of the PDA itself, you may want to conduct ensemble and/or sensitivity analyses based on the posteriors of the data assimilation, in order to check progress towards improved model fit and/or changing sensitivity. For this, you need to generate new model runs based on parameters sampled from the updated (by PDA) posterior, which is a simple matter of rerunning several steps of the PEcAn workflow. The PDA you ran has automatically produced an updated XML file (pecan.pda***.xml) that includes the posterior id to be used in the next round of runs. Locate this file in your run directory and load the file for the post-pda ensemble/sensitivity analysis (if you already have the settings list in your working environment you don’t need to re-read the settings): # read post-PDA settings if you don't have them in your wotking environment # replace the *** with the ensemble id given by the workflow # postPDA.settings <- read.settings(file.path(outdir,paste0("PEcAn_", workflow_id),"pecan.pda***.xml")) # Call model specific write.configs postPDA.settings <- run.write.configs(postPDA.settings, write=postPDA.settings$database$bety$write, ens.sample.method=postPDA.settings$ensemble$method) # Let's save the settings with the new ensemble id PEcAn.settings::write.settings(settings, outputfile=paste0('pecan.pda', postPDA.settings$assim.batch$ensemble.id,'.xml')) # Start ecosystem model runs, this one takes awhile... PEcAn.workflow::start_model_runs(postPDA.settings, postPDA.settings$database$bety$write) # Get results of model runs get.results(postPDA.settings) # Repeat ensemble analysis with PDA-constrained params run.ensemble.analysis(postPDA.settings, TRUE) # let's re-load the pre-PDA ensemble outputs load(prePDA_ensemble_output_file) pre_pda_ens <- ensemble.ts[["NEE"]] # nowload the post-PDA ensemble outputs postPDA_ensemble_output_file <- file.path(outdir,paste0("PEcAn_", workflow_id, "/ensemble.ts.", postPDA.settings$ensemble$ensemble.id, ".NEE.2003.2006.Rdata")) load(postPDA_ensemble_output_file) post_pda_ens <- ensemble.ts[["NEE"]] # try changing the window value for daily, weekly, monthly smoothing later # see if this changes your model-data agreement, why? window <- 1 # no smoothing pre_pda <- t(apply(pre_pda_ens, 1, function(x) { tapply(x, rep(1:(length(x)/window + 1), each = window)[1:length(x)], mean, na.rm = TRUE)})) post_pda <- t(apply(post_pda_ens, 1, function(x) { tapply(x, rep(1:(length(x)/window + 1), each = window)[1:length(x)], mean, na.rm = TRUE)})) fobs <- tapply(NEEo, rep(1:(length(NEEo) / window + 1), each = window)[1:length(NEEo)], mean, na.rm = TRUE) # save the comparison plots to pdf pdf(file.path(outdir,paste0("PEcAn_",workflow_id),"model.data.comparison.pdf"), onefile=T, paper='A4r', height=15, width=20) # now plot the pre-PDA ensemble similar to the way we did before preCI <- apply(pre_pda, 2, quantile, c(0.025, 0.5, 0.975), na.rm = TRUE) ymin <- min(min(c(preCI, fobs), na.rm = TRUE)) ymax <- max(max(c(preCI, fobs), na.rm = TRUE)) plot(pre_pda[1,], ylim = c(ymin, ymax), lwd = 2, xlab = "time", ylab = "NEE", main = "pre-PDA vs post-PDA", type = "n") prepoly <- 1:dim(preCI)[2] polygon(c(prepoly, rev(prepoly)),c(preCI[3,], rev(preCI[1,])),col='khaki',border=NA) # plot the post-PDA ensemble postCI <- apply(post_pda, 2, quantile, c(0.025, 0.5, 0.975), na.rm = TRUE) postpoly <- 1:dim(postCI)[2] polygon(c(postpoly, rev(postpoly)),c(postCI[3,], rev(postCI[1,])),col='lightblue',border=NA) # finally let's add the data and see how we did points(fobs, pch = ".", col= adjustcolor("purple",alpha.f=0.7)) legend("topright", legend=c("Data","Pre-PDA Model", "Post-PDA Model"), pch=c(15,15,15), col=c("purple","khaki","lightblue")) dev.off() # Repeat variance decomposition to see how constraints have changed run.sensitivity.analysis(postPDA.settings) Now you can check the new figures produced by your analyses under PEcAn_[workflow_id]/pft/*/variance.decomposition.*.pdf and PEcAn_[workflow_id]/pft/*/sensitivity.analysis.*.pdf, and compare them to the previous ones. Also, take a look at the comparison of model outputs to data when we run SIPNET with pre- and post-PDA parameter (mean) values under PEcAn_[workflow_id]/model.data.comparison.pdf. 5.5.3.15 Questions: Looking at the ensemble analysis outputs in order (i.e., in order of increasing ID in the filenames), qualitatively how did the model fit to data change over the course of the analysis? Based on the final ensemble analysis, what are the major remaining discrepancies between model and data? Can you think of the processes / parameters that are likely contributing to the differences? What would be your next steps towards evaluating or improving model performance? 5.5.4 State-Variable Data Assimilation 5.5.4.1 Objectives: Assimilate tree ring estimated NPP & inventory AGB within the SIPNET model in order to: Reconcile data and model NPP & AGB estimates Constrain inferences about other ecosystem responses. 5.5.4.2 Overview: Initial Run Settings Load and match plot and increment data Estimate tree-level data uncertainties Estimate allometric relationships Estimate stand-level NPP Sample initial conditions and parameters Run Ensemble Kalman Filter 5.5.4.3 Initial Run Perform a site-level SIPNET run using the following settings Site = UNDERC Start = 01/01/1979 End = 12/31/2015 Met = NARR Check Brown Dog When the run is complete, open the pecan.xml and cut-and-paste the outdir for later use 5.5.4.4 Settings: Open the PEcAn RStudio environment back up. Set your working directory to the outdir from above setwd(outdir) and shift the file browser to that location (Files > More > Go To Working Directory) Open up the latest settings file pecan.CONFIG.xml. At the top of the file add the following tags to set the ensemble size <state.data.assimilation> <n.ensemble>35</n.ensemble> <process.variance>FALSE</process.variance> <sample.parameters>TRUE</sample.parameters> <data> <format_id>1000000040</format_id> <input.id>1000013298</input.id> </data> <state.variables> <variable> <variable.name>NPP</variable.name> <unit>MgC/ha/yr</unit> <min_value>-9999</min_value> <max_value>9999</max_value> </variable> <variable> <variable.name>AbvGrndWood</variable.name> <unit>KgC/m^2</unit> <min_value>0</min_value> <max_value>9999</max_value> </variable> <variable> <variable.name>TotSoilCarb</variable.name> <unit>KgC/m^2</unit> <min_value>0</min_value> <max_value>9999</max_value> </variable> <variable> <variable.name>LeafC</variable.name> <unit>m^2/m^2</unit> <min_value>0</min_value> <max_value>9999</max_value> </variable> <variable> <variable.name>SoilMoistFrac</variable.name> <unit></unit> <min_value>0</min_value> <max_value>9999</max_value> </variable> <variable> <variable.name>SWE</variable.name> <unit>cm</unit> <min_value>0</min_value> <max_value>9999</max_value> </variable> <variable> <variable.name>Litter</variable.name> <unit>gC/m^2</unit> <min_value>0</min_value> <max_value>9999</max_value> </variable> </state.variables> <forecast.time.step>year</forecast.time.step> <start.date>1980/01/01</start.date> <end.date>2015/12/31</end.date> </state.data.assimilation> Delete the <pfts> block from the settings In the PEcAn History, go to your PDA run and open pecan.pda[UNIQUEID].xml (the one PEcAn saved for you AFTER you finished the PDA) Cut-and-paste the PDA <pfts> block into the SDA settings file Save the file as pecan.SDA.xml 5.5.4.5 Loading data If you have not done so already, clone (new) or pull (update) the PalEON Camp2016 repository Open a shell under Tools > Shell cd to go to your home directory To clone: git clone git@github.com:PalEON-Project/Camp2016.git To pull: cd Camp2016; git pull https://github.com/PalEON-Project/Camp2016.git master Open the tree-ring data assimilation workflow under Home > pecan > scripts > workflow.treering.R Run the script from the start up through the LOAD DATA section 5.5.4.6 Estimating tree-level data uncertainties One thing that is critical for data assimilation, whether it is being used to estimate parameters or state variables, is the careful consideration and treatment of the uncertainties in the data itself. For this analysis we will be using a combination of forest plot and tree ring data in order to estimate stand-level productivity. The basic idea is that we will be using the plot-sample of measured DBHs as an estimate of the size structure of the forest, and will use the annual growth increments to project that forest backward in time. Tree biomass is estimated using empirical allometric equations relating DBH to aboveground biomass. There are a number of sources of uncertainty in this approach, and before moving you are encouraged to think about and write down a few: Today we will use a statistical model based on the model developed by Clark et al 2007 that partitions out a number of sources of variability and uncertainty in tree ring and plot data (Fig 1). This model is a Bayesian statespace model that treats the true diameters (D) and increments (X) as latent variables that are connected through a fairly simple mixed effects process model \\[D_{ij,t+1} = D_{ij,t} + \\mu + \\alpha_{i} + \\alpha_t + \\epsilon_{ij,t}\\] where i = individual, j = plot, t = time (year). Each of these terms are represented at normal distributions, where \\(\\mu\\) is a fixed effect (overall mean growth rate) and individual and year are random effects \\[\\mu \\sim N(0.5,0.5)\\] \\[\\alpha_{i} \\sim N(0,\\tau_{i})\\] \\[\\alpha_{t} \\sim N(0,\\tau_{t})\\] \\[\\epsilon_{ij,t} \\sim N(0,\\tau_{e})\\] The connection between the true (latent) variable and the observations is also represented as normal with these variances representing measurement error: \\[D_{ij,t}^O \\sim N( D_{ij,t},\\tau_D)\\] \\[X_{ij,t}^O \\sim N( X_{ij,t},\\tau_r)\\] Finally, there are five gamma priors on the precisions, one for the residual process error (\\(\\tau_{e}\\)), two for the random effects on individual (\\(\\tau_{i}\\)) and time (\\(\\tau_t\\)), and two measurement errors or DBH (\\(\\tau_D\\)) and tree rings (\\(\\tau_r\\)) \\[\\tau_{e} \\sim Gamma(a_e,r_e)\\] \\[\\tau_{i} \\sim Gamma(a_i,r_i)\\] \\[\\tau_{t} \\sim Gamma(a_t,r_t)\\] \\[\\tau_{D} \\sim Gamma(a_D,r_D)\\] \\[\\tau_{r} \\sim Gamma(a_r,r_r)\\] This model is encapsulated in the PEcAn function: InventoryGrowthFusion(combined,n,iter) where the first argument is the combined data set formatted for JAGS and the second is the number of MCMC interations. The model itself is written for JAGS and is embedded in the function. Running the above InventoryGrowthFusion will run a full MCMC algorithm, so it does take a while to run. The code returns the results as an mcmc.list object, and the next line in the script saves this to the outputs directory We then call the function InventoryGrowthFusionDiagnostics to print out a set of MCMC diagnostics and example time-series for growth and DBH. 5.5.4.7 Allometric equations Aboveground NPP is estimated as the increment in annual total aboveground biomass. This estimate is imperfect, but not unreasonable for demonstration purposes. As mentioned above, we will take an allometric approach of scaling from diameter to biomass: Biomass = b0 * DBH b1 We will generate the allometric equation on a PFT level using another Bayesian model that synthesizes across a database of species-level allometric equations (Jenkins et al 2004). This model has two steps within the overall MCMC loop. First it simulates data from each equation, including both parameter and residual uncertainties, and then it updated the parameters of a single allometric relationship across all observations. The code also fits a second model, which includes a random site effect, but for simplicity we will not be using output from this version. Prior to running the model we have to first query the species codes for our pfts. Next we pass this PFT list to the model, AllomAve, which saves the results to the output directory in addition to returning a summary of the parameters and covariances. 5.5.4.8 Estimate stand-level NPP If we have no uncertainty in our data or allometric equations, we could estimate the stand aboveground biomass (AGB) for every year by summing over the biomass of all the trees in the plot and then divide by the plot area. We would then estimate NPP by the difference in AGB between years. One approach to propagating uncertainties into NPP would be to transform the distribution of DBH for each individual tree and year into a distribution for biomass, then sum over those distributions to get a distribution for AGB and then subtract the distributions to get the distributions of NPP. However, if we do this we will greatly overestimate the uncertainty in NPP because we ignore the fact that our increment data has much lower uncertainty than our diameter data. In essence, if we take a random draw from a distribution of AGB in year and it comes back above average, the AGB is much more likely to also be above average the following year than if we were to do an independent draw from that distribution. Accounting for this covariance requires a fairly simple change in our approach and takes advantage of the nature of the MCMC output. The basic idea is that we are going to take a random draw from the full individual x year diameter matrix, as well as a random draw of allometric parameters, and perform the ‘zero-error’ calculation approach described above. We will then create a distribution of all the NPP estimates that comes out of repeated draws for the full diameter matrix. This approach is encapsulated in the function plot2AGB. The argument unit.conv is a factor that combines both the area of the plot and the unit conversion from tree biomass (kg/tree) to stand AGB (Mg/ha). There are two outputs from plot2AGB: a pdf depicting estimated NPP and AGB (mean and 95% CI) time series, with each page being a plot; and plot2AGB.Rdata, a binary record of the function output that is read into the data assimilation code. The latter is also returned from the fuction and assigned to the variable “state”. Finally, we calculate the mean and standard deviation of NPP and save this as obs. 5.5.4.9 Build Initial Conditions The function sample.IC.SIPNET uses the AGB estimate from the previous function in order to initialize the data assimilation routine. Specifically it samples n.ensemble values from the first time step of the AGB estimate. Embedded in this function are also a number of prior distributions for other state variables, which are also samples in order to create a full set of initial conditions for SIPNET. 5.5.4.10 Load Priors The function sample.parameters samples values from the most recent posterior parameter distributions. You can also specify a specific set of parameters so sample from by specifying the argument <prior> within <assim.sequential> as the posterior.id you want to use. This is useful to know if you want to go back and run with the Meta-analysis posteriors, or if you end up rerunning the meta-analysis and need to go back and specify the parameter data assimilation posteriors instead of the most recent. 5.5.4.11 Ensemble Kalman Filter The function sda.enkf will run SIPNET in Ensemble Kalman Filter mode. The output of this function will be all the of run outputs, a PDF of diagnostics, and an Rdata object that includes three lists: FORECAST will be the ensemble forecasts for each year ANALYSIS will be the updated ensemble sample given the NPP observations enkf.params contains the prior and posterior mean vector and covariance matrix for each time step. If you look within this function you will find that much of the format is similar to the pda.mcmc function, but in general is much simpler. The function begins by setting parameters, opening a database connection, and generating workflow and ensemble ID’s. Next we split the SIPNET clim meteorology file up into individual annual files since we will be running SIPNET for a year at a time between updates. Next we perform an initial set of runs starting from the initial states and parameters we described above. In doing so we create the run and output directories, the README file, and the runs.txt file that is read by start_model_runs. Worth noting is that the README and runs.txt don’t need to be updated within the forecast loop. Given this initial run we then enter the forecast loop. Within this loop over years we perform four basic steps. First, we read the output from the latest runs. Second, we calculate the updated posterior state estimates based on the model ensemble prior and observation likelihood. Third, we resample the state estimates based on these posterior parameters. Finally, we start a new set of runs based on this sample. The sda.enfk function then ends by saving the outputs and generating some diagnostic figures. The first set of these shows the data, forecast, analysis. The second set shows pairs plots of the covariance structure for the Forecast and Analysis steps. The final set shows the time-series plots for the Analysis of the over state variables produced by SIPNET. 5.5.4.12 Finishing up The final bit of code in the script will register the workflow as complete in the database. After this is run you should be able to find all of the runs, and all of the outputs generated above, from within the PEcAn webpages. 5.5.5 PEcAn: Testing the Sensitivity Analysis Against Observations” 5.5.5.1 Author: “Ankur Desai” 5.5.5.2 Flux Measurements and Modeling Course, Tutorial Part 2 This tutorial assumes you have successfully completed the Demo01, Demo02 and the modelVSdata tutorial. 5.5.5.3 Introduction Now that you have successfully run PEcAn through the web interface and have learned how to do a simple comparison of flux tower observations to model output, let’s start looking at how data assimilation and parameter estimation would work with an ecosystem model. Before we start a full data assimilation exercise, let’s try something simple – single parameter selection by hand. Open http://localhost:3280/rstudio or http://localhost:6480/rstudio or the Amazon URL/rstudio if running on the cloud. In Demo02, you have ran a sensitivity analysis of SIPNET model runs at Niwot Ridge sampling across quantiles of a parameter prior, while holding all others to the median value. The pecan.xml file told PEcAn to run an sensitivity analysis, which simply meant SIPNET was run multiple times with the same driver, but varying parameter values one at a time (while holding all others to their median), and the parameter range also specified in the pecan.xml file (as quantiles, which were then sampled against the BETY database of observed variation in the parameter for species within the specific plant functional type). Let’s try to compare Ameriflux NEE to SIPNET NEE across all these runs to make a plot of parameter vs. goodness-of-fit. We’ll start with root mean square error (RMSE), but then discuss some other tests, too. 5.5.5.4 A. Read in settings object from a run xml Open up a connection to the bety database and create a settings object from your xml, just like in the modelVSdata tutorial. settings<-PEcAn.settings::read.settings("~/output/PEcAn_99000000002/pecan.CONFIGS.xml") con <- PEcan.DB::db.open(settings$database$bety) We read in the pecan.CONFIG.xml instead of the pecan.xml because the pecan.CONFIG.xml has already incorperated some of the information from the database we would have to query again if we used the pecan.xml. runid<-as.character(read.table(paste(settings$outdir, "/run/","runs.txt", sep=""))[1,1]) # Note: if you are using an xml from a run with multiple ensembles this line will provide only the first run id outdir<- paste(settings$outdir,"/out/",runid,sep= "") start.year<-as.numeric(lubridate::year(settings$run$start.date)) end.year<-as.numeric(lubridate::year(settings$run$end.date)) site.id<-settings$run$site$id Back to the files pane, within the run/ folder, find a folder called pft/ and within that a folder with the pft name (such as temprature.coniferous). Within that is a PDF file that starts sensitivity.analysis. In Rstudio, just click on the PDF to view it. You discussed this PDF last tutorial, through the web interface. Here, we see how the model NEE in SIPNET changes with each parameter. Let’s read that sensitivity output. Navigate back up (..) to the ~/output/RUNDIR/ folder. Find a series of files that end in “.RData”. These files contain the R variables used to make these plots. In particular, there is sensitivity.output..RData which contains the annual NEE as a function of each parameter quantile. Click on it to load a variable into your environment. There is sensitivity.results..RData which contains plotting functions and variance decomposition output, which we don’t need in this tutorial. And finally, there is **sensitivity.samples.*.RData** which contains the actual parameter values and the RunIDs associated with each sensitivity run. Click on sensitivity.samples..RData* to load it into your environment, or run the {r}load() script below. You should see a set of five new variables (pft.names, trait.names, sa.ensemble.id, sa.run.ids, sa.samples). Let’s extract a parameter and it’s sensitivity NEE output from the list sa.samples, which is organized by PFT, and then by parameter. First, let’s look at a list of PFTs and parameters available: load(paste(settings$outdir,"/sensitivity.samples.", settings$sensitivity.analysis$ensemble.id,".Rdata", sep="")) names(sa.samples) names(sa.samples$temperate.coniferous) Now to see the actual parameter values used by the runs, just pick a parameter and type: sa.samples$temperate.coniferous$psnTOpt Let’s store that value for future use: psnTOpt <- sa.samples$temperate.coniferous$psnTOpt Now, to see the annual NEE output from the model for a particular PFT and parameter range, try load(paste(settings$outdir,paste("/sensitivity.output", settings$sensitivity.analysis$ensemble.id,settings$sensitivity.analysis$variable,start.year,end.year,"Rdata", sep="."), sep="")) sensitivity.output$temperate.coniferous$psnTOpt You could even plot the two: plot(psnTOpt,sensitivity.output$temperate.coniferous$psnTOpt) What do you notice? Let’s try to read the output from a single run id as you did in the earlier tutorial. runids <- sa.run.ids$temperate.coniferous$psnTOpt arun <- PEcAn.utils::read.output(runids[1], paste(settings$outdir, "out", runids[1], sep="/"), start.year= start.year, end.year= end.year,"NEE", dataframe = TRUE) plot(arun$posix,arun$NEE) 5.5.5.5 B. Now let’s bring in the actual observations Recall reading Ameriflux NEE in the modelVSdata tutorial. File_path<-"~/output/dbfiles/AmerifluxLBL_site_0-772/AMF_US-NR1_BASE_HH_9-1.csv" File_format<-PEcAn.DB::query.format.vars(bety = con, format.id = 5000000002) #This matches the file with a premade "format" or a template that describes how the information in the file is organized site<-PEcAn.DB::query.site(site.id = site.id, con) obs<-PEcAn.benchmark::load_data(data.path = File_path, format= File_format, time.row = File_format$time.row, site = site, start_year = start.year, end_year = end.year) obs$NEE[obs$UST<0.2]<-NA #Apply a U* filter plottable<-align_data(model.calc = arun, obvs.calc = obs, align_method = "match_timestep", var= "NEE") head(plottable) 5.5.5.6 C. Finally, we can finally compare model to data In the modelVSdata, you also compared NEE to the ensemble model run. Here we will do the same except we include each sensitivity run. plot(plottable$NEE.m,plottable$NEE.o) abline(0,1,col="red") And remember the formula for RMSE: sqrt(mean((plottable$NEE.o-plottable$NEE.m)^2,na.rm = TRUE)) All we need to do to go beyond this is to make a loop that reads in each sensitivity run NEE based on runids, calculates RMSE against the observations, and stores it in an array, by combining the steps above in a for loop. Make sure you change the directory names and year to your specific run. rmses <- rep(0,length(runids)) for(r in 1:length(runids)){ arun <- read.output(runids[r],paste(settings$outdir, "out", runids[r], sep="/"),2004,2004,"NEE", dataframe= TRUE) plottable<-align_data(model.calc = arun, obvs.calc = obs, align_method = "match_timestep", var= "NEE") rmses[r] <- sqrt(mean((plottable$NEE.o-plottable$NEE.m)^2,na.rm = TRUE)) } rmses Let’s plot that array plot(psnTOpt,rmses) Can you identify a minimum (if there is one)? If so, is there any reason to believe this is the “best” parameter? Why or why not? Think about all the other parameters. Now that you have the hang of it, here are a few more things to try: Try a different error functions, given actual NEE uncertainty. You learned earlier that uncertainty in half-hourly observed NEE is not Gaussian. This makes RMSE not the correct measure for goodness-of-fit. Go to ~/pecan/modules/uncertainty/R, open flux_uncertainty.R, and click on the source button in the program editing pane. Alternatively, you can source the function from the console using: source("pecan/modules/uncertainty/R/flux_uncertainty.R") Then you can run: unc <- flux.uncertainty(plottable$NEE.o,QC=rep(0,17520)) plot_flux_uncertainty(unc) The figure shows you uncertainty (err) as a function of NEE magnitude (mag). How might you use this information to change the RMSE calculation? Try a few other parameters. Repeat the above steps but with a different parameter. You might want to select one from the sensitivity PDF that has a large sensitivity or from the variance decomposition that is also poorly constrained. "],["advanced-user.html", "5.6 Advanced User Guide", " 5.6 Advanced User Guide Workflow curl submission 5.6.1 Submitting Workflow from Command Line This is how you can submit a workflow from the command line through the pecan web interface. This will use curl to submit all the requireed parameters to the web interface and trigger a run. # the host where the model should run # never use remote sites since you will need to pass your username/password and that WILL be stored hostname=pecan.vm # the site id where to run the model (NIWOT in this case) siteid=772 # start date and end date, / need to be replaced with %2F or use - (NOT TESTED) start=2004-01-01 end=2004-12-31 # if of model you want to run, rest of section parameters depend on the model selected (SIPNET 136) modelid=5000000002 # PFT selected (we should just use a number here) # NOTE: the square brackets are needed and will need be escaped with a \\ if you call this from command line pft[]=temperate.coniferous # initial pool condition (-1 means nothing is selected) input_poolinitcond=-1 # met data input_met=99000000006 # variables to collect variables=NPP,GPP # ensemble size runs=10 # use sensitivity analysis sensitivity=-1,1 # redirect to the edit pecan.xml file pecan_edit=on # redirect to edit the model configuration files model_edit=on # use browndog browndog=on For example the following will run the above workflow. Using -v in curl will show verbose output (needed) and the grep will make sure it only shows the redirect. This will show the actual workflowid: curl -s -v 'http://localhost:6480/pecan/04-runpecan.php?hostname=pecan.vm&siteid=772&start=2004-01-01&end=2004-12-31&modelid=5000000002&pft\\[\\]=temperate.coniferous&input_poolinitcond=-1&input_met=99000000006' 2>&1 | grep 'Location:' < Location: 05-running.php?workflowid=99000000004 In this case you can use the browser to see progress, or use the following to see the status: curl -s 'http://localhost:6480/pecan/dataset.php?workflowid=99000000004&type=file&name=STATUS' TRAIT 2017-12-13 08:56:56 2017-12-13 08:56:57 DONE META 2017-12-13 08:56:57 2017-12-13 08:57:13 DONE CONFIG 2017-12-13 08:57:13 2017-12-13 08:57:14 DONE MODEL 2017-12-13 08:57:14 2017-12-13 08:57:15 DONE OUTPUT 2017-12-13 08:57:15 2017-12-13 08:57:15 DONE ENSEMBLE 2017-12-13 08:57:15 2017-12-13 08:57:16 DONE FINISHED 2017-12-13 08:57:16 2017-12-13 08:57:16 DONE Or to show the output log: curl -s 'http://localhost:6480/pecan/dataset.php?workflowid=99000000004&type=file&name=workflow.Rout' R version 3.4.3 (2017-11-30) -- "Kite-Eating Tree" Copyright (C) 2017 The R Foundation for Statistical Computing Platform: x86_64-pc-linux-gnu (64-bit) R is free software and comes with ABSOLUTELY NO WARRANTY. You are welcome to redistribute it under certain conditions. Type 'license()' or 'licence()' for distribution details. R is a collaborative project with many contributors. .... "],["basic-web-workflow.html", "6 Basic Web workflow", " 6 Basic Web workflow This chapter describes the major steps of the PEcAn web-based workflow, which are as follows: Model and site selection Model configuration Run execution – TODO! Results – TODO! Interactive visualizations – TODO! We recommend that all new users begin with [PEcAn Hands-On Demo 01: Basic Run]. The documentation below assumes you are already familiar with how to navigate to PEcAn’s interactive web interface for running models. "],["web-site-model.html", "6.1 Site and model selection", " 6.1 Site and model selection This page is used to select the model to run and the site at which you would like to run that model. NOTE: If this page does not load for you, it may be related to a known Google Maps API key issue. See issue #1269 for a possible solution. 6.1.1 Selecting a model On the Select Host webpage use the Host pull-down menu to select the server you want to run on. PEcAn is designed to allow models to be run both locally and on remote high-performance computing (HPC) resources (i.e. clusters). We recommend that users start with local runs. More information about connecting your PEcAn instance to a cluster can be found on the Remote execution with PEcAn page. Next, select the model you want to run under the Model pull-down menu. The list of models currently supported by PEcAn, along with information about these models, is available on the PEcAn Models page. If a PEcAn-supported model is not listed, this is most likely because the model has not been installed on the server. The PEcAn team does not have permissions to redistribute all of the models that are coupled to it, so you will have to install some PEcAn-compatible models yourself. Please consult the PEcAn model listing for information about obtaining and installing different models. Once the model is installed and you have added the location of the model executable to Bety (see Adding An Ecosystem Model), your model should appear on the PEcAn Select Host page after your refresh the page. If you would like to add a new model to PEcAn please consult our guide for Adding an Ecosystem Model and contact the PEcAn team for assistance. If selecting your model causes your site to disappear from the Google Map, that means the site exists but there are no drivers for that model-site combination registered in the database. Click the “Conversion” checkbox. If your site reappears, that means PEcAn should be able to automatically generate the required inputs for this site by converting from existing input files in other formats. If the site still does not reappear, that means there are required input files for that model-site combination that PEcAn cannot autogenerate. This may be because the model has unique input requirements or because it has not yet been fully coupled to the PEcAn input processing workflow. Go to the troubleshooting section under Selecting a site for more information on diagnosing what drivers are missing. 6.1.2 Selecting a site 6.1.3 Site Groups PEcAn provides the option of organizing sites into groups to make them easier to find and easier to run as a group. We have pre-loaded a number of common research networks (e.g., FLUXNET, LTER, NEON), but you are free to create new site groups through Bety. If you are searching for a site that is not part of an existing site group, or you are unsure which site group it belongs to, select “All Sites” to see all sites in Bety. Note that this may take a while to render. 6.1.4 Using existing sites Find the site on the map The simplest way of determining if a site exists in PEcAn is through the Google Map interface of the web-based workflow. You’ll want to make sure that the “Site Group” is set to “All Sites” and the “Model” is set to “All Models”. Find the site in BETY If the site is not on the map, it may still be in Bety but with insufficient geographic information. To locate the site in Bety, first login to your local version of the BETY database. If using the VM, navigate to localhost:6480/bety and login with username bety and password illinois. Then, navigate to Data > Sites and use the “Search” box to search for your site. If you do find your site, click “Edit” and add geographic information so that the site will show up on the map. Also, note that the site ID number shows up in the URL for the “Show” or “Edit” pages. This ID is often useful to know, for example when editing a PEcAn settings file by hand. If you did not find you site, follow the instructions below to add a site. 6.1.5 Adding a new site (TODO: Move most of this out) Log into Bety as described above. Pick a citation for your site Each site requires an associated “citation” that must be added before the site itself is added. First, navigate to “Data > Citations” and use the “Search” box to see if the relevant citation already exists. If it does, click the check mark under “Actions” to proceed to site creation. To create a new citation, click the New Citation button, fill in the fields, and then click “Create”. The “field URL” should contain the web address that takes you to this publication on the publisher’s website. The “PDF” field should be the full web address to a PDF for this citation. Note that our definition of a citation is flexible, and a citation need not be a peer-reviewed publication. Most of the fields in “New Citation” can be left blank, but we recommend at least adding a descriptive title, such as “EBI Farm Field Data” and a relevant contact person as the “Author”. Once the Citation is created or selected this should automatically take you to the Sites page and list any Sites already associated with this citation. To create a new site click the New Site button. When creating a new site, the most important fields are the Site name and coordinates (latitude and longitude). The coordinates can be entered by hand or by clicking on the site location on the Google Map interface. All other information is optional, but can be useful for searching and indexing purposes. When you are done click Create. At this point, once the PEcAn site-level page is refreshed, the site should automatically appear. 6.1.6 Troubleshooting 6.1.6.1 My site shows up when I don’t have any model selected, but disappears once I select the model I want to run Selecting a model will cause PEcAn to filter the available sites based on whether they possess the required Inputs for a given model (e.g. meteorology). To check what Inputs are missing for a site point your browser to the pecan/checksite.php webpage (e.g. localhost:6480/pecan/checksite.php). This page looks virtually identical to the site selection page, except that it has a Check button instead of Prev and Next. If you select a Machine, Model, and Site and then click Check the page should return a list of what Inputs are missing (listing both the name and the Format ID number). Don’t forget that its possible for PEcAn to have required Inputs in its database, but just not have them for the Machine where you want to run. To see more about what Inputs a given model can accept, and which of those are required, take a look at the MODEL_TYPE table entry in the database (e.g. go to localhost:6480/bety; Select Runs > Model Type; and then click on the model you want to run). For information about loading missing Inputs into the database visit Input records in BETY, and also read the rest of the pages under this section, which will provide important information about the specific classes of Inputs (e.g. meteorology, vegetation, etc). Finally, we are continually developing and refining workflows and standards for processing Input data in a model-agnostic way. The details about what Inputs can be processed automatically are discussed input-by-input in the sections below. For those looking to dive into the code or troubleshoot further, these conversions are ultimately handled under the PEcAn.workflow::do_conversions workflow module. "],["web-model-config.html", "6.2 Model configuration", " 6.2 Model configuration This page is used for basic model configuration, including when your model will run and what input data it will use. 6.2.1 Choosing meteorology Once a Machine, Model, and Site have been selected, PEcAn will take you to the Input selection page. From this page you will select what Plant Functional Type (PFT) you want to run at a site, the start and end dates of the run, and various Input selections. The most common of these across all models is the need to specify meteorological forcing data. The exact name of the menu item for meteorology will vary by model because all of the Input requirements are generated individually for each model based on the MODEL_TYPE table. In general there are 3 possible cases for meteorology PEcAn already has driver files in its database PEcAn does not have drivers, but can generate them from publicly available data You need (or want) to upload your own drivers The first two cases will appear automatically in the the pull down menu. For meteorological files that already exist you will see the date range that’s available. By contrast, met that can be generated will appear as “Use ”, where is the origin of the data (e.g. “Use Ameriflux” will use the micromet from an Ameriflux eddy covariance tower, if one is present at the site). If you want to upload your own met data this can be done in three ways. The default way to add met data is to incorporate it into the overall meteorological processing workflow. This is preferred if you are working with a common meteorological data product that is not yet in PEcAn’s workflow. This case can be divided into two special cases: Data is in a common MIME-type that PEcAn already has a converter for (e.g. CSV). In this case you’ll want to create a new Format record for the meta-data so that the existing converter can process this data. See documentation for [Creating a new Format record in BETY] for more details. Data is in a more complicated format or interactive database, but large/useful enough to warrent a custom conversion function. Details on creating custom met conversions is in the [Input Conversion], though at this stage you would also be strongly encouraged to contact the PEcAn development team. The second-best way is to upload data in PEcAn’s standard meteorological format (netCDF files, CF metadata). See [Input Conversion] for details about variables and units. From this standard, PEcAn can then convert the file to the model-specific format required by the model you have chosen. This approach is preferred for a rare or one-off meterological file format, because PEcAn will also be able to convert the file into the format required by any other model as well. The last option for adding met data is to add it in a model-specific format, which is often easiest if you’ve already been running your model at a site and are just switching to using PEcAn. 6.2.2 Met workflow In a nutshell, the PEcAn met workflow is designed to reduce the problem of converting n possible met inputs into m possible model formats, which requires n x m conversion functions as well as numerous custom functions for downscaling, gap filling, etc. Instead, PEcAn works with a single met standard, and thus requires n conversion functions, one for converting each data source into the PEcAn standard, and then m conversion functions for converting from that standard to what an individual model requires. For a new model joining the PEcAn system the burden in particularly low – writing one conversion function provides access to n inputs. Similarly, PEcAn performs all other operations/manipulations (extracting a site, downscaling, gap filling, etc) within the PEcAn standard, which means these operations only need be implemented once. Consider a generic met data product named MET for simplicity. PEcAn will use a function, download.MET, to pull data for the selected year from a public data source (e.g. Ameriflux, North American Regional Reanalysis, etc). Next, PEcAn will use a function, met2CF.MET, to convert the data into the PEcAn standard. If the data is already at the site scale it will then gapfill the data. If the data is a regional or global data product, PEcAn will then permute the data to allow easier site-level extraction, then it will extract data for the requested site and data range. Modules to address the temporal and spatial downscaling of meteorological data products, as well as their uncertainties, are in development but not yet part of the operational workflow. All of these functions are located within the data.atmosphere module. Once data is in the standard format and processed, it will be converted to the model-specific format using a met2model.MODEL function (located in that MODEL’s module). More detailed information on how PEcAn processes inputs can be found on our [Input Conversion] page. 6.2.3 Troubleshooting meteorological conversions At the current moment, most of the issues below address possible errors that the Ameriflux meteorology workflow might report 6.2.3.1 Could not do gapfill … The following variables have NA’s This error message means that there were gaps in the downloaded data, for whatever variables that were listed, which were larger than the current algorithm could fill. Particularly common is missing radiation or PAR data, as Ameriflux frequently converts nighttime data to NULL, and work is in progress to detect this based on solar geometry. Also common are incomplete years (first or last year of tower operations). 6.2.3.2 Could not get information about . Is this an Ameriflux site? This message occurs when PEcAn believes that a site is part of Ameriflux (because it was listed on the Ameriflux or FLUXNET webpage and has a US-* site code), but no data is present on the Ameriflux server. The most common reasons for this is that you have selected a site that has not submitted data to Ameriflux yet (or that data hasn’t been processed yet), or you have selected a year that’s outside the tower’s operational period. Visit Ameriflux and FLUXNET for lists of available site years. 6.2.3.3 Could not download data for for the year This is similar to the previous error, but in this case PEcAn did find data for the site listed, but just not for the year requested. This can usually be fixed by just altering the years of the run to match those with available data. 6.2.3.4 I could not find the requested var (or dimvar) in the file! PEcAn could not find a required variable within the downloaded file. Most likely this is due to that variable not being measured at this site. The most common cause of failure is the absence of atmospheric pressure data (PRESS), but since most models have a low sensitivity to this variable we are working on methods to estimate this from other sources. "],["selecting-plant-functional-types-pfts-and-other-parameter-groupings..html", "6.3 Selecting Plant Functional Types (PFTs) and other parameter groupings.", " 6.3 Selecting Plant Functional Types (PFTs) and other parameter groupings. 6.3.1 Using existing PFTs PEcAn does not automatically know what vegetation types are present at your study site so you need to select the PFT. Some models, such as ED2 and LINKAGES, support competition among multiple PFTs and thus you are encouraged to highlight multiple choices. Other models, such as SIPNET and DALEC, only support one PFT at a site. Many models also have parameters that control non-vegetation processes (e.g. soil biogeochemistry and hydrology). PEcAn allows users to assign these parameters to functional groups as well (e.g. a soils PFT) 6.3.2 Creating new PFTs To modify or add a new Plant Functional Type (PFT), or to change a PFT’s priors, navigate on the grey menu bar to Data > PFTs To add a new pft, click “new PFT” at the top and enter a name and description. (hint: we’re trying to name PFTs based on model.biome.pft, ED2 is the default model if one isn’t specified) To add new species to a PFT click on [+] View Related Species and type the species, genus, or family you are looking for into the Search box. Click on the + to add. To remove a species from a PFT, click on [+] View Related Species and click on the X of the species you want to remove from the PFT. To remove a prior, click [-] View Related Prior and click on the X of the variable who’s prior you want to remove. This will cause the parameter to be excluded from all analyses (meta-analysis, sensitivity analysis, etc) and revert to its default value. To add a prior, choose one from the white box of priors on the right to choose. To view the specification of a prior, or to add a new prior, click BETY-DB > Priors and enter the information on the variable, distribution name, distribution parameters, etc. N is the sample size underlying the prior specification (0 is ok for uninformative priors). You can also got to Data > Variables in order to use the search function to find an existing variable (or create a new one). Please try not to create new variables unnecessarily (e.g. changes of variable name or units to what your model uses is handled internally, so you want to find the trait with the correct MEANING). Additional information on adding PFTs, Species, and Priors can be found in Adding An [Ecosystem Model]. 6.3.3 Choosing initial vegetation On the Input Selection webpage, in addition to selecting PFTs, start & end dates, and meteorology, many models also require some way of specifying the initial conditions for the vegetation, which may range from setting the aboveground biomass and LAI up to detailed inventory-like data on species composition and stand structure. At the moment, PEcAn has three cases for initial conditions: If files already exist in the database, they can simply be selected from the menu. For ED2, there are 3 different veg files (site, pss, css) and it is important that you select a complete set, not mix and match. If files don’t exist they can be uploaded following the instructions in Create a database file record for the input data. Automated vegetation initial condition workflow As with meteorology, PEcAn is working to develop a model-agnostic workflow for converting various sources of vegetation data to common standards, developing common processing tools, and then writing out to model-specific formats. This process is in a much early stage than the meteorology workflow, as we are still researching what the options are for standard formats, but ultimately aims to be much more broad in scope, considering not just plot inventory data but also historical documentation, paleoecological proxies, satellite remote sensing (e.g. LANDSAT), airborne hyperspectral imagery, and active remote sensing (Lidar, Radar). At the moment, what is functional is a prototype workflow that works for inventory-based vegetation data. This data can come from either files that have been registered with the BETY Inputs and Formats tables or can be queried from the USFS Forest Inventory and Analysis (FIA). For more information visit Section 13.1.2.2 Vegetation Data 6.3.4 US FIA This tool works with an internal copy of the FIA that is uploaded to a postGRES database along side BETY, however for space reasons this database does not ship with the PEcAn VM. To turn this feature on: Download and Install the FIA database. Instructions in Installing data for PEcAn For web-base runs, specify the database settings in the config.php For R-based runs, specify the database settings in the THE PEcAn XML More detailed information on how PEcAn processes inputs can be found on our [Input Conversion]page. 6.3.5 Spin up A number of ecosystem models are typically initialized by spinning up to steady state. At the moment PEcAn doesn’t handle spin up automatically (e.g. looping met, checking for stability), but there are various ways to achieve a spin-up within the system. Option 1: If there are model-specific settings in a model’s settings/config file, then that file can be accessed by clicking on the Edit model config check box. If this box is selected then PEcAn will pause the site run workflow after it has generated your model config file, but before it runs the model, and give you an opportunity to edit the file by hand, allowing you to change any model-specific spin up settings (e.g met recycling, spin up length) Option 2: Set start_year very early and set the met drivers to be a long time series (e.g. PalEON, something custom uploaded to Inputs) Option 3: In the MODEL_TYPE table, add your model’s restart format as an optional input, modify the model specific write.config function to use that restart, and then load a previous spin-up to the Inputs table Beyond these options, we hope to eventually develop more general, model-agnostic tools for spin up. In particular, we have started to explore the accelerated spin-up and semi-analytical techniques being developed by Yiqi Luo’s lab 6.3.6 Selecting a soils product Many models have requirements for soils information, which may include: site-specific soil texture and depth information; soil biogeochemical initial conditions (e.g. soil carbon and nitrogen pools); soil moisture initial conditions; and soil thermal initial conditions. As with Choosing initial vegetation, we eventually hope to develop data standards, soils workflows, and spin-up tools, but at the moment this workflow is in the early stages of development. Model requirements need to be met byCreating a new Input record in BETY into the database or using files that have already been uploaded. Similar to met, we recommend that this file be in the PEcAn-standard netCDF described below, but model-specific files can also be registered. 6.3.7 Soil texture, depth, and physical parameters A PEcAn-standard netCDF file format exists for soil texture, depth, and physical parameters, using PEcAn standard names that are largely a direct extention of the CF standard. The easiest way to create this file is with the PEcAn R function soil2netcdf as described in the Soil Data section of the Advanced Users Guide. A table of standard names and units can be listed using PEcAn.data.land::soil.units() with no arguments. More detailed information on how PEcAn processes inputs can be found on our [Input Conversion] page. 6.3.8 Other model inputs Finally, any other model-specific inputs (e.g. N deposition, land use history, etc), should be met by Creating a new Input record in BETY or using files that have already been uploaded. "],["intermediate-user.html", "7 More on the PEcAn Web Interface", " 7 More on the PEcAn Web Interface This section will provide information to those wanting to take advantage of PEcAn’s customizations from the web interface. Additional web configuration - Advanced options available from the web interface Brown Dog Sensitivity and ensemble analyses[TODO: Under construction…] [Editing model configurations][TODO: Under construction…] Settings-configured analyses - Analyses only available by manually editing pecan.xml Parameter data assimilation (PDA) State data assimilation (SDA) Remote execution with PEcAn - Running analyses and generally working with external machines (HPC) in the context of PEcAn. "],["additional-web-configuration.html", "7.1 Additional web configuration", " 7.1 Additional web configuration Additional settings for web configuration: Web interface setup Brown Dog Advanced setup [Sensitivity analysis] (TODO) [Uncertainty analysis] (TODO) Editing model configuration files 7.1.1 Web interface setup There are few options which you can change via web interface. To visit the configuration page either you can just click on the setups link on the introduction page alternatively can type <host>/setups/. The list of configuration available Database configuration : BETYdb(Biofuel Ecophysiological Traits and Yields database) configuration details, can be edited according to need. Browndog configuration : Browndog configuration details, Used to connect browndog. Its included by default in VM. FIA Database : FIA(Forest Inventory and Analysis) Database configuration details, Can be used to add additional data to models. Google MapKey : Google Map key, used to access the google map by PEcAn. Change Password : A small infomation to change the VM user password. (if using Docker image it won’t work) Automatic Sync : If ON then it will sync the database between local machine and the remote servers. Still unders testing part might be buggy. Still work on the adding other editing feature going on, this page will be updated as new configuration will be available. 7.1.2 Brown Dog The Browndog service provides PEcAn with access to large and diverse sets of data at the click of a button in the format that PEcAn needs. By clicking the checkbox you will be using the Browndog Service to process data. For more information regarding meteorological data check out Available Meteorological Drivers. More information can be found at the Browndog website. 7.1.3 Advanced Setup (TODO: Under construction…) 7.1.4 Editing model configurations (TODO: Under construction…) "],["settings-configured-analyses.html", "7.2 Settings-configured analyses", " 7.2 Settings-configured analyses These analyses can be run through the web interface, but lack graphical interfaces and currently can only be configured throughthe XML settings. To run these analyses use the Edit pecan.xml checkbox on the Input configuration page. Eventually, these modules will be integrated into the web user interface. Parameter Data Assimilation (PDA) State Data Assimilation (SDA) MultiSettings Benchmarking (TODO: Add links) 7.2.1 Parameter data assimilation (PDA) All functions pertaining to Parameter Data Assimilation are housed within: pecan/modules/assim.batch. For a detailed usage of the module, please see the vignette under pecan/modules/assim.batch/vignettes. Hierarchical version of the PDA is also implemented, for more details, see the MultiSitePDAVignette package vignette and function-level documentation. 7.2.1.1 pda.mcmc.R This is the main PDA code. It performs Bayesian MCMC on model parameters by proposing parameter values, running the model, calculating a likelihood (between model output and supplied observations), and accepting or rejecting the proposed parameters (Metropolis algorithm). Additional notes: The first argument is settings, followed by others that all default to NULL.settings is a list used throughout Pecan, which contains all the user options for whatever analyses are being done. The easiest thing to do is just pass that whole object all around the Pecan code and let different functions access whichever settings they need. That’s what a lot of the rest of the Pecan code does. But the flexibility to override most of the relevant settings in settings is there by providing them directly as arguments to the function. The if(FALSE)… : If you’re trying to step through the function you probably will have the settings object around, but those other variables will be undefined. If you set them all to NULL then they’ll be ignored without causing errors. It is there for debugging purposes. The next step calls pda.settings(), which is in the file pda.utils.R (see below). It checks whether any settings are being overridden by arguments, and in most cases supplies default values if it can’t find either. In the MCMC setup section The code is set up to allow you to start a new MCMC chain, or to continue a previous chain as specified in settings. The code writes a simple text file of parameter samples at every iteration, which lets you get some results and even re-start an MCMC that fails for some reason. The code has adaptive jump distributions. So you can see some initialization of the jump distributions and associated variables here. Finally, note that after all this setup a new XML settings file is saved. The idea is that the original pecan.xml you create is preserved for provenance, and then periodically throughout the workflow the settings (likely containing new information) are re-saved with descriptive filenames. MCMC loop Periodically adjust jump distribution to make acceptance rate closer to target Propose new parameters one at a time. For each: First, note that Pecan may be handling many more parameters than are actually being targeted by PDA. Pecan puts priors on any variables it has information for (in the BETY database), and then these get passed around throughout the analysis and every step (meta-, sensitivity, ensemble analyses, etc.). But for PDA, you specify a separate list of probably far fewer parameters to constrain with data. These are the ones that get looped over and varied here. The distinction between all parameters and only those dealt with in PDA is dealt with in the setup code above. First a new value is proposed for the parameter of interest. Then, a new model run is set up, identical to the previous except with the new proposed value for the one parameter being updated on this run. The model run is started, and outputs collected after waiting for it to finish. A new likelihood is calculated based on the model outputs and the observed dataset provided. Standard Metropolis acceptance criteria is used to decide whether to keep the proposed parameter. Periodically (at interval specified in settings), a diagnostic figure is saved to disk so you can check on progress. This works only for NEE currently 7.2.1.2 pda.mcmc.bs.R This file is basically identical to pda.mcm.R, but rather than propose parameters one at a time, it proposes new values for all parameters at once (“bs” stands for “block sampling”). You choose which option to use by specifying settings\\(assim.batch\\)method: * “bruteforce” means sample parameters one at a time * “bruteforce.bs” means use this version, sampling all parameters at once * “emulator” means use the emulated-likelihood version 7.2.1.3 pda.emulator This version of the PDA code again looks quite similar to the basic “bruteforce” one, but its mechanics are very different. The basic idea is, rather than running thousands of model iterations to explore parameter space via MCMC, run a relatively smaller number of runs that have been carefully chosen to give good coverage of parameter space. Then, basically interpolate the likelihood calculated for each of those runs (actually, fit a Gaussian process to it), to get a surface that “emulates” the true likelihood. Now, perform regular MCMC (just like the “bruteforce” approach), except instead of actually running the model on every iteration to get a likelihood, just get an approximation from the likelihood emulator. Since the latter step takes virtually no time, you can run as long of an MCMC as you need at little computational cost, once you have done the initial model runs to create the likelihood emulator. 7.2.1.4 pda.mcmc.recover.R This function is for recovering a failed PDA MCMC run. 7.2.1.5 pda.utils.R This file contains most of the individual functions used by the main PDA functions (pda.mcmc.*.R). assim.batch is the main function Pecan calls to do PDA. It checks which method is requested (bruteforce, bruteforce.bs, or emulator) and call the appropriate function described above. pda.setting handles settings. If a setting isn’t found, the code can usually supply a reasonable default. pda.load.priors is fairly self explanatory, except that it handles a lot of cases and gives different options priority over others. Basically, the priors to use for PDA parameters can come from either a Pecan prior.distns or post.distns object (the latter would be, e.g., the posteriors of a meta-analysis or previous PDA), or specified either by file path or BETY ID. If not told otherwise, the code tries to just find the most recent posterior in BETY, and use that as prior for PDA. pda.create.ensemble gets an ensemble ID for the PDA. All model runs associated with an individual PDA (any of the three methods) are considered part of a single ensemble. This function does is register a new ensemble in BETY, and return the ID that BETY gives it. pda.define.prior.fn creates R functions for all of the priors the PDA will use. pda.init.params sets up the parameter matrix for the run, which has one row per iteration, and one column per parameter. Columns include all Pecan parameters, not just the (probably small) subset that are being updated by PDA. This is for compatibility with other Pecan components. If starting a fresh run, the returned matrix is just a big empty matrix to fill in as the PDA runs. If continuing an existing MCMC, then it will be the previous params matrix, with a bunch of blank rows added on for filling in during this round of PDA. pda.init.run This is basically a big wrapper for Pecan’s write.config function (actually functions [plural], since every model in Pecan has its own version). For the bruteforce and bruteforce.bs methods this will be run once per iteration, whereas the emulator method knows about all its runs ahead of time and this will be a big batch of all runs at once. pda.adjust.jumps tweaks the jump distributions for the standard MCMC method, and pda.adjust.jumps.bs does the same for the block-sampled version. pda.calc.llik calculates the log-likelihood of the model given all datasets provided to compare it to. pda.generate.knots is for the emulator version of PDA. It uses a Latin hypercube design to sample a specified number of locations in parameter space. These locations are where the model will actually be run, and then the GP interpolates the likelihood surface in between. pda.plot.params provides basic MCMC diagnostics (trace and density) for parameters being sampled. pda.postprocess prepares the posteriors of the PDA, stores them to files and the database, and performs some other cleanup functions. pda.load.data.r This is the function that loads in data that will be used to constrain the PDA. It’s supposed to be eventually more integrated with Pecan, which will know how to load all kinds of data from all kinds of sources. For now, it can do NEE from Ameriflux. pda.define.llik.r A simple helper function that defines likelihood functions for different datasets. Probably in the future this should be queried from the database or something. For now, it is extremely limited. The original test case of NEE assimilation uses a heteroskedastic Laplacian distribution. pda.get.model.output.R Another function that will eventually grow to handle many more cases, or perhaps be replaced by a better system altogether. For now though, it again just handles Ameriflux NEE. 7.2.1.6 get.da.data.*.R, plot.da.R Old codes written by Carl Davidson. Defunct now, but may contain good ideas so currently left in. 7.2.2 State data assimilation (SDA) sda.enkf.R is housed within: /pecan/modules/assim.sequential/R The tree ring tutorial is housed within: /pecan/documentation/tutorials/StateAssimilation More descriptive SDA methods can be found at: /pecan/book_source/adve_user_guide_web/SDA_Methods.Rmd 7.2.2.1 sda.enkf.R Description This is the main ensemble Kalman filter and generalized filter code. Originally, this was just ensemble Kalman filter code. Mike Dietze and Ann Raiho added a generalized ensemble filter to avoid filter divergence. The output of this function will be all the of run outputs, a PDF of diagnostics, and an Rdata object that includes three lists: FORECAST will be the ensemble forecasts for each year ANALYSIS will be the updated ensemble sample given the NPP observations enkf.params contains the prior and posterior mean vector and covariance matrix for each time step. 7.2.2.2 sda.enkf.R Arguments settings - (required) State Data Assimilation Tags Example settings object obs.mean - (required) a list of observation means named with dates in YYYY/MM/DD format obs.cov - (required) a list of observation covariances names with dates in YYYY/MM/DD format IC - (optional) initial condition matrix (dimensions: ensemble memeber # by state variables). Default is NULL. Q - (optional) process covariance matrix (dimensions: state variable by state variables). Default is NULL. 7.2.2.3 State Data Assimilation Workflow Before running sda.enkf, these tasks must be completed (in no particular order), Read in a State Data Assimilation Tags Example settings file with tags listed below. i.e. read.settings(‘pecan.SDA.xml’) Load data means (obs.mean) and covariances (obs.cov) as lists with PEcAn naming and unit conventions. Each observation must have a date in YYYY/MM/DD format (optional time) associated with it. If there are missing data, the date must still be represented in the list with an NA as the list object. Create initial conditions matrix (IC) that is state variables columns by ensemble members rows in dimension. sample.IC.MODEL can be used to create the IC matrix, but it is not required. This IC matrix is fed into write.configs for the initial model runs. The main parts of the SDA function are: Setting up for initial runs: Set parameters Load initial run inputs via split.inputs.MODEL Open database connection Get new workflow ids Create ensemble ids Performing the initial set of runs Set up for data assimilation Loop over time read.restart.MODEL - read model restart files corresponding to start.time and stop.time that you want to assimilate data into Analysis - There are four choices based on if process variance is TRUE or FALSE and if there is data or not. See explaination below. write.restart.MODEL - This function has two jobs. First, to insert adjusted state back into model restart file. Second, to update start.time, stop.time, and job.sh. run model Save outputs Create diagnostics 7.2.2.4 State Data Assimilation Tags Example <state.data.assimilation> <adjustment>TRUE</adjustment> <process.variance>FALSE</process.variance> <sample.parameters>FALSE</sample.parameters> <q.type>Single</q.type> <state.variables> <variable> <variable.name>AGB.pft</variable.name> <unit>MgC/ha/yr</unit> <min_value>0</min_value> <max_value>100000000</max_value> </variable> <variable> <variable.name>TotSoilCarb</variable.name> <unit>KgC/m^2</unit> <min_value>0</min_value> <max_value>100000000</max_value> </variable> </state.variables> <spin.up> <start.date>1950/01/01</start.date> <end.date>1960/12/31</end.date> </spin.up> <forecast.time.step>1</forecast.time.step> <start.date>1961/01/01</start.date> <end.date>2010/12/31</end.date> </state.data.assimilation> 7.2.2.5 State Data Assimilation Tags Descriptions adjustment : [optional] TRUE/FLASE flag for if ensembles needs to be adjusted based on weights estimated given their likelihood during analysis step. The Default is TRUE for this flag. process.variance : [optional] TRUE/FLASE flag for if process variance should be estimated (TRUE) or not (FALSE). If TRUE, a generalized ensemble filter will be used. If FALSE, an ensemble Kalman filter will be used. Default is FALSE. If you use the TRUE argument you can set three more optional tags to control the MCMCs built for the generalized esnsemble filter. nitrGEF : [optional] numeric defining the length of the MCMC chains. nthin : [optional] numeric defining thining length for the MCMC chains. nburnin : [optional] numeric defining the number of burnins during the MCMCs. q.type : [optional] If the process.variance is set to TRUE then this can take values of Single, Site or PFT. censored.data : [optional] logical set TRUE for censored state variables. sample.parameters : [optional] TRUE/FLASE flag for if parameters should be sampled for each ensemble member or not. This allows for more spread in the initial conditions of the forecast. state.variable : [required] State variable that is to be assimilated (in PEcAn standard format). spin.up : [required] start.date and end.date for initial model runs. NOTE: start.date and end.date are distinct from values set in the run tag because initial runs can be done over a subset of the full run. forecast.time.step : [optional] In the future, this will be used to allow the forecast time step to vary from the data time step. start.date : [optional] start date of the state data assimilation (in YYYY/MM/DD format) end.date : [optional] end date of the state data assimilation (in YYYY/MM/DD format) NOTE: start.date and end.date are distinct from values set in the run tag because this analysis can be done over a subset of the run. 7.2.2.6 Model Specific Functions for SDA Workflow 7.2.2.7 read.restart.MODEL.R The purpose of read.restart is to read model restart files and return a matrix that is site rows by state variable columns. The state variables must be in PEcAn names and units. The arguments are: outdir - output directory runid - ensemble member run ID stop.time - used to determine which restart file to read (in POSIX format) settings - pecan.SDA.xml settings object var.names - vector with state variable names with PEcAn standard naming. Example: c(‘AGB.pft’, ‘TotSoilCarb’) params - parameters used by ensemble member (same format as write.configs) 7.2.2.8 write.restart.MODEL.R This model specific function takes in new state and new parameter matrices from sda.enkf.R after the analysis step and translates new variables back to the model variables. Then, updates start.time, stop.time, and job.sh so that start_model_runs() does the correct runs with the new states. In write.restart.LINKAGES and write.restart.SIPNET, job.sh is updated by using write.configs.MODEL. outdir - output directory runid - run ID for ensemble member start.time - beginning of model run (in POSIX format) stop.time - end of model run (in POSIX format) settings - pecan.SDA.xml settings object new.state - matrix from analysis of updated state variables with PEcAn names (dimensions: site rows by state variables columns) new.params - In the future, this will allow us to update parameters based on states (same format as write.configs) inputs - model specific inputs from split.inputs.MODEL used to run the model from start.time to stop.time RENAME - [optional] Flag used in write.restart.LINKAGES.R for development. 7.2.2.9 split.inputs.MODEL.R This model specific function gives the correct met and/or other model inputs to settings\\(run\\)inputs. This function returns settings\\(run\\)inputs to an inputs argument in sda.enkf.R. But, the inputs will not need to change for all models and should return settings\\(run\\)inputs unchanged if that is the case. settings - pecan.SDA.xml settings object start.time - start time for model run (in POSIX format) stop.time - stop time for model run (in POSIX format) 7.2.2.10 sample.IC.MODEL.R This model specific function is optional. But, it can be used to create initial condition matrix (IC) with # state variables columns by # ensemble rows. This IC matrix is used for the initial runs in sda.enkf.R in the write.configs.MODEL function. ne - number of ensemble members state - matrix of state variables to get initial conditions from year - used to determine which year to sample initial conditions from 7.2.2.11 Analysis Options There are four options depending on whether process variance is TRUE/FALSE and whether or not there is data or not. If there is no data and process variance = FALSE, there is no analysis step. If there is no data and process variance = TRUE, process variance is added to the forecast. If there is data and process variance = TRUE, the generalized ensemble filter is implemented with MCMC. If there is data and process variance = FALSE, the Kalman filter is used and solved analytically. 7.2.2.12 The Generalized Ensemble Filter An ensemble filter is a sequential data assimilation algorithm with two procedures at every time step: a forecast followed by an analysis. The forecast ensembles arise from a model while the analysis makes an adjustment of the forecasts ensembles from the model towards the data. An ensemble Kalman filter is typically suggested for this type of analysis because of its computationally efficient analytical solution and its ability to update states based on an estimate of covariance structure. But, in some cases, the ensemble Kalman filter fails because of filter divergence. Filter divergence occurs when forecast variability is too small, which causes the analysis to favor the forecast and diverge from the data. Models often produce low forecast variability because there is little internal stochasticity. Our ensemble filter overcomes this problem in a Bayesian framework by including an estimation of model process variance. This methodology also maintains the benefits of the ensemble Kalman filter by updating the state vector based on the estimated covariance structure. This process begins after the model is spun up to equilibrium. The likelihood function uses the data vector \\(\\left(\\boldsymbol{y_{t}}\\right)\\) conditional on the estimated state vector \\(\\left(\\boldsymbol{x_{t}}\\right)\\) such that \\(\\boldsymbol{y}_{t}\\sim\\mathrm{multivariate\\:normal}(\\boldsymbol{x}_{t},\\boldsymbol{R}_{t})\\) where \\(\\boldsymbol{R}_{t}=\\boldsymbol{\\sigma}_{t}^{2}\\boldsymbol{I}\\) and \\(\\boldsymbol{\\sigma}_{t}^{2}\\) is a vector of data variances. To obtain an estimate of the state vector \\(\\left(\\boldsymbol{x}_{t}\\right)\\), we use a process model that incorporates a process covariance matrix \\(\\left(\\boldsymbol{Q}_{t}\\right)\\). This process covariance matrix differentiates our methods from past ensemble filters. Our process model contains the following equations \\(\\boldsymbol{x}_{t} \\sim \\mathrm{multivariate\\: normal}(\\boldsymbol{x}_{model_{t}},\\boldsymbol{Q}_{t})\\) \\(\\boldsymbol{x}_{model_{t}} \\sim \\mathrm{multivariate\\: normal}(\\boldsymbol{\\mu}_{forecast_{t}},\\boldsymbol{P}_{forecast_{t}})\\) where \\(\\boldsymbol{\\mu}_{forecast_{t}}\\) is a vector of means from the ensemble forecasts and \\(\\boldsymbol{P}_{forecast_{t}}\\) is a covariance matrix calculated from the ensemble forecasts. The prior for our process covariance matrix is \\(\\boldsymbol{Q}_{t}\\sim\\mathrm{Wishart}(\\boldsymbol{V}_{t},n_{t})\\) where \\(\\boldsymbol{V}_{t}\\) is a scale matrix and \\(n_{t}\\) is the degrees of freedom. The prior shape parameters are updated at each time step through moment matching such that \\(\\boldsymbol{V}_{t+1} = n_{t}\\bar{\\boldsymbol{Q}}_{t}\\) \\(n_{t+1} = \\frac{\\sum_{i=1}^{I}\\sum_{j=1}^{J}\\frac{v_{ijt}^{2}+v_{iit}v_{jjt}}{Var(\\boldsymbol{\\bar{Q}}_{t})}}{I\\times J}\\) where we calculate the mean of the process covariance matrix \\(\\left(\\bar{\\boldsymbol{Q}_{t}}\\right)\\) from the posterior samples at time t. Degrees of freedom for the Wishart are typically calculated element by element where \\(v_{ij}\\) are the elements of \\(\\boldsymbol{V}_{t}\\). \\(I\\) and \\(J\\) index rows and columns of \\(\\boldsymbol{V}\\). Here, we calculate a mean number of degrees of freedom for \\(t+1\\) by summing over all the elements of the scale matrix \\(\\left(\\boldsymbol{V}\\right)\\) and dividing by the count of those elements \\(\\left(I\\times J\\right)\\). We fit this model sequentially through time in the R computing environment using R package ‘rjags.’ Users have control over how they think is the best way to estimate \\(Q\\). Our code will look for the tag q.type in the XML settings under state.data.assimilation which can take 4 values of Single, Site, Vector, or Wishart. If q.type is set to single then one value of process variance will be estimated across all different sites and variables. When q.type is set to Site then a process variance will be estimated for each siteat a cost of more time and computation power. When the q.type is set to Vector or Wishart then process errors for each variable of each site will be estimated and propagated through time, while the Wishart Q support the estimation of covariance between sites and variables through the MCMC sampling of wishart distributions, which further support the propagation of process error through not just time but space and variables. 7.2.2.13 Multi-site State data assimilation. sda.enkf.multisite is housed within: /pecan/modules/assim.sequential/R The 4-site tutorial is housed within: ~/pecan/modules/assim.sequential/inst/MultiSite-Exs 7.2.2.14 sda.enkf.multisite.R Description sda.enkf.multisite function allows for assimilation of observed data at multiple sites at the same time. In order to run a multi-site SDA, one needs to send a multisettings pecan xml file to this function. This multisettings xml file needs to contain information required for running at least two sites under run tag. The code will automatically run the ensembles for all the sites and reformats the outputs matching the required formats for analysis step. #### sda.enkf.multisite.R Arguments * settings - (required) State Data Assimilation Tags Example settings object obs.mean - (required) Lists of date times named by time points, which contains lists of sites named by site ids, which contains observation means for each state variables of each site for each time point. obs.cov - (required) Lists of date times named by time points, which contains lists of sites named by site ids, which contains observation covariances for all state variables of each site for each time point. Q - (optional) Process covariance matrix given if there is no data to estimate it. Default is NULL. restart - (optional) Used for iterative updating previous forecasts. Default NULL. List object includes file path to previous runs and start date for SDA. Default is NULL. pre_enkf_params - (optional) Used for carrying out SDA with pre-existed enkf.params, in which the Pf, aqq, and bqq can be used for the analysis step. Default is NULL. ensemble.samples - (optional) Pass ensemble.samples from outside, which are lists of calibrated parameters for different plant functional types. This also helps to avoid GitHub check issues. Default is NULL. control - (optional) List of flags controlling the behavior of the SDA. Here is an example of the control list. The detailed explanation of them are shown inside the sda.enkf.multisite function in the assim.sequential package. control=list(trace = TRUE, TimeseriesPlot = FALSE, debug = FALSE, pause = FALSE, Profiling = FALSE, OutlierDetection=FALSE, parallel_qsub = TRUE, send_email = NULL, keepNC = TRUE, run_parallel = TRUE, MCMC.args = NULL) 7.2.2.15 obs.mean and obs.cov Description The observations are required for passing the time points into the SDA workflow, which should match the start and end date in the settings object. For the generations of obs.mean and obs.cov, please use the function SDA_OBS_Assembler inside the assim.sequential package. For the unconstrained runs, please specify the free.run flag as TRUE inside the settings$state.data.assimilation$Obs_Prep section. Otherwise, please specify the arguments that are needed for preparations of different observations (note that, the observation preparation functions currently only support MODIS LAI, Landtrendr AGB, SMAP soil moisture, and SoilGrid soil organic carbon). For the details about how to setup those arguments, please reference the Create_Multi_settings.R script inside ~/pecan/modules/assim.sequential/inst/MultiSite-Exs/SDA directory. The observed mean and covariance need to be formatted as list of different dates with observations. For each element of this list also there needs to be a list with mean and cov matrices of different sites named by their siteid. In case that zero variance was estimated for a variable inside the obs.cov, the SDA code will automatically replace that with half of the minimum variance from other non-zero variables in that time step. Here are examples of the obs.mean and obs.cov for single time point, two sites, and two observations. > obs.mean $`2010/12/31` $`2010/12/31`$`1000000650` AbvGrndWood GWBI 111.502 1.0746 $`2010/12/31`$`1000000651` AbvGrndWood GWBI 114.302 1.574695 > obs.cov $`2010/12/31` $`2010/12/31`$`1000000650` [,1] [,2] [1,] 19.7821691 0.213584319 [2,] 0.5135843 0.005162113 $`2010/12/31`$`1000000651` [,1] [,2] [1,] 15.2821691 0.513584319 [2,] 0.1213583 0.001162113 7.2.2.16 Anlysis SDA workflow Before running the SDA analysis functions, the ensemble forecast results have to be generated, and arguments such as H matrix, MCMC arguments, and multi-site Y and R (by Construct.R function) have to be generated as well. Here are the workflows for three types of SDA analysis functions that we are currently used. Decide which analysis function to be used. Here we have three options: 1) traditional ensemble Kalman Filter (EnKF.MultiSite) with analytical solution, within which the process error needs to be prescribed from outside (see Q arguments in the sda.enkf.multisite function); 2) generalized ensemble Kalman Filter (GEF.MultiSite); and 3) block-based generalized ensemble Kalman Filter (analysis_sda_block). The latter two methods support the feature of propagating process variance across space and time. To choose the analysis method 1, we need to set the process.variance as FALSE. Otherwise, if we set the process.variance as TRUE and provide the q.type as either SINGLE or SITE the method GEF.MultiSite will be used, and if we provide the q.type as either vector or wishart the method analysis_sda_block will be used. The explanations for different Q types can be found in the The Generalized Ensemble Filter section in this documentation. For the analysis_sda_block method, there is also a special case for complete or partial missing of observations. If we decide to use EnKF.MultiSite, then the analysis results will be calculated based on equations. If we decide to use GEF.MultiSite, then it will first do censoring process based on how you setup the censored.data flag within settings xml file. Then, if t equals to 1, we will first initialize the aqq, bqq, aq, and bq based on how you setup the q.type argument within settings xml file. After preparing the initial conditions (ICs), data, and constants for the GEF.MultiSite.Nimble nimble model, the MCMC sampling will happen afterwards. Finally, the process variance and the analysis results will be calculated and updated and returned to the sda.enkf.multisite function. If we decide to use analysis_sda_block method, then if t equals 1, the workflow will first build blocks using the matrix_network function for the calculations for indexes of variables by networks of site groups based on the spatial scale (see scalef argument in the Example of multi-settings pecan xml file section) that we specify inside the state.data.assimilation section. Then, the workflow will execute the build.block.xy to automatically initialize the overall block-based MCMC lists (block.list.all) and fill in datasets (mu.f, y.censored, or Pf) for each block and for all time points to facilitate the process of passing arguments between scripts/functions. After that, the MCMC_args (see the explanations inside the roxygen structure of the sda.enkf.multisite function) will be specified either from the control list or by default (see below). Then, the workflow will update the process error using the update_q function. If t equals 1, it will initialize the arguments for the process error. Otherwise, it will grab the previously updated process error. After that, in the MCMC_Init function, it will create the initial conditions (ICs) for the MCMC sampling based on randomly sampled data. Then, the completed block-based arguments (block.list.all) will be used by the MCMC_block_function function under the parallel mode. Finally, the block-based results will be converted into long vectors and large matrices by the block.2.vector function and values such as block.list.all, mu.f, mu.a, Pf, Pa will be returned to the sda.enkf.multisite function. MCMC.args <- list(niter = 1e5, nthin = 10, nchain = 3, nburnin = 1e4) There is a special case for the analysis_sda_block method where NA values appear in the observations, which provides the opportunity for the estimations of process error without any observations. This special case currently is only working under restricted conditions when we set the scalef as 0 (that feature currently only works for isolated-site SDA runs) and turn on the free.run flag in the settings, which will then automatically fill in NA values to the observations by each site (see bellow). <state.data.assimilation> <scalef>0</scalef> <free.run>TRUE</free.run> </state.data.assimilation> 7.2.2.17 Example of multi-settings pecan xml file Here is an example of what does a multi-settings pecan xml file look like. The detailed explanation for the xml file can be found under the Multi-Settings section in the 03_pecan_xml.Rmd documentation. <?xml version="1.0"?> <pecan.multi> <state.data.assimilation> <process.variance>TRUE</process.variance> <aqq.Init>1</aqq.Init> <bqq.Init>1</bqq.Init> <sample.parameters>FALSE</sample.parameters> <adjustment>TRUE</adjustment> <censored.data>FALSE</censored.data> <FullYearNC>TRUE</FullYearNC> <NC.Overwrite>FALSE</NC.Overwrite> <NC.Prefix>sipnet.out</NC.Prefix> <q.type>SINGLE</q.type> <free.run>FALSE</free.run> <Localization.FUN>Local.support</Localization.FUN> <scalef>1</scalef> <chains>5</chains> <state.variables> <variable> <variable.name>AbvGrndWood</variable.name> <unit>MgC/ha</unit> <min_value>0</min_value> <max_value>9999</max_value> </variable> <variable> <variable.name>LAI</variable.name> <unit></unit> <min_value>0</min_value> <max_value>9999</max_value> </variable> <variable> <variable.name>SoilMoistFrac</variable.name> <unit></unit> <min_value>0</min_value> <max_value>100</max_value> </variable> <variable> <variable.name>TotSoilCarb</variable.name> <unit>kg/m^2</unit> <min_value>0</min_value> <max_value>9999</max_value> </variable> </state.variables> <Obs_Prep> <Landtrendr_AGB> <AGB_input_dir>/projectnb/dietzelab/dongchen/Multi-site/download_500_sites/AGB</AGB_input_dir> <allow_download>TRUE</allow_download> <export_csv>TRUE</export_csv> <timestep> <unit>year</unit> <num>1</num> </timestep> </Landtrendr_AGB> <MODIS_LAI> <search_window>30</search_window> <export_csv>TRUE</export_csv> <run_parallel>TRUE</run_parallel> <timestep> <unit>year</unit> <num>1</num> </timestep> </MODIS_LAI> <SMAP_SMP> <search_window>30</search_window> <export_csv>TRUE</export_csv> <update_csv>FALSE</update_csv> <timestep> <unit>year</unit> <num>1</num> </timestep> </SMAP_SMP> <Soilgrids_SoilC> <timestep> <unit>year</unit> <num>1</num> </timestep> </Soilgrids_SoilC> <outdir>/projectnb/dietzelab/dongchen/All_NEON_SDA/test_OBS</outdir> <start.date>2012-07-15</start.date> <end.date>2021-07-15</end.date> </Obs_Prep> <spin.up> <start.date>2004/01/01</start.date> <end.date>2006/12/31</end.date> </spin.up> <forecast.time.step>1</forecast.time.step> <start.date>2004/01/01</start.date> <end.date>2006/12/31</end.date> </state.data.assimilation> <info> <notes></notes> <userid>-1</userid> <username></username> <date>2017/12/06 21:19:33 +0000</date> </info> <outdir>/fs/data3/hamzed/output/MultiSite_Sandbox/paleon_sda_SIPNET-8768</outdir> <database> <bety> <user>bety</user> <password>bety</password> <host>128.197.168.114</host> <dbname>bety</dbname> <driver>PostgreSQL</driver> <write>false</write> </bety> <dbfiles>/fs/data1/pecan.data/dbfiles/</dbfiles> </database> <pfts> <pft> <name>temperate.deciduous_SDA</name> <constants> <num>2</num> </constants> <outdir>/fs/data2/output//PEcAn_1000008768/pft/temperate.deciduous_SDA</outdir> <posteriorid>1000008552</posteriorid> </pft> </pfts> <meta.analysis> <iter>3000</iter> <random.effects> <on>FALSE</on> <use_ghs>TRUE</use_ghs> </random.effects> </meta.analysis> <ensemble> <size>20</size> <ensemble.id>1000016146</ensemble.id> <start.year>1995</start.year> <end.year>1999</end.year> <samplingspace> <parameters> <method>uniform</method> </parameters> <met> <method>sampling</method> </met> <soil> <parent>parameters</parent> </soil> <vegetation> <parent>soil</parent> </vegetation> </samplingspace> </ensemble> <model> <id>1000000022</id> <default.param>/fs/data3/hamzed/output/paleon_sda_SIPNET-8768/Bartlett.param</default.param> <type>SIPNET</type> <revision>r136</revision> <delete.raw>FALSE</delete.raw> <binary>/fs/data5/pecan.models/SIPNET/trunk/sipnet_ssr</binary> </model> <workflow> <id>1000008768</id> </workflow> <run> <settings.1000000650> <site> <id>1000000650</id> <met.start>1960/01/01</met.start> <met.end>1965/12/31</met.end> <name>Harvard Forest - Lyford Plots (PalEON PHA)</name> <lat>42.53</lat> <lon>-72.18</lon> </site> <inputs> <met> <source>CRUNCEP</source> <output>SIPNET</output> <path> <path1>/fs/data1/pecan.data/dbfiles/CRUNCEP_SIPNET_site_0-758/CRUNCEP.1960-01-01.2010-12-31.clim</path1> </path> </met> </inputs> <start.date>1960/01/01</start.date> <end.date>1980/12/31</end.date> </settings.1000000650> <settings.1000000651> <site> <id>1000000651</id> <met.start>1960/01/01</met.start> <met.end>1965/12/31</met.end> <name>Harvard Forest - Lyford Plots (PalEON PHA)</name> <lat>42.53</lat> <lon>-72.18</lon> </site> <inputs> <met> <source>CRUNCEP</source> <output>SIPNET</output> <path> <path1>/fs/data1/pecan.data/dbfiles/CRUNCEP_SIPNET_site_0-758/CRUNCEP.1960-01-01.2010-12-31.clim</path1> </path> </met> </inputs> <start.date>1960/01/01</start.date> <end.date>1980/12/31</end.date> </settings.1000000651> </run> <host> <name>localhost</name> <rundir>/fs/data3/hamzed/output/MultiSite_Sandbox/paleon_sda_SIPNET-8768/run</rundir> <outdir>/fs/data3/hamzed/output/MultiSite_Sandbox/paleon_sda_SIPNET-8768/out</outdir> </host> <settings.info> <deprecated.settings.fixed>TRUE</deprecated.settings.fixed> <settings.updated>TRUE</settings.updated> <checked>TRUE</checked> </settings.info> <rundir>/fs/data3/hamzed/output/MultiSite_Sandbox/paleon_sda_SIPNET-8768/run</rundir> <modeloutdir>/fs/data3/hamzed/output/MultiSite_Sandbox/paleon_sda_SIPNET-8768/out</modeloutdir> <multisettings>run</multisettings> </pecan.multi> 7.2.3 Running SDA on remote In general, the idea is that sending, running and monitoring an SDA job should all be done using two functions (SDA_remote_launcher and Remote_Sync_launcher). SDA_remote_launcher checks the XML settings defining the run, sets up the SDA on the remote machine, and then sends a qusb command for running the job. Remote_Sync_launcher, on the other hand, sits on the local machine and monitors the progress of the job(s) and brings back the outputs as long as the job is running. SDA_remote_launcher sets up the job by copying a template SDA workflow R script and a bash file template that are ready for submission to the remote machine. This function checks the paths to all inputs including met, soil, site_pft and etc., testing whether they exists on the remote machine or not. If they do not exist, the function copies the missing paths over and replaces the settings accordingly. After submitting the bash script, the function returns the PID of the job writing the log file, allowing the Remote_Sync_launcher to monitor the progress of the run, checks to see if the job is still alive, and determines if sda.output.rdata has been updated since the last check or not. Additionally, the Remote_Sync_launcher function follows the progress of the remote job by executing a nohup command on a template R script and keeps the R console open for further use. This R script, as mentioned above, constantly pings the given PID every 5 minutes and copies over the SDA output. Several points on how to prepare your xml settings for the remote SDA run: 1 - In the main pecan workflow.R, if you were able to generate pecan.TRAIT.xml, your settings are ready to be used for an SDA run. All you need to add is your state data assimilation tags. 2 - Inside the xml setting an <outdir> flag needs to be included and point to a local directory where SDA_remote_launcher will look for either a sample.Rdata file or a pft folder. 3 - You need to set your <host> tag according to the desired remote machine. You can learn more about this on the Remote execution with PEcAn section of the documentation. Please make sure that the <folder> tag inside <host> is pointing to a directory where you would like to store and run your SDA job(s). 4 - Finally, make sure the tag inside the tag is set to the correct path on the remote machine. 7.2.4 Restart functionality in SDA If you prefer to run your SDA analysis in multiple stages, where each phase picks up where the previous one left off, you can use the restart argument in the sda.enkf.multisite function. You need to make sure that the output from previous step exists in the SDA folder (in the outfolder), and the <start.date> is the same as <end.date> from the previous step. When you run the SDA with the restart parameter, it will load the output from the previous step and use configs already written in the run folder to set itself up for the next step. Using the restart argument could be as easy as : sda.enkf.multisite(settings, obs.mean =obs.mean , obs.cov = obs.cov, control = SDA.arguments(debug = FALSE, TimeseriesPlot = FALSE), restart = FALSE ) Where the new settings, obs.mean and obs.cov contain the relevant information for the next phase. 7.2.5 State Data Assimilation Methods By Ann Raiho Our goal is build a fully generalizable state data assimilation (SDA) workflow that will assimilate multiple types of data and data products into ecosystem models within PEcAn temporally and spatially. But, during development, specifically with PalEON goals in mind, we have been focusing on assimilating tree ring estimated NPP and AGB and pollen derived fractional composition into two ecosystem models, SIPNET and LINKAGES, at Harvard Forest. This methodology will soon be expanded to include the PalEON sites listed on the state data assimilation wiki page. 7.2.5.1 Data Products During workflow development, we have been working with tree ring estimated NPP and AGB and pollen derived fractional composition data products. Both of these data products have been estimated with a full accounting of uncertainty, which provides us with state variable observation mean vector and covariance matrix at each time step. These data products are discussed in more detail below. Even though we have been working with specific data products during development, our workflow is generalizable to alternative data products as long as we can calculate a state variable observation mean vector and covariance for a time point. 7.2.5.2 Tree Rings We have been primarily been working with the tree ring data product created by Andria Dawson and Chris Paciorek and the PEcAn tree ring allometry module. They have developed a Bayesian model that estimates annual aboveground biomass increment (Mg/ha/yr) and aboveground biomass (Mg/ha) for each tree in a dataset. We obtain this data and aggregate to the level appropriate for the ecosystem model. In SIPNET, we are assimilating annual gross woody increment (Mg/ha/yr) and above ground woody biomass (Mg/ha). In LINKAGES, we are assimilating annual species biomass. More information on deriving these tree ring data products can be found in Dawson et al 201?. We have been working mostly with tree data collected at Harvard Forest. Tree rings and census data were collected at Lyford Plot between 1960 and 2010 in three separate plots. Other tree ring data will be added to this analysis in the future from past PEON courses (UNDERC), Kelly Heilman (Billy’s Lake and Bigwoods), and Alex Dye (Huron Mt. Club). 7.2.5.3 Pollen STEPPS is a Bayesian model developed by Paciorek and McLachlan 2009 and Dawson et al 2016 to estimate spatially gridded fractional composition from fossil pollen. We have been working with STEPPS1 output, specifically with the grid cell that contains Harvard Forest. The temporal resolution of this data product is centennial. Our workflow currently operates at annual time steps, but does not require data at every time step. So, it is possible to assimilate fractional composition every one hundred years or to assimilate fractional composition data every year by accounting for variance inflation. In the future, pollen derived biomass (ReFAB) will also be available for data assimilation. Although, we have not discussed how STEPPS and ReFAB data assimilation will work. 7.2.5.4 Variance Inflation *Side Note: Probably want to call this something else now. Since the fractional composition data product has a centennial resolution, in order to use fractional composition information every year we need to change the weight the data has on the analysis. The basic idea is to downweight the likelihood relative to the prior to account for (a) the fact that we assimilate an observation multiple times and (b) the fact that the number of STEPPS observations is ‘inflated’ because of the autocorrelation. To do this, we take the likelihood and raise it to the power of (1/w) where ‘w’ is an inflation factor. w = D * (N / ESS) where D is the length of the time step. In our case D = 100. N is the number of time steps. In our case N = 11. and ESS is the effective sample size. The ESS is calculated with the following function where ntimes is the same as N above and sims is a matrix with the dimensions number of MCMC samples by number of state variables. ESS_calc <- function(ntimes, sims){ # center based on mean at each time to remove baseline temporal correlation # (we want to estimate effective sample size effect from correlation of the errors) row.means.sims <- sims - rowMeans(sims) # compute all pairwise covariances at different times covars <- NULL for(lag in 1:(ntimes-1)){ covars <- c(covars, rowMeans(row.means.sims[(lag+1):ntimes, , drop = FALSE] * row.means.sims[1:(ntimes-lag), , drop = FALSE])) } vars <- apply(row.means.sims, 1, var) # pointwise post variances at each time, might not be homoscedastic # nominal sample size scaled by ratio of variance of an average # under independence to variance of average of correlated values neff <- ntimes * sum(vars) / (sum(vars) + 2 * sum(covars)) return(neff) } The ESS for the STEPPS1 data product is 3.6, so w in our assimilation of fractional composition at Harvard Forest will be w = 305.6. 7.2.5.5 Current Models SIPNET and LINKAGES are the two ecosystem models that have been used during state data assimilation development within PEcAn. SIPNET is a simple ecosystem model that was built for… LINKAGES is a forest gap model created to simulate the process of succession that occurs when a gap is opened in the forest canopy. LINKAGES has 72 species level plant functional types and the ability to simulate some below ground processes (C and N cycles). 7.2.5.6 Model Calibration Without model calibration both SIPNET and LINKAGES make incorrect predictions about Harvard Forest. To confront this problem, SIPNET and LINKAGES will both be calibrated using data collected at the Harvard Forest flux tower. Istem has completed calibration for SIPNET using a parameter data assimilation emulator contained within the PEcAn workflow. LINKAGES will also be calibrated using this method. This method is also generalizable to other sites assuming there is data independent of data assimilation data available to calibrate against. 7.2.5.7 Initial Conditions The initial conditions for SIPNET are sampled across state space based on data distributions at the time when the data assimilation will begin. We do not sample LINAKGES for initial conditions and instead perform model spin up for 100 years prior to beginning data assimilation. In the future, we would like to estimate initial conditions based on data. We achieve adequate spread in the initial conditions by allowing the parameters to vary across ensemble members. 7.2.5.8 Drivers We are currently using Global Climate Model (GCM) drivers from the PaLEON model intercomparison. Christy Rollinson and John Tipton are creating MET downscaled GCM drivers for the Paleon data assimilation sites. We will use these drivers when they are available because they are a closer representation of reality. 7.2.5.9 Sequential State Data Assimilation We are using sequential state data assimilation methods to assimilate paleon data products into ecosystem models because less computation power is required for sequential state data assimilation than for particle filter methods. 7.2.5.10 General Description The general sequential data assimilation framework consists of three steps at each time step: 1. Read the state variable output for time t from the model forecast ensembles and save the forecast mean (muf) and covariance (Pf). 2. If there are data mean (y) and covariance (R) at this time step, perform data assimilation analysis (either EnKF or generalized ensemble filter) to calculate the new mean (mua) and covariance (Pa) of the state variables. 3. Use mua and Pa to restart and run the ecosystem model ensembles with new state variables for time t+1. 7.2.5.11 EnKF There are two ways to implement sequential state data assimilation at this time. The first is the Ensemble Kalman Filter (EnKF). EnKF has an analytical solution, so the kalman gain, analysis mean vector, and analysis covariance matrix can be calculated directly: K <- Pf %*% t(H) %*% solve((R + H %*% Pf %*% t(H))) ## Kalman Gain mu.a <- mu.f + K %*% (Y - H %*% mu.f) # Analysis mean vector Pa <- (diag(ncol(X)) - K %*% H) %*% Pf # Analysis covariance matrix The EnKF is typically used for sequential state data assimilation, but we found that EnKF lead to filter divergence when combined with our uncertain data products. Filter divergence led us to create a generalized ensemble filter that estimates process variance. 7.2.5.12 Generalized Ensemble Filter The generalized ensemble filter follows generally the three steps of sequential state data assimilation. But, in the generalized ensemble filter we add a latent state vector that accounts for added process variance. Furthermore, instead of solving the analysis analytically like the EnKF, we have to estimate the mean analysis vector and covariance matrix with MCMC. 7.2.5.13 Mapping Ensemble Output to Tobit Space There are some instances when we have right or left censored variables from the model forecast. For example, a model estimating species level biomass may have several ensemble members that produce zero biomass for a given species. We are considering this case a left censored state variable that needs to be mapped to normal space using a tobit model. We do this by creating two matrices with dimensions number of ensembles by state variable. The first matrix is a matrix of indicator variables (y.ind), and the second is a matrix of censored variables (y.censored). When the indicator variable is 0 the state variable (j) for ensemble member (i) is sampled. This allows us to impute a normal distribution for each state variable that contains ‘missing’ forecasts or forecasts of zero. tobit2space.model <- nimbleCode({ for(i in 1:N){ y.censored[i,1:J] ~ dmnorm(muf[1:J], cov = pf[1:J,1:J]) for(j in 1:J){ y.ind[i,j] ~ dconstraint(y.censored[i,j] > 0) } } muf[1:J] ~ dmnorm(mean = mu_0[1:J], cov = pf[1:J,1:J]) Sigma[1:J,1:J] <- lambda_0[1:J,1:J]/nu_0 pf[1:J,1:J] ~ dinvwish(S = Sigma[1:J,1:J], df = J) }) 7.2.5.14 Generalized Ensemble Filter Model Description Below is the BUGS code for the full analysis model. The forecast mean an covariance are calculated from the tobit2space model above. We use a tobit likelihood in this model because there are instances when the data may be left or right censored. Process variance is included by adding a latent model state (X) with a process precision matrix (q). We update our prior on q at each time step using our estimate of q from the previous time step. tobit.model <- nimbleCode({ q[1:N,1:N] ~ dwish(R = aq[1:N,1:N], df = bq) ## aq and bq are estimated over time Q[1:N,1:N] <- inverse(q[1:N,1:N]) X.mod[1:N] ~ dmnorm(muf[1:N], prec = pf[1:N,1:N]) ## Model Forecast ##muf and pf are assigned from ensembles ## add process error X[1:N] ~ dmnorm(X.mod[1:N], prec = q[1:N,1:N]) #agb linear #y_star[1:YN,1:YN] <- X[1:YN,1:YN] #[choose] #f.comp non linear #y_star[1:YN] <- X[1:YN] / sum(X[1:YN]) ## Analysis y.censored[1:YN] ~ dmnorm(X[1:YN], prec = r[1:YN,1:YN]) #is it an okay assumpution to just have X and Y in the same order? #don't flag y.censored as data, y.censored in inits #remove y.censored samplers and only assign univariate samplers on NAs for(i in 1:YN){ y.ind[i] ~ dconstraint(y.censored[i] > 0) } }) 7.2.5.15 Ensemble Adjustment Each ensemble member has a different set of species parameters. We adjust the updated state variables by using an ensemble adjustment. The ensemble adjustment weights the ensemble members based on their likelihood during the analysis step. S_f <- svd(Pf) L_f <- S_f$d V_f <- S_f$v ## normalize Z <- X*0 for(i in seq_len(nrow(X))){ Z[i,] <- 1/sqrt(L_f) * t(V_f)%*%(X[i,]-mu.f) } Z[is.na(Z)]<-0 ## analysis S_a <- svd(Pa) L_a <- S_a$d V_a <- S_a$v ## analysis ensemble X_a <- X*0 for(i in seq_len(nrow(X))){ X_a[i,] <- V_a %*%diag(sqrt(L_a))%*%Z[i,] + mu.a } 7.2.5.16 Diagnostics There are three diagnostics we have currently implemented: time series, bias time series, and process variance. The time series diagnostics show the data, forecast, and analysis time series for each state variable. These are useful for visually assessing variance and magnitude of change of state variables through time. These time series are also updated throughout the analysis and are also created as a pdf at the end of the SDA workflow. There are two types of bias time series the first assess the bias in the update (the forecast minus the analysis) and the second assess the bias in the error (the forecast minus the data). These bias time series are useful for identifying which state variables have intrinsic bias within the model. For example, if red oak biomass in LINKAGES increases at every time step (the update and the error are always positive), this would suggest that LINKAGES has a positive growth or recruitment bias for red oak. Finally, when using the generalized ensemble filter to estimate process variance, there are two additional plots to assess estimation of process variance. The first is a correlation plot of the process covariance matrix. This tells us what correlations are incorrectly represented by the model. For example, if red oak biomass and white pine biomass are highly negatively correlated in the process covariance matrix, this means that the model either 1) has no relationship between red oak and white pine and they should affect each other negatively or 2) there is a positive relationship between red oak and white pine and there shouldn’t be any relationship. We can determine which of these is true by comparing the process covariance matrix to the model covariance matrix. The second process variance diagnostic plot shows how the degrees of freedom associated with estimating the process covariance matrix have changed through time. This plot should show increasing degrees of freedom through time. 7.2.6 MultiSettings (TODO: Under construction…) 7.2.7 Benchmarking Benchmarking is the process of comparing model outputs against either experimental data or against other model outputs as a way to validate model performance. We have a suit of statistical comparisons that provide benchmarking scores as well as visual comparisons that help in diagnosing data-model and/or model-model differences. 7.2.7.1 Data Preparation All data that you want to compare with model runs must be registered in the database. This is currently a step that must be done by hand either from the command line or through the online BETY interface. The data must have three records: An input record (Instructions here) A database file record (Instructions here) A format record (Instructions here) 7.2.7.2 Model Runs Model runs can be setup and executed - Using the PEcAn web interface online or with a VM (see setup) - By hand using the pecan.xml 7.2.7.3 The Benchmarking Shiny App The entire benchmarking process can be done through the Benchmarking R Shiny app. When the model run has completed, navigate to the workflow visualization Shiny app. Load model data Select the workflow and run id Make sure that your model output is loading properly (i.e. you can see plots of your data) Load benchmarking data Again make sure that you can see the uploaded data plotted alongside the model output. In the future there will be more tools for double checking that your uploaded data is appropriate for benchmarking, but for now you may need to do the sanity checks by hand. 7.2.7.4 Create a reference run record Navigate to the Benchmarking tab The first step is to register the new model run as a reference run in the database. Benchmarking cannot be done before this step is completed. When the reference run record has been created, additional menus for benchmarking will appear. 7.2.7.5 Setup Benchmarks and metrics From the menus select The variables in the uploaded data that you wish to compare with model output. The numerical metrics you would like to use in your comparison. Additional comparison plots that you would like to see. Note: All these selections populate the benchmarking section of the pecan.BENCH.xml which is then saved in the same location as the original run output. This xml is purely for reference. 7.2.7.5.1 Benchmarking Output All benchmarking results are stored in the benchmarking directory which is created in the same folder as the original model run. The benchmaking directory contains subdirectories for each of the datasets compared with the model output. The names of these directories are the same as the corresponding data set’s input id in BETY. Each input directory contains benchmarking.output.Rdata, an Rdata file contianing all the results of the benchmarking workflow. load(benchmarking.output.Rdata) loads a list called result.out which contains the following: bench.results: a data frame of all numeric benchmarking scores format: a data frame that can be used to see how the input data was transformed to make it comparable to the model output. This involves converting from the original variable names and units to the internal pecan standard. aligned.dat: a data frame of the final aligned model and input values. All plots are saved as pdf files with names with “benchmark_plot-type_variable_input-id.pdf” To view interactive results, naviage to the Benchmarking Plots tab in the shiny app. 7.2.7.6 Benchmarking in pecan.xml Before reading this section, it is recommended that you familiarize yourself with basics of the pecan.xml file. The pecan.xml has an optional benchmarking section. Below are all the tags in the benchmarking section explained. Many of these field are filled in automatically during the benchmarking process when using the benchmarking shiny app. The only time one should edit the benchmarking section by hand is for performing clone runs. See clone run documentation. <benchmarking> settings: ensemble_id: the id of the ensemble that you will be using - the settings from this ensemble will be saved in a reference run record and then ensemble_id will be replaced with reference_run_id new_run: TRUE = create new run, FALSE = use existing run (required, default FALSE) It is possible to look at more than one benchmark with a particular run. The specific settings related to each benchmark are in a sub section called benchmark input_id: the id of the benchmarking data (required) variable_id: the id of the variable of interest within the data. If you leave this blank, all variables that are shared between the input and model output will be used. metric_id: the id(s) of the metric(s) to be calculated. If you leave this blank, all metrics will be used. Example: In this example, - we are using a pre-existing run from ensemble_id = 1000010983 (new_run = FALSE) - the output will be compared to data from input_id = 1000013743, specifically two variables of interest: variable_id = 411, variable_id = 18 - for variable_id = 411 we will perform only one metric of comparison metric_id = 1000000001 - for for variable_id = 18 we will perform two metrics of comparison metric_id = 1000000001, metric_id = 1000000002 <benchmarking> <ensemble_id>1000010983</ensemble_id> <new_run>FALSE</new_run> <benchmark> <input_id>1000013743</input_id> <variable_id>411</variable_id> <site_id>853</site_id> <metrics> <metric_id>1000000001</metric_id> </metrics> </benchmark> <benchmark> <input_id>1000013743</input_id> <variable_id>18</variable_id> <site_id>853</site_id> <metrics> <metric_id>1000000001</metric_id> <metric_id>1000000002</metric_id> </metrics> </benchmark> </benchmarking> "],["developer-guide.html", "8 Developer guide", " 8 Developer guide Update BETY Update PEcAn Code PEcAn and Git Coding Practices "],["updatebety.html", "8.1 Updating PEcAn Code and Bety Database", " 8.1 Updating PEcAn Code and Bety Database Release notes for all releases can be found here. This page will only list any steps you have to do to upgrade an existing system. When updating PEcAn it is highly encouraged to update BETY. You can find instructions on how to do this, as well on how to update the database in the Updating BETYdb gitbook page. 8.1.1 Updating PEcAn The latest version of PEcAn code can be obtained from the PEcAn repository on GitHub: cd pecan # If you are not already in the PEcAn directory git pull The PEcAn build system is based on GNU Make. The simplest way to install is to run make from inside the PEcAn directory. This will update the documentation for all packages and install them, as well as all required dependencies. For more control, the following make commands are available: make document – Use devtools::document to update the documentation for all package. Under the hood, this uses the roxygen2 documentation system. make install – Install all packages and their dependnencies using devtools::install. By default, this only installs packages that have had their code changed and any dependent packages. make check – Perform a rigorous check of packages using devtools::check make test – Run all unit tests (based on testthat package) for all packages, using devtools::test make clean – Remove the make build cache, which is used to track which packages have changed. Cache files are stored in the .doc, .install, .check, and .test subdirectories in the PEcAn main directory. Running make clean will force the next invocation of make commands to operate on all PEcAn packages, regardless of changes. The following are some additional make tricks that may be useful: Install, check, document, or test a specific package – make .<cmd>/<pkg-dir>; e.g. make .install/utils or make .check/modules/rtm Force make to run, even if package has not changed – make -B <command> Run make commands in parallel – make -j<ncores>; e.g. make -j4 install to install packages using four parallel processes. Note that packages containing compiled code (e.g. PEcAn.RTM, PEcAn.BASGRA) might fail when j is greater than 1, because of limitations in the way R calls make internally while compiling them. See GitHub issue 1976 for more details. All instructions for the make build system are contained in the Makefile in the PEcAn root directory. For full documentation on make, see the man pages by running man make from a terminal. "],["pecan-git.html", "8.2 Git and GitHub Workflow", " 8.2 Git and GitHub Workflow Using Git 8.2.1 Using Git This document describes the steps required to download PEcAn, make changes to code, and submit your changes. If you are new to GitHub or to PEcAn, start with the one-time set-up instructions under Before any work is done. Also see the excellent tutorials and references in the Git) section right below this list and at the bootom in References. To make trivial changes, see [Quick and Easy]. To make a few changes to the code, start with the [Basic Workflow]. To make substantial changes and/or if plan to contribute over time see [Recommended Workflow: A new branch for each change]. 8.2.1.1 Git Git is a free & open source, distributed version control system designed to handle everything from small to very large projects with speed and efficiency. Every Git clone is a full-fledged repository with complete history and full revision tracking capabilities, not dependent on network access or a central server. Branching and merging are fast and easy to do. A good place to start is the GitHub 5 minute illustrated tutorial. In addition, there are three fun tutorials for learning git: Learn Git is a great web-based interactive tutorial. LearnGitBranching TryGit. URLs In the rest of the document will use specific URL’s to clone the code. There a few URL’s you can use to clone a project, using https, ssh and git. You can use either https or git to clone a repository and write to it. The git protocol is read-only. This document describes the steps required to download PEcAn, make changes to code, and submit your changes. If during above process you want to work on something else, commit all your code, create a new branch, and work on new branch. 8.2.1.2 PEcAn Project and Github Organization Repository: https://github.com/organizations/PecanProject PEcAn source code: https://github.com/PecanProject/pecan.git BETYdb source code: https://github.com/PecanProject/bety.git These instructions apply to other repositories too. 8.2.1.3 PEcAn Project Branches We follow branch organization laid out on this page. In short, there are three main branches you must be aware of: develop - Main Branch containing the latest code. This is the main branch you will make changes to. master - Branch containing the latest stable code. DO NOT MAKE CHANGES TO THIS BRANCH. release/vX.X.X - Named branches containing code specific to a release. Only make changes to this branch if you are fixing a bug on a release branch. 8.2.1.4 Milestones, Issues, Tasks The Milestones, issues, and tasks can be used to organize specific features or research projects. In general, there is a heirarchy: milestones (Big picture, “Epic”): contains many issues, organized by release. issues (Specific features / bugs, “Story”): may contain a list of tasks; represent task list (to do list, “Tasks”): list of steps required to close an issue, e.g.: * [ ] first do this * [ ] then this * [ ] completed when x and y 8.2.1.5 Editing files on GitHub The easiest approach is to use GitHub’s browser based workflow. This is useful when your change is a few lines, if you are editing a wiki, or if the edit is trivial (and won’t break the code). The GitHub documentation is here but it is simple: finding the page or file you want to edit, click “edit” and then the GitHub web application will automatically forking and branch, then allow you to submit a pull request. However, it should be noted that unless you are a member of the PEcAn project that the “edit” button will not be active and you’ll want to follow the workflow described below for forking and then submitting a pull request. 8.2.2 Recommended Git Workflow Summary: development should occur on a fork of the main repository. Fork Create Branch Develop Push changes to your fork Create pull request from branch on your fork to develop branch on pecanproject/pecan Each feature should be in its own branch (for example each issue is a branch, names of branches are often the issue in a bug tracking system). Commit and Push Frequency On your branch, commit any time that you have done work that you do not want to re-do. Remember, pushing changes to your branch is like saving a draft. Submit a pull request when you are done. 8.2.2.1 Before any work is done The first step below only needs to be done once when you first start working on the PEcAn code. The steps below that need to be done to set up PEcAn on your computer, and would need to be repeated if you move to a new computer. All contributors should create a fork of the PEcAn source code in their own folder see github help: “fork a repo”). This forked repository will allow you to create branches and submit these changes back to GitHub using pull requests to the develop branch of PEcAn. The pull request will start a review process that will eventually result in the code being merged into the main copy of the codebase. See https://help.github.com/articles/fork-a-repo for more information, especially on how to keep your fork up to date with respect to the original. (Rstudio users should also see Git + Rstudio, below). You can setup SSH keys to make it easier to commit cod back to GitHub. This might especially be true if you are working from a cluster, see set up ssh keys There is a script in the scripts folder called scripts/syncgit.sh that will keep your fork in sync with the main pecanproject repository. Introduce yourself to GIT git config --global user.name "FULLNAME" git config --global user.email you@yourdomain.example.com Fork PEcAn on GitHub. Go to the PEcAn source code and click on the Fork button in the upper right. This will create a copy of PEcAn in your personal space. Clone to your local machine via command line git clone git@github.com:<username>/pecan.git Define PEcAnProject/pecan as upstream repository cd pecan git remote add upstream git@github.com:PecanProject/pecan.git 8.2.2.1.1 Hint: Keeping your fork in sync If you have used the instructions above, you can use the helper script called scripts/syncgit.sh to keep the master and develop branches of your own fork in sync with the PEcAnProject/pecan repository. After following the above, your .git/config file will include the following: ... [remote "origin"] url = git@github.com:<username>/pecan.git fetch = +refs/heads/*:refs/remotes/origin/* [branch "develop"] remote = origin merge = refs/heads/develop [remote "upstream"] url = git@github.com:PecanProject/pecan.git fetch = +refs/heads/*:refs/remotes/upstream/* Then, you can run: ./scripts/syncgit.sh Now the master and develop branches on your fork will be up to date. 8.2.2.2 Using Branching Ideally, a developer should create a new branch for each feature or bug fix Make sure you start in the develop branch git checkout develop Make sure develop is up to date git pull upstream develop Run the PEcAn MAKEFILE to compile code from the main directory. make Create a new branch and switch to it git checkout -b <branchname> Work/commit/etc git add <file_that_was_changed.R> git commit -m "<some descriptive information about what was done>" Make sure that code compiles and documentation updated. The make document command will run roxygenise. make document make Push this branch to your github space git push origin <branchname> submit pull request with [[link commits to issues|Using-Git#link-commits-to-issuess]]; also see github documentation 8.2.2.3 After pull request is merged Make sure you start in master git checkout develop` delete branch remotely git push origin --delete <branchname>` delete branch locally git branch -D <branchname>` 8.2.2.4 Link commits to issues You can reference and close issues from comments, pull requests, and commit messages. This should be done when you commit code that is related to or will close/fix an existing issue. There are two ways to do this. One easy way is to include the following text in your commit message: Github to close: “closes gh-xxx” (or syn. close, closed, fixes, fix, fixed) to reference: just the issue number (e.g. “gh-xxx”) 8.2.3 Useful Git tools 8.2.3.1 GitHub Desktop The easiest way to get working with GitHub is by installing the GitHub client. For instructions for your specific OS and download of the GitHub client, see https://help.github.com/articles/set-up-git. This will help you set up an SSH key to push code back to GitHub. To check out a project you do not need to have an ssh key and you can use the https or git url to check out the code. 8.2.3.2 Git + Rstudio Rstudio is nicely integrated with many development tools, including git and GitHub. It is quite easy to check out source code from within the Rstudio program or browser. The Rstudio documentation includes useful overviews of version control and R package development. Once you have git installed on your computer (see the Rstudio version control documentation for instructions), you can use the following steps to install the PEcAn source code in Rstudio. 8.2.4 Advanced 8.2.4.1 Fixing a release Branch If you would like to make changes to a release branch, you must follow a different workflow, as the release branch will not contain the latest code on develop and must remain seperate. Fetch upstream remote branches git fetch upstream Checkout the correct release branch git checkout -b release/vX.Y.Z Compile Code with make make Make changes and commit them git add <changed_file.R> git commit -m \"Describe changes\" Compile and make roxygen changes make make document Commit and push any files that were changed by make document Make a pull request. It is essential that you compare your pull request to the remote release branch, NOT the develop branch. 8.2.4.2 Tags Git supports two types of tags: lightweight and annotated. For more information see the Tagging Chapter in the Git documentation. Lightweight tags are useful, but here we discuss the annotated tags that are used for marking stable versions, major releases, and versions associated with published results. The basic command is git tag. The -a flag means ‘annotated’ and -m is used before a message. Here is an example: git tag -a v0.6 -m \"stable version with foo and bar features, used in the foobar publication by Bob\" Adding a tag to the a remote repository must be done explicitly with a push, e.g. git push v0.6 To use a tagged version, just checkout: git checkout v0.6 To tag an earlier commit, just append the commit SHA to the command, e.g.  git tag -a v0.99 -m \"last version before 1.0\" 9fceb02 8.2.5 References 8.2.5.1 Git Documentation Scott Chacon, ‘Pro Git book’, http://git-scm.com/book GitHub help pages, https://help.github.com/ Main GIT page http://git-scm.com/documentation Another set of pages about branching, http://sandofsky.com/blog/git-workflow.html Stackoverflow highest voted questions tagged “git” 8.2.5.2 GitHub Documentation When in doubt, the first step is to click the “Help” button at the top of the page. GitHub Flow by Scott Chacon (Git evangelist and Ruby developer working on GitHub.com) GitHub FAQ Using Pull Requests SSH Keys 8.2.6 GitHub use with PEcAn In this section, development topics are introduced and discussed. PEcAn code lives within the If you are looking for an issue to work on, take a look through issues labled “good first issue”. To get started you will want to review We use GitHub to track development. To learn about GitHub, it is worth taking some time to read through the FAQ. When in doubt, the first step is to click the “Help” button at the top of the page. To address specific people, use a github feature called @mentions e.g. write @dlebauer, @robkooper, @mdietze, or @serbinsh … in the issue to alert the user as described in the GitHub documentation on notifications 8.2.6.1 Bugs, Issues, Features, etc. 8.2.6.2 Reporting a bug (For developers) work through debugging. Once you have identified a problem, that you can not resolve, you can write a bug report Write a bug report submit the bug report If you do find the answer, explain the resolution (in the issue) and close the issue 8.2.6.3 Required content Note: a bug is only a bug if it is reproducible clear bug reports save time Clear, specific title Description - What you did What you expected to happen What actually happened What does work, under what conditions does it fail? Reproduction steps - minimum steps required to reproduce the bug additional materials that could help identify the cause: screen shots stack traces, logs, scripts, output specific code and data / settings / configuration files required to reproduce the bug environment (operating system, browser, hardware) 8.2.6.4 Requesting a feature (from The Pragmatic Programmer, available as ebook through UI libraries, hardcopy on David’s bookshelf) focus on “user stories”, e.g. specific use cases Be as specific as possible, Here is an example: Bob is at www.mysite.edu/maps map of the the region (based on user location, e.g. US, Asia, etc) option to “use current location” is provided, if clicked, map zooms in to, e.g. state or county level for site run: option to select existing site or specify point by lat/lon option to specify a bounding box and grid resolution in either lat/lon or polar stereographic. asked to specify start and end times in terms of year, month, day, hour, minute. Time is recorded in UTC not local time, this should be indicated. 8.2.6.5 Closing an issue Definition of “Done” test documentation when issue is resolved: status is changed to “resolved” assignee is changed to original author if original author agrees that issue has been resolved original author changes status to “closed” except for trivial issues, issues are only closed by the author 8.2.6.6 When to submit an issue? Ideally, non-trivial code changes will be linked to an issue and a commit. This requires creating issues for each task, making small commits, and referencing the issue within your commit message. Issues can be created on GitHub. These issues can be linked to commits by adding text such as fixes gh-5). Rationale: This workflow is a small upfront investment that reduces error and time spent re-creating and debugging errors. Associating issues and commits, makes it easier to identify why a change was made, and potential bugs that could arise when the code is changed. In addition, knowing which issue you are working on clarifies the scope and objectives of your current task. "],["coding-practices.html", "8.3 Coding Practices", " 8.3 Coding Practices 8.3.1 Coding Style Consistent coding style improves readability and reduces errors in shared code. Unless otherwise noted, PEcAn follows the Tidyverse style guide, so please familiarize yourself with it before contributing. In addition, note the following: Document all functions using roxygen2. See Roxygen2 for more details. Put your name on things. Any function that you create or make a meaningful contribution to should have your name listed after the author tag in the function documentation. It is also often a good idea to add your name to extended comments describing particularly complex or strange code. Write unit tests with testthat. Tests are a complement to documentation - they define what a function is (and is not) expected to do. Not all functions necessarily need unit tests, but the more tests we have, the more confident we can be that changes don’t break existing code. Whenever you discover and fix a bug, it is a good idea to write a unit test that makes sure the same bug won’t happen again. See Unit_Testing for instructions, and Advanced R: Tests. Do not use abbreviations. Always write out TRUE and FALSE (i.e. do not use T or F). Do not rely on partial argument matching – write out all arguments in full. Avoid dots in function names. R’s S3 methods system uses dots to denote object methods (e.g. print.matrix is the print method for objects of class matrix), which can cause confusion. Use underscores instead (e.g. do_analysis instead of do.analysis). (NOTE that many old PEcAn functions violate this convention. The plan is to deprecate those in PEcAn 2.0. See GitHub issue #392). Use informative file names with consistent extensions. Standard file extensions are .R for R scripts, .rds for individual objects (via saveRDS function), and .RData (note: capital D!) for multiple objects (via the save function). For function source code, prefer multiple files with fewer functions in each to large files with lots of files (though it may be a good idea to group closely related functions in a single file). File names should match, or at least closely reflect, their files (e.g. function do_analysis should be defined in a file called do_analysis.R). Do not use spaces in file names – use dashes (-) or underscores (_). For using external packages, add the package to Imports: and call the corresponding function with package::function. Do not use @importFrom package function or, worse yet, @import package. (The exception is infix operators like magrittr::%>% or ggplot2::%+%, which can be imported via roxygen2 documentation like @importFrom magrittr %>%). Do not add packages to Depends. In general, try to avoid adding new dependencies (especially ones that depend on system libraries) unless they are necessary or already widely used in PEcAn (e.g. GDAL, NetCDF, XML, JAGS, dplyr). For a more thorough and nuanced discussion, see the package dependencies appendix. "],["dplyr.html", "9 dplyr", " 9 dplyr When running devtools::check() a common warning relating to dplyr code is “no visible binding for global variable ‘x’” In data-masking situations (e.g. mutate(), filter()), you can eliminate this warning by using the .data pronoun. For example, instead of df %>% mutate(newvar = oldvar + 2), use df %>% mutate(newvar = .data$oldvar + 2). In tidy-select situations (e.g. select(), rename()), you can eliminate this warning by using strings instead of naked column names. For example, instead of df %>% select(y) use df %>% select(\"y\"). Using .data inside of select() is deprecated as of tidyselect v1.2.0 9.0.1 Logging During development we often add many print statements to check to see how the code is doing, what is happening, what intermediate results there are etc. When done with the development it would be nice to turn this additional code off, but have the ability to quickly turn it back on if we discover a problem. This is where logging comes into play. Logging allows us to use “rules” to say what information should be shown. For example when I am working on the code to create graphs, I do not have to see any debugging information about the SQL command being sent, however trying to figure out what goes wrong during a SQL statement it would be nice to show the SQL statements without adding any additional code. PEcAn provides a set of logger.* functions that should be used in place of base R’s stop, warn, print, and similar functions. The logger functions make it easier to print to a system log file, and to control the level of output produced by PEcAn. The file test.logger.R provides descriptive examples This query provides an current overview of functions that use logging Logger functions and their corresponding levels (in order of increasing level): logger.debug (\"DEBUG\") – Low-level diagnostic messages that are hidden by default. Good examples of this are expanded file paths and raw results from database queries or other analyses. logger.info (\"INFO\") – Informational messages that regular users may want to see, but which do not indicate anything unexpected. Good examples of this are progress updates updates for long-running processes, or brief summaries of queries or analyses. logger.warn (\"WARN\") – Warning messages about issues that may lead to unexpected but valid results. Good examples of this are interactions between arguments that lead to some arguments being ignored or removal of missing or extreme values. logger.error (\"ERROR\") – Error messages from which PEcAn has some capacity to recover. Unless you have a very good reason, we recommend avoiding this in favor of either logger.severe to actually stop execution or logger.warn to more explicitly indicate that the problem is not fatal. logger.severe – Catastrophic errors that warrant immediate termination of the workflow. This is the only function that actually stops R’s execution (via stop). The logger.setLevel function sets the level at which a message will be printed. For instance, logger.setLevel(\"WARN\") will suppress logger.info and logger.debug messages, but will print logger.warn and logger.error messages. logger.setLevel(\"OFF\") suppresses all logger messages. To print all messages to console, use logger.setUseConsole(TRUE) 9.0.2 Package Data 9.0.2.1 Summary: Files with the following extensions will be read by R as data: plain R code in .R and .r files are sourced using source() text tables in .tab, .txt, .csv files are read using read() ** objects in R image files: .RData, .rda are loaded using load() capitalization matters all objects in foo.RData are loaded into environment pro: easiset way to store objects in R format con: format is application (R) specific Details are in ?data, which is mostly a copy of Data section of Writing R Extensions. 9.0.2.2 Accessing data Data in the [data] directory will be accessed in the following ways, efficient way: (especially for large data sets) using the data function: data(foo) # accesses data with, e.g. load(foo.RData), read(foo.csv), or source(foo.R) easy way: by adding the following line to the package DESCRIPTION: note: this should be used with caution or it can cause difficulty as discussed in redmine issue #1118 LazyData: TRUE From the R help page: Currently, a limited number of data formats can be accessed using the data function by placing one of the following filetypes in a packages’ data directory: * files ending .R or .r are source()d in, with the R working directory changed temporarily to the directory containing the respective file. (data ensures that the utils package is attached, in case it had been run via utils::data.) * files ending .RData or .rda are load()ed. * files ending .tab, .txt or .TXT are read using read.table(..., header = TRUE), and hence result in a data frame. * files ending .csv or .CSV are read using read.table(..., header = TRUE, sep = ';'), and also result in a data frame. If your data does not fall in those 4 categories, or you can use the system.file function to get access to the data: system.file("data", "ed.trait.dictionary.csv", package="PEcAn.utils") [1] "/home/kooper/R/x86_64-pc-linux-gnu-library/2.15/PEcAn.utils/data/ed.trait.dictionary.csv" The arguments are folder, filename(s) and then package. It will return the fully qualified path name to a file in a package, in this case it points to the trait data. This is almost the same as the data function, however we can now use any function to read the file, such as read.csv instead of read.csv2 which seems to be the default of data. This also allows us to store arbitrary files in the data folder, such as the the bug file and load it when we need it. 9.0.2.2.1 Examples of data in PEcAn packages outputs: [/modules/uncertainties/data/output.RData] parameter samples [/modules/uncertainties/data/samples.RData] 9.0.3 Documenting functions using roxygen2 This is the standard method for documenting R functions in PEcAn. For detailed instructions, see one of the following resources: roxygen2 pacakge documentation Formatting overview Markdown formatting Namespaces (e.g. when to use @export) From “R packages” by Hadley Wickham: Object Documentation Package Metadata Below is a complete template for a Roxygen documentation block. Note that roxygen lines start with #': #' Function title, in a few words #' #' Function description, in 2-3 sentences. #' #' (Optional) Package details. #' #' @param argument_1 A description of the argument #' @param argument_2 Another argument to the function #' @return A description of what the function returns. #' #' @author Your name <your_email@email.com> #' @examples #' \\dontrun{ #' # This example will NOT be run by R CMD check. #' # Useful for long-running functions, or functions that #' # depend on files or values that may not be accessible to R CMD check. #' my_function("~/user/my_file") #'} # # This example WILL be run by R CMD check #' my_function(1:10, argument_2 = 5) ## ^^ A few examples of the function's usage #' @export # ^^ Whether or not the function will be "exported" (made available) to the user. # If omitted, the function can only be used inside the package. my_function <- function(argument_1, argument_2) {...} Here is a complete example from the PEcAn.utils::days_in_year() function: #' Number of days in a year #' #' Calculate number of days in a year based on whether it is a leap year or not. #' #' @param year Numeric year (can be a vector) #' @param leap_year Default = TRUE. If set to FALSE will always return 365 #' #' @author Alexey Shiklomanov #' @return integer vector, all either 365 or 366 #' @export #' @examples #' days_in_year(2010) # Not a leap year -- returns 365 #' days_in_year(2012) # Leap year -- returns 366 #' days_in_year(2000:2008) # Function is vectorized over years days_in_year <- function(year, leap_year = TRUE) {...} To update documentation throughout PEcAn, run make document in the PEcAn root directory. Make sure you do this before opening a pull request – PEcAn’s automated testing (Travis) will check if any documentation is out of date and will throw an error like the following if it is: These files were changed by the build process: {...} 9.0.3.1 Updating to a new Roxygen version For consistency across packages and machines, all PEcAn developers need to compile documentation with the same version of Roxygen. Roxygen itself will check for this and refuse to rebuild a package that was last touched by a newer version of Roxygen, but the warning it gives is very quiet and easy to miss. We take a louder approach by hardcoding the expected Roxygen version into PEcAn’s Makefile and throwing a build failure if the installed Roxygen is not an exact match. When it is time for everyone to update to a newer Roxygen, follow the same procedure we used when updating from 7.2.3 to 7.3.1, replacing version strings as appropriate: Before starting, work with the team to merge/close as many existing PRs as feasible – this process touches a lot of files and is likely to create merge conflicts in other PRs. Edit the Makefile to change EXPECTED_ROXYGEN_VERSION := 7.2.3 to EXPECTED_ROXYGEN_VERSION := 7.3.1. Run make clean && make document to be sure Roxygen has been run on all packages. Check the console output for warnings from Roxygen, and fix them as needed. New versions often get pickier about formatting issues that used to be considered minor. Run ./scripts/generate_dependencies.R to update the version of Roxygen recorded as a Docker dependency. Grep the PEcAn folder for the string 7.2.3 to make sure no references were missed. e.g. this time I found a remaining RoxygenNote: 7.2.3 in models/cable/DESCRIPTION – Make currently skips cable, so I redocumented it manually. Review all changes. The changes should mostly just consist of updated RoxygenNote: lines in all the DESCRIPTION files. In all cases but extra-double-specially if any NAMESPACE files change, make sure you understand what happened rather than blindly committing the changes. Usually the new version is an improvement, but this is the time to check. Once all looks good, commit and push. Make a loud announcement, e.g. on Slack, to tell all developers to update roxygen2 on their machines as soon as the PR is merged. "],["developer-testing.html", "9.1 Testing", " 9.1 Testing PEcAn uses two different kinds of testing – unit tests and integration tests. 9.1.1 Unit testing Unit tests are short (<1 minute runtime) tests of functionality of specific functions. Ideally, every function should have at least one unit test associated with it. A unit test should be written for each of the following situations: Each bug should get a regression test. The first step in handling a bug is to write code that reproduces the error This code becomes the test most important when error could re-appear essential when error silently produces invalid results Every time a (non-trivial) function is created or edited Write tests that indicate how the function should perform example: expect_equal(sum(1,1), 2) indicates that the sum function should take the sum of its arguments Write tests for cases under which the function should throw an error example: expect_error(sum(\"foo\")) better : expect_error(sum(\"foo\"), \"invalid 'type' (character)\") Any functionality that you would like to protect over the long term. Functionality that is not tested is more likely to be lost. PEcAn uses the testthat package for unit testing. A general overview of is provided in the “Testing” chapter of Hadley Wickham’s book “R packages”. Another useful resource is the testthat package documentation website. See also our testthat appendix. Below is a lightning introduction to unit testing with testthat. Each package’s unit tests live in .R scripts in the folder <package>/tests/testthat. In addition, a testthat-enabled package has a file called <packagename>/tests/testthat.R with the following contents: library(testthat) library(<packagename>) test_check("<packagename>") Tests should be placed in <packagename>/tests/testthat/test-<sourcefilename>.R, and look like the following: context("Mathematical operators") test_that("mathematical operators plus and minus work as expected",{ sum1 <- sum(1, 1) expect_equal(sum1, 2) sum2 <- sum(-1, -1) expect_equal(sum2, -2) expect_equal(sum(1,NA), NA) expect_error(sum("cat")) set.seed(0) expect_equal(sum(matrix(1:100)), sum(data.frame(1:100))) }) test_that("different testing functions work, giving excuse to demonstrate",{ expect_identical(1, 1) expect_identical(numeric(1), integer(1)) expect_equivalent(numeric(1), integer(1)) expect_warning(mean('1')) expect_that(mean('1'), gives_warning("argument is not numeric or logical: returning NA")) expect_warning(mean('1'), "argument is not numeric or logical: returning NA") expect_message(message("a"), "a") }) 9.1.2 Integration testing Integration tests consist of running the PEcAn workflow in full. One way to do integration tests is to manually run workflows for a given version of PEcAn, either through the web interface or by manually creating a pecan.xml file. Such manual tests are an important part of checking PEcAn functionality. Alternatively, the base/workflow/inst/batch_run.R script can be used to quickly run a series of user-specified integration tests without having to create a bunch of XML files. This script is powered by the PEcAn.workflow::create_execute_test_xml() function, which takes as input information about the model, meteorology driver, site ID, run dates, and others, uses these to construct a PEcAn XML file, and then uses the system() command to run a workflow with that XML. If run without arguments, batch_run.R will try to run the model configurations specified in the base/workflow/inst/default_tests.csv file. This file contains a CSV table with the following columns: model – The name of the model (models.model_name column in BETY) revision – The version of the model (models.revision column in BETY) met – The name of the meteorology driver source site_id – The numeric site ID for the model run (sites.site_id) pft – The name of the plant functional type to run. If NA, the script will use the first PFT associated with the model. start_date, end_date – The start and end dates for the model run, respectively. These should be formatted according to ISO standard (YYYY-MM-DD, e.g. 2010-03-16) sensitivity – Whether or not to run the sensitivity analysis. TRUE means run it, FALSE means do not. ensemble_size – The number of ensemble members to run. Set this to 1 to do a single run at the trait median. comment – An string providing some user-friendly information about the run. The batch_run.R script will run a workflow for every row in the input table, sequentially (for now; eventually, it will try to run them in parallel), and at the end of each workflow, will perform some basic checks, including whether or not the workflow finished and if the model produced any output. These results are summarized in a CSV table (by default, a file called test_result_table.csv), with all of the columns as the input test CSV plus the following: outdir – Absolute path to the workflow directory. workflow_complete – Whether or not the PEcAn workflow completed. Note that this is a relatively low bar – PEcAn workflows can complete without having run the model or finished some other steps. has_jobsh – Whether or not PEcAn was able to write the model’s job.sh script. This is a good indication of whether or not the model’s write.configs step was successful, and may be useful for separating model configuration errors from model execution errors. model_output_raw – Whether or not the model produced any output files at all. This is just a check to see of the <workflow>/out directory is empty or not. Note that some models may produce logfiles or similar artifacts as soon as they are executed, whether or not they ran even a single timestep, so this is not an indication of model success. model_output_processed – Whether or not PEcAn was able to post-process any model output. This test just sees if there are any files of the form YYYY.nc (e.g. 1992.nc) in the <workflow>/out directory. Right now, these checks are not particularly robust or comprehensive, but they should be sufficient for catching common errors. Development of more, better tests is ongoing. The batch_run.R script can take the following command-line arguments: --help – Prints a help message about the script’s arguments --dbfiles=<path> – The path to the PEcAn dbfiles folder. The default value is ~/output/dbfiles, based on the file structure of the PEcAn VM. Note that for this and all other paths, if a relative path is given, it is assumed to be relative to the current working directory, i.e. the directory from which the script was called. --table=<path> – Path to an alternate test table. The default is the base/workflow/inst/default_tests.csv file. See preceding paragraph for a description of the format. --userid=<id> – The numeric user ID for registering the workflow. The default value is 99000000002, corresponding to the guest user on the PEcAn VM. --outdir=<path> – Path to a directory (which will be created if it doesn’t exist) for storing the PEcAn workflow outputs. Default is batch_test_output (in the current working directory). --pecandir=<path> – Path to the PEcAn source code root directory. Default is the current working directory. --outfile=<path> – Full path (including file name) of the CSV file summarizing the results of the runs. Default is test_result_table.csv. The format of the output 9.1.3 Continuous Integration Every time anyone commits a change to the PEcAn code, the act of pushing to GitHub triggers an automated build and test of the full PEcAn codebase, and all pull requests must report a successful CI build before they will be merged. This will sometimes feel like a burden when the build breaks on an issue that looks trivial, but anything that breaks the build is important enough to fix. It’s much better to find errors early and fix them before they get incorporated into the released PEcAn code. At this writing PEcAn’s CI builds primarily use GitHub Actions and the rest of this section assumes a GitHub Actions. All our GitHub Actions builds run in a containers using different versions of R in parallel. The build will use the latest pecan/depends container for that specific R version. Each night this depends image is rebuild. Each build starts by launching a separate clean virtual machine for each R version and performs roughly the following actions on all of them: * Compile the source code in the container - Installs all the R packages that are declared as dependencies in any PEcAn package, as computed by scripts/generate_dependencies.R. - This will also check to see if any files have been modified during this step * Run the tests inside the container, and checks to see if they all pass - This will also check to see if any files have been modified during this step * Run the doxygen command inside the container - This will also check to see if any files have been modified during this step * Run the check command inside the container, and checks if there are any new warnings and/or errors - Runs package unit tests (the same ones you run locally with make test or devtools::test(pkgname)). - As discussed in Unit testing, these tests should run quickly and test individual components in relative isolation. - Any test that calls the skip_on_ci function will be skipped. This is useful for tests that need to run for a very long time (e.g. large data product downloads) or require resources that aren’t available on Travis (e.g. specific models), but be sure to run these tests locally before pushing your code! - This will also check to see if any files have been modified during this step - Any ERROR in the check output will stop the build immediately. - If there are no ERRORs, any WARNINGs or NOTEs are compared against a stored historic check result in <package>/tests/Rcheck_reference.log. If the package has no stored reference result, all WARNINGs and NOTEs are considered newly added and reported as build failures. - If all messages from the current built were also present in the reference result, the check passes. If any messages are newly added, a build failure is reported. - Each line of the check log is considered a separate message, and the test requires exact matching, so a change from Undocumented arguments in documentation object 'foo': 'x' to Undocumented arguments in documentation object 'foo': 'x', 'y' will be counted as a new warning… and you should fix both of them while you’re at it! - The idea here is to enforce good coding practice and catch likely errors in all new code while recognizing that we have a lot of legacy code whose warnings need to be fixed as we have time rather than all at once. - As we fix historic warnings, we will revoke their grandfathered status by removing them from the stored check results, so that they will break the build if they reappear. - If your PR reports a failure in pre-existing code that you think ought to be grandfathered, please fix it as part of your PR anyway. It’s frustrating to see tests complain about code you didn’t touch, but the failures all need to be cleaned up eventually and it’s likely easier to fix the error than to figure out how to re-ignore it. * Run a simple integration test using SIPNET model * Create the docker images - Once your PR is merged, it will push them to DockerHub and github container repository. * Compiles the PEcAn documentation book (book_source) and the tutorials (documentation/tutorials) and uploads them to the PEcAn website. - This is only done for commits to the master or develop branch, so changes to in-progress pull requests never change the live documentation until after they are merged. If your build fails and indicates that files have been modified there are a few common causes. It should also list the files that have changes, and what has changed. * The most common cause is that you forgot to Roxygenize before committing. * This step will also detect newly added files, e.g. tests improperly writing to the current working directory rather than tempdir() and then failing to clean up after themselves. If any of the actionsreports an error, the build is marked as “failed”. If they all pass, the GitHub actions marks the build as successful and tells the PR that it’s OK to allow your changes to be merged… but the final decision belongs to the human reviewing your code and they might still ask you for other changes! "],["download-and-compile-pecan.html", "9.2 Download and Compile PEcAn", " 9.2 Download and Compile PEcAn Set R_LIBS_USER CRAN Reference # point R to personal lib folder echo 'export R_LIBS_USER=${HOME}/R/library' >> ~/.profile source ~/.profile mkdir -p ${R_LIBS_USER} 9.2.1 Download, compile and install PEcAn from GitHub # download pecan cd git clone https://github.com/PecanProject/pecan.git # compile pecan cd pecan make For more information on the capabilities of the PEcAn Makefile, check out our section on Updating PEcAn. Following will run a small script to setup some hooks to prevent people from using the pecan demo user account to check in any code. # prevent pecan user from checking in code ./scripts/create-hooks.sh 9.2.2 PEcAn Testrun Do the run, this assumes you have installed the BETY database, sites tar file and SIPNET. # create folder cd mkdir testrun.pecan cd testrun.pecan # copy example of pecan workflow and configuration file cp ../pecan/tests/pecan32.sipnet.xml pecan.xml cp ../pecan/scripts/workflow.R workflow.R # exectute workflow rm -rf pecan ./workflow.R pecan.xml NB: pecan.xml is configured for the virtual machine, you will need to change the field from ‘/home/carya/’ to wherever you installed your ‘sites’, usually $HOME "],["directory-structure.html", "9.3 Directory structure", " 9.3 Directory structure 9.3.1 Overview of PEcAn repository as of PEcAn 1.5.3 pecan/ +- base/ # Core functions +- all # Dummy package to load all PEcAn R packages +- db # Modules for querying the database +- logger # Report warnings without killing workflows +- qaqc # Model skill testing and integration testing +- remote # Communicate with and execute models on local and remote hosts +- settings # Functions to read and manipulate PEcAn settings files +- utils # Misc. utility functions +- visualization # Advanced PEcAn visualization module +- workflow # functions to coordinate analysis steps +- book_source/ # Main documentation and developer's guide +- CHANGELOG.md # Running log of changes in each version of PEcAn +- docker/ # Experimental replacement for PEcAn virtual machine +- documentation # index_vm.html, references, other misc. +- models/ # Wrappers to run models within PEcAn +- ed/ # Wrapper scripts for running ED within PEcAn +- sipnet/ # Wrapper scripts for running SIPNET within PEcAn +- ... # Wrapper scripts for running [...] within PEcAn +- template/ # Sample wrappers to copy and modify when adding a new model +- modules # Core modules +- allometry +- data.atmosphere +- data.hydrology +- data.land +- meta.analysis +- priors +- rtm +- uncertainty +- ... +- scripts # R and Shell scripts for use with PEcAn +- shiny/ # Interactive visualization of model results +- tests/ # Settings files for host-specific integration tests +- web # Main PEcAn website files 9.3.2 Generic R package structure: see the R development wiki for more information on writing code and adding data. +- DESCRIPTION # short description of the PEcAn library +- R/ # location of R source code +- man/ # Documentation (automatically compiled by Roxygen) +- inst/ # files to be installed with package that aren't R functions +- extdata/ # misc. data files (in misc. formats) +- data/ # data used in testing and examples (saved as *.RData or *.rda files) +- NAMESPACE # declaration of package imports and exports (automatically compiled by Roxygen) +- tests/ # PEcAn testing scripts +- testthat/ # nearly all tests should use the testthat framework and live here "],["working-with-vm.html", "10 VM configuration and maintenance ", " 10 VM configuration and maintenance "],["maintain-vm.html", "10.1 Updating the VM", " 10.1 Updating the VM The PEcAn VM is distributed with specific versions of PEcAn compiled. However, you do not need to constantly download the VM in order to update your code and version of BETY. To update and maintain your code you can follow the steps found in the Developer section in Updating PecAn and Code and BETY Database. However, if you are using the latest version of the PEcAn VM (>=1.7) you have the Dockerized version of PEcAn and need to follow the instructions under the DOCKER section to update your PEcAn and BETY containers. "],["ssh-vm.html", "10.2 Connecting to the VM via SSH", " 10.2 Connecting to the VM via SSH Once the VM is running anywhere on your machine, you can connect to it from a separate terminal via SSH as follows: ssh -p 6422 carya@localhost You will be prompted for a password. Like everywhere else in PEcAn, the username is carya and the password is illinois. The same password is used for any system maintenance you wish to do on the VM via sudo. As a shortcut, you can add the following to your ~/.ssh/config file (or create one if it does not exist). Host pecan-vm Hostname localhost Port 6422 user carya ForwardX11Trusted yes This will allow you to SSH into the VM with the simplified command, ssh pecan-vm. "],["ssh-vm-bety.html", "10.3 Connecting to BETYdb on the VM via SSH", " 10.3 Connecting to BETYdb on the VM via SSH Sometimes, you may want to develop code locally but connect to an instance of BETYdb on the VM. To do this, first open a new terminal and connect to the VM while enabling port forwarding (with the -L flag) and setting the port number. Using 5433 does not conflict with the postgres default port of 5432, the forwarded port will not conflict with a postgres database server running locally. ssh -L 5433:localhost:5432 carya@localhost:6422 This makes port 5433 on the local machine match port 5432 on the VM. This means that connecting to localhost:5433 will give you access to BETYdb on the VM. To test this on the command line, try the following command, which, if successful, will drop you into the psql console. psql -d bety -U bety -h localhost -p 5433 To test this in R, open a Postgres using the analogous parameters: library(DBI) library(RPostgres) con <- dbConnect( drv = Postgres(), user = "bety", password = "bety", dbname = "bety", host = "localhost", port = 5433 ) dbListTables(con) # This should return a vector of bety tables Note that the same general approach will work on any BETYdb server where port forwarding is enabled, but it requires ssh access. 10.3.1 Using Amazon Web Services for a VM (AWS) Login to Amazon Web Services (AWS) and select the EC2 Dashboard. If this is your first time using AWS you will need to set up an account before you are able to access the EC2 Dashboard. Important: You will need a credit card number and access to a phone to be able to verify AWS account registration. AWS is free for one year. Choose AMI On the top right next to your name, make sure the location setting is on U.S. East (N. Virginia), not U.S. West (Oregon) On the left click, click on EC2 (Virtual servers), then click on “AMIs”, also on the left In the search window toggle to change “Owned by me” to “Public images” Type “pecan” into the search window Click on the toggle button on the left next to PEcAn1.4.6 Click on the “Launch” button at the top Choose an Instance Type Select what type of machine you want to run. For this demo the default, t2.micro, will be adequate. Be aware that different machine types incur very different costs, from 1.3 cents/hour to over $5/hr https://aws.amazon.com/ec2/pricing/ Select t2.micro, then click “Next: Configure Instance Details” Configure Instance Details The defaults are OK. Click “Next: Add Storage” Add Storage The defaults are OK. Click “Next: Tag Instance” Tag Instance You can name your instance if you want. Click “Next: Configure Security Group” Configure Security Group You will need to add two new rules: Click “Add Rule” then select “HTTP” from the pull down menu. This rule allows you to access the webserver on PEcAn. Click “Add Rule”, leave the pull down on “Custom TCP Rule”, and then change the Port Range from 0 to 8787. Set “Source” to Anywhere. This rule allows you to access RStudio Server on PEcAn. Click “Review and Launch” . You will then see this pop-up: Select the default drive volume type and click Next Review and Launch Review the settings and then click “Launch”, which will pop up a select/create Key Pair window. Key Pair Select “Create a new key pair” and give it a name. You won’t actually need this key unless you need to SSH into your PEcAn server, but AWS requires you to create one. Click on “Download Key Pair” then on “Launch Instances”. Next click on “View Instances” at the bottom of the following page. Instances You will see the status of your PEcAn VM, which will take a minute to boot up. Wait until the Instance State reads “running”. The most important piece of information here is the Public IP, which is the URL you will need in order to access your PEcAn instance from within your web browser (see Demo 1 below). Be aware that it often takes ~1 hr for AWS instances to become fully operational, so if you get an error when you put the Public IP in you web browser, most of the time you just need to wait a bit longer. Congratulations! You just started a PEcAn server in the “cloud”! When you are done using PEcAn, you will want to return to the “Instances” menu to turn off your VM. To STOP the instance (which will turn the machine off but keep your work), select your PEcAn instance and click Actions > Instance state > Stop. Be aware that a stopped instance will still accrue a small storage cost on AWS. To restart this instance at any point in the future you do not want to repeat all the steps above, but instead you just need to select your instance and then click Actions > Instance state > Start To TERMINATE the instance (which will DELETE your PEcAn machine), select your instance and click Actions > Instance state > Terminate. Terminated instances will not incur costs. In most cases you will also want to go to the Volumes menu and delete the storage associated with your PEcAn VM.Remember, AWS is free for one year, but will automatically charge a fee in second year if account is not cancelled. 10.3.2 Creating a Virtual Machine First create virtual machine # ---------------------------------------------------------------------- # CREATE VM USING FOLLOWING: # - VM NAME = PEcAn # - CPU = 2 # - MEMORY = 2GB # - DISK = 100GB # - HOSTNAME = pecan # - FULLNAME = PEcAn Demo User # - USERNAME = xxxxxxx # - PASSWORD = yyyyyyy # - PACKAGE = openssh # ---------------------------------------------------------------------- To enable tunnels run the following on the host machine: VBoxManage modifyvm "PEcAn" --natpf1 "ssh,tcp,,6422,,22" VBoxManage modifyvm "PEcAn" --natpf1 "www,tcp,,6480,,80" Make sure machine is up to date. UBUNTU sudo apt-get update sudo apt-get -y dist-upgrade sudo reboot CENTOS/REDHAT sudo yum -y update sudo reboot Install compiler and other packages needed and install the tools. UBUNTU sudo apt-get -y install build-essential linux-headers-server dkms CENTOS/REDHAT sudo yum -y groupinstall "Development Tools" sudo yum -y install wget Install Virtual Box additions for better integration sudo mount /dev/cdrom /mnt sudo /mnt/VBoxLinuxAdditions.run sudo umount /mnt sudo usermod -a -G vboxsf carya Finishing up the machine Add a message to the login: sudo -s export PORT=$( hostname | sed 's/pecan//' ) cat > /etc/motd << EOF PEcAn version 1.4.3 For more information about: Pecan - http://pecanproject.org BETY - http://www.betydb.org For a list of all models currently navigate [here](../users_guide/basic_users_guide/models_table.md) You can access this system using a webbrowser at http://<hosting machine>:${PORT}80/ or using SSH at ssh -l carya -p ${PORT}22 <hosting machine> where <hosting machine> is the machine where the VM runs on. EOF exit Finishing up Script to clean the VM and remove as much as possible history cleanvm.sh wget -O ~/cleanvm.sh http://isda.ncsa.uiuc.edu/~kooper/EBI/cleanvm.sh chmod 755 ~/cleanvm.sh Make sure machine has SSH keys rc.local sudo wget -O /etc/rc.local http://isda.ncsa.illinois.edu/~kooper/EBI/rc.local Change the resolution of the console sudo sed -i -e 's/#GRUB_GFXMODE=640x480/GRUB_GFXMODE=1024x768/' /etc/default/grub sudo update-grub Once all done, stop the virtual machine history -c && ${HOME}/cleanvm.sh "],["pecan-standards.html", "11 PEcAn standard formats ", " 11 PEcAn standard formats "],["defining-new-input-formats.html", "11.1 Defining new input formats", " 11.1 Defining new input formats New formats can be defined on the ‘formats’ page of BETYdb After creating a new format, the contents should be defined by specifying the BETYdb variable name and the name used in the file/ "],["time-standard.html", "11.2 Time Standard", " 11.2 Time Standard Internal PEcAn standard time follows ISO_8601 format for dates and time (https://en.wikipedia.org/wiki/ISO_8601). For example ordinal dates go from 1 365/366 (https://en.wikipedia.org/wiki/ISO_8601#Ordinal_dates). However, time used in met drivers or model outputs follows CF convention with julian dates following the 0 to 364/365 format To aid in the conversion between PEcAn internal ISO_8601 standard and CF convention used in all met drivers and PEcAn standard output you can utilize the functions: “cf2datetime”,“datetime2doy”,“cf2doy”, and for SIPNET “sipnet2datetime” 11.2.1 Input Standards 11.2.1.1 Meterology Standards 11.2.1.1.1 Dimensions: CF standard-name units time days since 1700-01-01 00:00:00 UTC longitude degrees_east latitude degrees_north General Note: dates in the database should be date-time (preferably with timezone), and datetime passed around in PEcAn should be of type POSIXct. 11.2.1.1.2 The variable names should be standard_name preferred variables indicated in bold wind_direction has no CF equivalent and should not be converted, instead the met2CF functions should convert wind_direction and wind_speed to eastward_wind and northward_wind standard_name is CF-convention standard names units can be converted by udunits, so these can vary (e.g. the time denominator may change with time frequency of inputs) soil moisture for the full column, rather than a layer, is soil_moisture_content A full list of PEcAn standard variable names, units and dimensions can be found here: https://github.com/PecanProject/pecan/blob/develop/base/utils/data/standard_vars.csv For example, in the MsTMIP-CRUNCEP data, the variable rain should be precipitation_rate. We want to standardize the units as well as part of the met2CF.<product> step. I believe we want to use the CF “canonical” units but retain the MsTMIP units any time CF is ambiguous about the units. The key is to process each type of met data (site, reanalysis, forecast, climate scenario, etc) to the exact same standard. This way every operation after that (extract, gap fill, downscale, convert to a model, etc) will always have the exact same inputs. This will make everything else much simpler to code and allow us to avoid a lot of unnecessary data checking, tests, etc being repeated in every downstream function. 11.2.2 Soils and Vegetation Inputs 11.2.2.0.1 Soil Data Check out the Soil Data section on more into on creating a standard soil data file. 11.2.2.0.2 Vegetation Data Check Out the Vegetation Data section on more info on creating a standard vegetation data file 11.2.3 Output Standards created by model2netcdf functions based on format used by MsTMIP Can be seen at HERE We originally used the MsTMIP conventions. Since then, we’ve added the PaLEON variable conventions to our standard as well. If a variable isn’t in one of those two, we stick to the CF conventions. "],["pecanXML.html", "12 The PEcAn XML", " 12 The PEcAn XML The PEcAn system is configured using a XML file, often called pecan.xml. It contains the following major sections (“nodes”): Core configuration Top level structure info – Run metadata outdir – Output directory database – PEcAn database settings pft – Plant functional type selection meta.analysis – Trait meta analysis model – Model configuration run – Run setup host – Host information for remote execution Advanced features ensemble – Ensemble runs sensitivity.analysis – Sensitivity analysis parameter.data.assimilation – Parameter data assimilation multi.settings – Multi Site Settings (experimental) state.data.assimilation – State data assimilation (experimental) browndog – Brown Dog configuration (experimental) benchmarking – Benchmarking remote_process – Remote data module A basic example looks like this: <?xml version="1.0" encoding="UTF-8"?> <pecan> <info> <notes>Example run</notes> <userid>-1</userid> <username>guestuser</username> <date>2018/09/18 19:12:28 +0000</date> </info> <outdir>/data/workflows/PEcAn_99000000006</outdir> <database> <bety> <user>bety</user> <password>bety</password> <host>postgres</host> <dbname>bety</dbname> <driver>PostgreSQL</driver> <write>true</write> </bety> <dbfiles>/data/dbfiles</dbfiles> </database> <pfts> <pft> <name>tundra.grasses</name> <constants> <num>1</num> </constants> </pft> </pfts> <meta.analysis> <iter>3000</iter> <random.effects> <on>FALSE</on> <use_ghs>TRUE</use_ghs> </random.effects> </meta.analysis> <ensemble> <size>1</size> <variable>NPP</variable> <samplingspace> <parameters> <method>uniform</method> </parameters> <met> <method>sampling</method> </met> </samplingspace> </ensemble> <model> <id>5000000002</id> </model> <workflow> <id>99000000006</id> </workflow> <run> <site> <id>1000000098</id> <met.start>2004/01/01</met.start> <met.end>2004/12/31</met.end> </site> <inputs> <met> <source>CRUNCEP</source> <output>SIPNET</output> </met> </inputs> <start.date>2004/01/01</start.date> <end.date>2004/12/31</end.date> </run> <host> <name>localhost</name> <rabbitmq> <uri>amqp://guest:guest@rabbitmq:5672/%2F</uri> <queue>SIPNET_136</queue> </rabbitmq> </host> </pecan> In the following sections, we step through each of these sections in detail. "],["xml-core-config.html", "12.1 Core configuration", " 12.1 Core configuration 12.1.1 Top-level structure The first line of the XML file should contain version and encoding information. <?xml version="1.0" encoding="UTF-8"?> The rest of the XML file should be surrounded by <pecan>...</pecan> tags. <pecan> ...XML body here... </pecan> 12.1.2 info: Run metadata This section contains run metadata. This information is not essential to a successful model run, but is useful for tracking run provenance. <info> <notes>Example run</notes> <userid>-1</userid> <username>guestuser</username> <date>2018/09/18 19:12:28 +0000</date> </info> The <notes> tag will be filled in by the web GUI if you provide notes, or you can add notes yourself within these tags. We suggest adding notes that help identify your run and a brief description of what the run is for. Because these notes are searchable within the PEcAn database and web interface, they can be a useful way to distinguish between similar runs. The <userid> and <username> section is filled in from the GUI if you are signed in. If you are not using the GUI, add the user name and ID you are associated with that exists within the PEcAn database. The <date></date> tag is filled automatically at the time of your run from the GUI. If you are not using the GUI, add the date you execute the run. This tag is not the tag for the dates you would like to run your model simulation. 12.1.3 outdir: Output directory The <outdir> tag is used to configure the output folder used by PEcAn. This is the directory where all model input and output files will be stored. By default, the web interface names this folder PEcAn_<workflow ID>, and higher-level location is set by the $output_folder$ variable in the web/config.php file. If no outdir is specified, PEcAn defaults to the working directory from which it is called, which may be counterintuitive. <outdir>/data/workflows/PEcAn_99000000006</outdir> 12.1.4 database: PEcAn database settings 12.1.4.1 bety: PEcAn database (Bety) configuration The bety tag defines the driver to use to connect to the database (we support PostgreSQL, which is the default, and Postgres) and parameters required to connect to the database. Note that connection parameters are passed exactly as entered to the underlying R database driver, and any invalid or extra parameters will result in an error. In other words, this configuration… <database> ... <bety> <user>bety</user> <password>bety</password> <host>postgres</host> <dbname>bety</dbname> <driver>PostgreSQL</driver> <port>5432</port> <write>true</write> </bety> ... </database> …will be translated (by way of PEcAn.DB::db.open(settings$database$bety)) into R code like the following: con <- DBI::dbConnect( drv = RPostgreSQL::PostgreSQL(), user = "bety", password = "bety", dbname = "bety", host = "postgres", port = "5432", write = TRUE ) Common parameters are described as follows: driver: The driver to use to connect to the database. This should always be set to PostgreSQL, unless you absolutely know what you’re doing. dbname: The name of the database (formerly name), corresponding to the -d argument to psql. In most cases, this should be set to bety, and will only be different if you named your Bety instance something else (e.g. if you have multiple instances running at once). If unset, it will default to the user name of the current user, which is usually wrong! user: The username to connect to the database (formerly userid), corresponding to the -U argument to psql. default value is the username of the current user logged in (PostgreSQL uses user for this field). password: The password to connect to the database (was passwd), corresponding to the -p argument to psql. If unspecified, no password is used. On standard PEcAn installations, the username and password are both bety (all lowercase). host: The hostname of the bety database, corresponding to the -h argument to psql. On the VM, this will be localhost (the default). If using docker, this will be the name of the PostgreSQL container, which is postgres if using our standard docker-compose. If connecting to the PEcAn database on a remote server (e.g. psql-pecan.bu.edu), this should be the same as the hostname used for ssh access. write: Logical. If true (the default), write results to the database. If false, PEcAn will run but will not store any information to bety. When using the web interface, this section is configured by the web/config.php file. The default config.php settings on any given platform (VM, Docker, etc.) or in example files (e.g. config.php.example) are a good place to get default values for these fields if writing pecan.xml by hand. Key R functions using these parameters are as follows: PEcAn.DB::db.open – Open a database connection and create a connection object, which is used by many other functions for communicating with the PEcAn database. 12.1.4.2 dbfiles: Location of database files The dbfiles is a path to the local location of files needed to run models using PEcAn, including model executables and inputs. <database> ... <dbfiles>/data/dbfiles</dbfiles> ... </database> 12.1.4.3 (Experimental) fia: FIA database connection parameters If a version of the FIA database is available, it can be configured using <fia> node, whose syntax is identical to that of the <bety> node. <database> ... <fia> <dbname>fia5data</dbname> <username>bety</username> <password>bety</password> <host>localhost</host> </fia> ... </database> Currently, this is only used for extraction of specific site vegetation information (notably, for ED2 css, pss, and site files). Stability not ensured as of 1.5.3. 12.1.5 pft: Plant functional type selection The PEcAn system requires at least 1 plant functional type (PFT) to be specified inside the <pfts> section. <pfts> <pft> <name>tundra.grasses</name> <constants> <num>1</num> </constants> <posterior.files>Path to a post.distns.*.Rdata or prior.distns.Rdata</posterior.files> </pft> </pfts> name : (required) the name of the PFT, which must exactly match the name in the PEcAn database. outdir: (optional) Directory path in which PFT-specific output will be stored during meta-analysis and sensitivity analysis. If not specified (recommended), it will be written into <outdir>/<pftname>. contants: (optional) this section contains information that will be written directly into the model specific configuration files. For example, some models like ED2 use PFT numbers instead of names for PFTs, and those numbers can be specified here. See documentation for model-specific code for details. posterior.files (Optional) this tag helps to signal write.config functions to use specific posterior/prior files (such as HPDA or MA analysis) for generating samples without needing to access to the bety database. `` This information is currently used by the following PEcAn workflow function: get.traits - ?????? 12.1.6 meta.analysis: Trait Meta Analysis The section meta.analysis needs to exists for a meta.analysis to be executed, even though all tags inside are optional. Conversely, if you do not want to do a trait meta-analysis (e.g. if you want to manually set all parameters), you should omit this node. <meta.analysis> <iter>3000</iter> <random.effects> <on>FALSE</on> <use_ghs>TRUE</use_ghs> </random.effects> </meta.analysis> Some of the tags that can go in this section are: iter: MCMC (Markov Chain Monte Carlo) chain length, i.e. the total number of posterior samples in the meta-analysis, default is 3000. Smaller numbers will run faster but produce larger errors. random.effects: Settings related to whether to include random effects (site, treatment) in meta-analysis model. on: Default is set to FALSE to work around convergence problems caused by an over parameterized model (e.g. too many sites, not enough data). Can be turned to TRUE for including hierarchical random effects. use_ghs: Default is set to TRUE to include greenhouse measurements. Can be set to FALSE to exclude cases where all data is from greenhouse. update: Should previous results of meta.analysis and get.traits be re-used. If set to TRUE the meta-analysis and get.trait.data will always be executed. Setting this to FALSE will try and reuse existing results. Future versions will allow for AUTO as well which will try and reuse if the PFT/traits have not changed. The default value is FALSE. threshold: threshold for Gelman-Rubin convergence diagnostic (MGPRF); default is 1.2. This information is currently used by the following PEcAn workflow function: PEcAn.MA::run.meta.analysis - ??? 12.1.7 model: Model configuration This section describes which model PEcAn should run and some instructions for how to run it. <model> <id>7</id> <type>ED2</type> <binary>/usr/local/bin/ed2.r82</binary> <prerun>module load hdf5</prerun> <config.header> <!--...xml code passed directly to config file...--> </config.header> </model> Some important tags are as follows: id – The unique numeric ID of the model in the PEcAn database models table. If this is present, then type and binary are optional since they can be determined from the PEcAn database. type – The model “type”, matching the PEcAn database modeltypes table name column. This also refers to which PEcAn model-specific package will be used. In PEcAn, a “model” refers to a specific version (e.g. release, git commit) of a specific model, and “model type” is used to link different releases of the same model. Model “types” also have specific PFT definitions and other requirements associated with them (e.g. the ED2 model “type” requires a global land cover database). binary – The file path to the model executable. If omitted, PEcAn will use whatever path is registered in the PEcAn database for the current machine. prerun – Additional options added to the job.sh script, which is used to execute the model. This is useful for setting specific environment variables, load modules, etc. This information is currently used by the following PEcAn workflow function: PEcAn.<MODEL>::write.config.<MODEL> – Write model-specific configuration files PEcAn.workflow::start_model_runs – Begin model run execution 12.1.7.1 Model-specific configuration See the following: ED2 Configuration SIPNET Configuration BIOCRO Configuration 12.1.7.2 ED2 specific tags Following variables are ED specific and are used in the ED2 Configuration. Starting at 1.3.7 the tags for inputs have moved to <run><inputs>. This includes, veg, soil, psscss, inputs. <edin>/home/carya/runs/PEcAn_4/ED2IN.template</edin> <config.header> <radiation> <lai_min>0.01</lai_min> </radiation> <ed_misc> <output_month>12</output_month> </ed_misc> </config.header> <phenol.scheme>0</phenol.scheme> edin : [required] template used to write ED2IN file veg : OBSOLETE [required] location of VEG database, now part of <run><inputs> soil : OBSOLETE [required] location of soild database, now part of <run><inputs> psscss : OBSOLETE [required] location of site inforation, now part of <run><inputs>. Should be specified as <pss>, <css> and <site>. inputs : OBSOLETE [required] location of additional input files (e.g. data assimilation data), now part of <run><inputs>. Should be specified as <lu> and <thsums>. 12.1.8 run: Run Setup This section provides detailed configuration for the model run, including the site and time period for the simulation and what input files will be used. <run> <site> <id>1000000098</id> <met.start>2004/01/01</met.start> <met.end>2004/12/31</met.end> <site.pft> <pft.name>temperate.needleleaf.evergreen</pft.name> <pft.name>temperate.needleleaf.evergreen.test</pft.ame> </site.pft> </site> <inputs> <met> <source>CRUNCEP</source> <output>SIPNET</output> </met> <poolinitcond> <source>NEON_veg</source> <output>poolinitcond</output> <ensemble>100</ensemble> <startdate>2019-01-01</startdate> <enddate>2019-12-31</enddate> <storedir>/projectnb/dietzelab/neon_store</storedir> </poolinitcond> </inputs> <start.date>2004/01/01</start.date> <end.date>2004/12/31</end.date> <stop_on_error>TRUE</stop_on_error> </run> 12.1.8.1 site: Where to run the model This contains the following tags: id – This is the numeric ID of the site in the PEcAn database (table sites, column id). PEcAn can automatically fill in other relevant information for the site (e.g. name, lat, lon) using the site ID, so those fields are optional if ID is provided. name – The name of the site, as a string. lat, lon – The latitude and longitude coordinates of the site, as decimals. met.start, met.end – ??? <site.pft> (optional) If this tag is found under the site tag, then PEcAn automatically makes sure that only PFTs defined under this tag is used for generating parameter’s samples. Following shows an example of how this tag can be added to the PEcAn xml : <site.pft> <pft.name>temperate.needleleaf.evergreen</pft.name> <pft.name>temperate.needleleaf.evergreen</pft.name> </site.pft> For multi-site runs if the pft.site tag (see {#xml-run-inputs}) is defined under input, then the above process will be done automatically under prepare settings step in PEcAn main workflow and there is no need for adding the tags manually. Using the pft.site tag however, requires a lookup table as an input (see {#xml-run-inputs}). 12.1.8.2 inputs: Model inputs Models require several different types of inputs to run. Exact requirements differ from model to model, but common inputs include meteorological/climate drivers, site initial conditions (e.g. vegetation composition, carbon pools), and land use drivers. In general, all inputs should have the following tags: id: Numeric ID of the input in the PEcAn database (table inputs, column id). If not specified, PEcAn will try to figure this out based on the source tag (described below). path: The file path of the input. Usually, PEcAn will set this automatically based on the id (which, in turn, is determined from the source). However, this can be set manually for data that PEcAn does not know about (e.g. data that you have processed yourself and have not registered with the PEcAn database). source: The input data type. This tag name needs to match the names in the corresponding conversion functions. If you are using PEcAn’s automatic input processing, this is the only field you need to set. However, this field is ignored if id and/or path are provided. output: ??? The following are the most common types of inputs, along with their corresponding tags: 12.1.8.2.1 met: Meteorological inputs (Under construction. See the PEcAn.data.atmosphere package, located in modules/data.atmosphere, for more details.) 12.1.8.2.2 (Experimental) soil: Soil inputs (Under construction. See the PEcAn.data.land package, located in modules/data.land, for more details). 12.1.8.2.3 (Experimental) veg: Vegetation initial conditions 12.1.8.2.4 poolinitcond: initial condition inputs source: Data source of initial condition .rd veg files ex: NEON_veg, FIA. output: This tag can only must match the cooresponding tag in the modeltypes_formats table that matches with your model type ex for SIPNET model tag is poolinitcond. ensemble: Number of initial conditions ensemble member files ex: 30. (Under construction. Follow developments in the PEcAn.data.land package, located in modules/data.land in the source code). 12.1.8.2.5 pft.site Multi-site site / PFT mapping When performing multi-site runs, it is not uncommon to find that different sites need to be run with different PFTs, rather than running all PFTs at all sites. If you’re interested to use a specific PFT for your site/sites you can use the following tag to tell PEcAn which PFT needs to be used for what site. <pft.site> <path>site_pft.csv</path> </pft.site> For example using the above tag, user needs to have a csv file named site_pft stored in the pecan folder. At the moment we have functions supporting just the .csv and .txt files which are comma separated and have the following format: site_id, pft_name 1000025731,temperate.broadleaf.deciduous 764,temperate.broadleaf.deciduous Then pecan would use this lookup table to inform write.ensemble.config function about what PFTs need to be used for what sites. 12.1.8.3 start.date and end.date The start and end date for the run, in a format parseable by R (e.g. YYYY/MM/DD or YYYY-MM-DD). These dates are inclusive; in other words, they refer to the first and last days of the run, respectively. NOTE: Any time-series inputs (e.g. meteorology drivers) must contain all of these dates. PEcAn tries to detect and throw informative errors when dates are out of bounds inputs, but it may not know about some edge cases. 12.1.8.4 Other tags The following tags are optional run settings that apply to any model: jobtemplate: the template used when creating a job.sh file, which is used to launch the actual model. Each model has its own default template in the inst folder of the corresponding R package (for instance, here is the one for ED2). The following variables can be used: @SITE_LAT@, @SITE_LON@, @SITE_MET@, @START_DATE@, @END_DATE@, @OUTDIR@, @RUNDIR@ which all come variables in the pecan.xml file. The following two command can be used to copy and clean the results from a scratch folder (specified as scratch in the run section below, for example local disk vs network disk) : @SCRATCH_COPY@, @SCRATCH_CLEAR@. stop_on_error: (logical) Whether the workflow should immediately terminate if any of the model runs fail. If unset, this defaults to TRUE unless you are running an ensemble simulation (and ensemble size is greater than 1). Some models also have model-specific tags, which are described in the PEcAn Models section. 12.1.9 host: Host information for remote execution This section provides settings for remote model execution, i.e. any execution that happens on a machine (including “virtual” machines, like Docker containers) different from the one on which the main PEcAn workflow is running. A common use case for this section is to submit model runs as jobs to a high-performance computing cluster. If no host tag is provided, PEcAn assumes models are run on localhost, a.k.a. the same machine as PEcAn itself. For detailed instructions on remote execution, see the Remote Execution page. For detailed information on configuring this for RabbitMQ, see the RabbitMQ page. The following provides a quick overview of XML tags related to remote execution. NOTE: Any paths specified in the pecan.xml refer to paths on the host specified in this section, /not/ the machine on which PEcAn is running (unless models are running on localhost or this section is omitted). <host> <name>pecan2.bu.edu</name> <rundir>/fs/data3/guestuser/pecan/testworkflow/run</rundir> <outdir>/fs/data3/guestuser/pecan/testworkflow/out</outdir> <scratchdir>/tmp/carya</scratchdir> <clearscratch>TRUE</clearscratch> <qsub>qsub -N @NAME@ -o @STDOUT@ -e @STDERR@ -S /bin/bash</qsub> <qsub.jobid>Your job ([0-9]+) .*</qsub.jobid> <qstat>'qstat -j @JOBID@ &amp;> /dev/null || echo DONE'</qstat> <prerun>module load udunits R/R-3.0.0_gnu-4.4.6</prerun> <cdosetup>module load cdo/2.0.6</cdosetup> <modellauncher> <binary>/usr/local/bin/modellauncher</binary> <qsub.extra>-pe omp 20</qsub.extra> </modellauncher> </host> The host section has the following tags: name: [optional] name of host server where model is located and executed, if not specified localhost is assumed. folder: [required] The location to store files on the remote machine. For localhost this is optional (<outdir> is the default), for any other host this is required. rundir: [optional] location where all the configuration files are written. If not specified, this will be generated starting at the path specified in folder. outdir: [optional] location where all the outputs of the model are written. If not specified, this will be generated starting at the path specified in folder. scratchdir: [optional] location where output is written. If specified the output from the model is written to this folder and copied to the outdir when the model is finished, this could significantly speed up the model execution (by using local or ram disk). clearscratch: [optional] if set to TRUE the scratchfolder is cleaned up after copying the results to the outdir, otherwise the folder will be left. The default is to clean up after copying. qsub: [optional] the command to submit a job to the queuing system. There are 3 parameters you can use when specifying the qsub command, you can add additional values for your specific setup (for example -l walltime to specify the walltime, etc). You can specify @NAME@ the pretty name, @STDOUT@ where to write stdout and @STDERR@, where to write stderr. You can specify an empty element (<qsub/>) in which case it will use the default value is qsub -V -N @NAME@ -o @STDOUT@ -e @STDERR@ -s /bin/bash. qsub.jobid: [optional] the regular expression used to find the jobid returned from qsub. If not specified (and qsub is) it will use the default value is Your job ([0-9]+) .* qstat: [optional] the command to execute to check if a job is finished, this should return DONE if the job is finished. There is one parameter this command should take @JOBID@ which is the ID of the job as returned by qsub.jobid. If not specified (and qsub is) it will use the default value is qstat -j @JOBID@ || echo DONE prerun: [optional] additional options to add to the job.sh at the top. cdosetup: [optional] additional options to add to the job.sh at the top, specifically work for the CDO Linux command line package, allowing the user to generate the full year netCDF file through model2netcdf.SIPNET function (there has been an issue while this function will iteratively overlap the previous netCDF file, resulting in partial data loss). modellauncher: [optional] this is an experimental section that will allow you to submit all the runs as a single job to a HPC system. The modellauncher section if specified will group all runs together and only submit a single job to the HPC cluster. This single job will leverage of a MPI program that will execute a single run. Some HPC systems will place a limit on the number of jobs that can be executed in parallel, this will only submit a single job (using multiple nodes). In case there is no limit on the number of jobs, a single PEcAn run could potentially submit a lot of jobs resulting in the full cluster running jobs for a single PEcAn run, preventing others from executing on the cluster. The modellauncher has 3 arguments: * binary : [required] The full path to the binary modellauncher. Source code for this file can be found in pecan/contrib/modellauncher](https://github.com/PecanProject/pecan/tree/develop/contrib/modellauncher). * qsub.extra : [optional] Additional flags to pass to qsub besides those specified in the qsub tag in host. This option can be used to specify that the MPI environment needs to be used and the number of nodes that should be used. * mpirun: [optional] Additional commands to be added to the front of launcher.sh. Default is mpirun <path to binary> <path to joblist.txt>. Edit this to, for example, load necessary modules to run mpirun. "],["xml-advanced.html", "12.2 Advanced features", " 12.2 Advanced features 12.2.1 ensemble: Ensemble Runs As with meta.analysis, if this section is missing, then PEcAn will not do an ensemble analysis. <ensemble> <size>1</size> <variable>NPP</variable> <samplingspace> <parameters> <method>uniform</method> </parameters> <met> <method>sampling</method> </met> </samplingspace> </ensemble> An alternative configuration is as follows: <ensemble> <size>5</size> <variable>GPP</variable> <start.year>1995</start.year> <end.year>1999</end.year> <samplingspace> <parameters> <method>lhc</method> </parameters> <met> <method>sampling</method> </met> </samplingspace> </ensemble> Tags in this block can be broken down into two categories: Those used for setup (which determine how the ensemble analysis runs) and those used for post-hoc analysis and visualization (i.e. which do not affect how the ensemble is generated). Tags related to ensemble setup are: size : (required) the number of runs in the ensemble. samplingspace: (optional) Contains tags for defining how the ensembles will be generated. Each piece in the sampling space can potentially have a method tag and a parent tag. Method refers to the sampling method and parent refers to the cases where we need to link the samples of two components. When no tag is defined for one component, one sample will be generated and used for all the ensembles. This allows for partitioning/studying different sources of uncertainties. For example, if no met tag is defined then, one met path will be used for all the ensembles and as a result the output uncertainty will come from the variability in the parameters. At the moment no sampling method is implemented for soil and vegetation. Available sampling methods for parameters can be found in the documentation of the PEcAn.utils::get.ensemble.samples function. For the cases where we need simulations with a predefined set of parameters, met and initial condition we can use the restart argument. Restart needs to be a list with name tags of runid, inputs, new.params (parameters), new.state (initial condition), ensemble.id (ensemble ids), start.time, and stop.time. The restart functionality is developed using model specific functions by called write_restart.modelname. You need to make sure first that this function is already exist for your desired model. Note: if the ensemble size is set to 1, PEcAn will select the posterior median parameter values rather than taking a single random draw from the posterior Tags related to post-hoc analysis and visualization are: variable: (optional) name of one (or more) variables the analysis should be run for. If not specified, sensitivity.analysis variable is used, otherwise default is GPP (Gross Primary Productivity). (NOTE: This static visualization functionality will soon be deprecated as PEcAn moves towards interactive visualization tools based on Shiny and htmlwidgets). This information is currently used by the following PEcAn workflow functions: PEcAn.<MODEL>::write.config.<MODEL> - See above. PEcAn.uncertainty::write.ensemble.configs - Write configuration files for ensemble analysis PEcAn.uncertainty::run.ensemble.analysis - Run ensemble analysis 12.2.2 sensitivity.analysis: Sensitivity analysis Only if this section is defined a sensitivity analysis is done. This section will have <quantile> or <sigma> nodes. If neither are given, the default is to use the median +/- [1 2 3] x sigma (e.g. the 0.00135 0.0228 0.159 0.5 0.841 0.977 0.999 quantiles); If the 0.5 (median) quantile is omitted, it will be added in the code. <sensitivity.analysis> <quantiles> <sigma>-3</sigma> <sigma>-2</sigma> <sigma>-1</sigma> <sigma>1</sigma> <sigma>2</sigma> <sigma>3</sigma> </quantiles> <variable>GPP</variable> <perpft>TRUE</perpft> <start.year>2004</start.year> <end.year>2006</end.year> </sensitivity.analysis> quantiles/sigma : [optional] The number of standard deviations relative to the standard normal (i.e. “Z-score”) for which to perform the ensemble analysis. For instance, <sigma>1</sigma> corresponds to the quantile associated with 1 standard deviation greater than the mean (i.e. 0.681). Use a separate <sigma> tag, all under the <quantiles> tag, to specify multiple quantiles. Note that we do not automatically add the quantile associated with -sigma – i.e. if you want +/- 1 standard deviation, then you must include both <sigma>1</sigma> and <sigma>-1</sigma>. start.date : [required?] start date of the sensitivity analysis (in YYYY/MM/DD format) end.date : [required?] end date of the sensitivity analysis (in YYYY/MM/DD format) NOTE: start.date and end.date are distinct from values set in the run tag because this analysis can be done over a subset of the run. variable : [optional] name of one (or more) variables the analysis should be run for. If not specified, sensitivity.analysis variable is used, otherwise default is GPP. perpft : [optional] if TRUE a sensitivity analysis on PFT-specific outputs will be run. This is only possible if your model provides PFT-specific outputs for the variable requested. This tag only affects the output processing, not the number of samples proposed for the analysis nor the model execution. This information is currently used by the following PEcAn workflow functions: PEcAn.<MODEL>::write.configs.<MODEL> – See above PEcAn.uncertainty::run.sensitivity.analysis – Executes the uncertainty analysis 12.2.3 Parameter Data Assimilation The following tags can be used for parameter data assimilation. More detailed information can be found here: Parameter Data Assimilation Documentation 12.2.4 Multi-Settings Multi-settings allows you to do multiple runs across different sites. This customization can also leverage site group distinctions to expedite the customization. It takes your settings and applies the same settings, changing only the site level tags across sites. To start, add the multisettings tag within the <run></run> section of your xml <multisettings> <multisettings>run</multisettings> <multisettings> Additional tags for this section exist and can fully be seen here: <multisettings> <multisettings>assim.batch</multisettings> <multisettings>ensemble</multisettings> <multisettings>sensitivity.analysis</multisettings> <multisettings>run</multisettings> </multisettings> These tags correspond to different pecan analysis that need to know that there will be multiple settings read in. Next you’ll want to add the following tags to denote the group of sites you want to use. It leverages site groups, which are defined in BETY. <sitegroup> <id>1000000022</id> </sitegroup> If you add this tag, you must remove the <site> </site> tags from the <run> tag portion of your xml. The id of your sitegroup can be found by lookig up your site group within BETY. You do not have to use the sitegroup tag. You can manually add multiple sites using the structure in the example below. Lastly change the top level tag to <pecan.multi>, meaning the top and bootom of your xml should look like this: <?xml version="1.0"?> <pecan.multi> ... </pecan.multi> Once you have defined these tags, you can run PEcAn, but there may be further specifications needed if you know that different data sources have different dates available. Run workflow.R up until # Write pecan.CHECKED.xml PEcAn.settings::write.settings(settings, outputfile = "pecan.CHECKED.xml") Once this section is run, you’ll need to open pecan.CHECKED.xml. You will notice that it has expanded from your original pecan.xml. <run> <settings.1> <site> <id>796</id> <met.start>2005/01/01</met.start> <met.end>2011/12/31</met.end> <name>Bartlett Experimental Forest (US-Bar)</name> <lat>44.06464</lat> <lon>-71.288077</lon> </site> <start.date>2005/01/01</start.date> <end.date>2011/12/31</end.date> <inputs> <met> <path>/fs/data1/pecan.data/dbfiles/AmerifluxLBL_SIPNET_site_0-796/AMF_US-Bar_BASE_HH_4-1.2005-01-01.2011-12-31.clim</path> </met> </inputs> </settings.1> <settings.2> <site> <id>767</id> <met.start>2001/01/01</met.start> <met.end>2014/12/31</met.end> <name>Morgan Monroe State Forest (US-MMS)</name> <lat>39.3231</lat> <lon>-86.4131</lon> </site> <start.date>2001/01/01</start.date> <end.date>2014/12/31</end.date> <inputs> <met> <path>/fs/data1/pecan.data/dbfiles/AmerifluxLBL_SIPNET_site_0-767/AMF_US-MMS_BASE_HR_8-1.2001-01-01.2014-12-31.clim</path> </met> </inputs> </settings.2> .... </run> The ... replaces the rest of the site settings for however many sites are within the site group. Looking at the example above, take a close look at the <met.start></met.start> and <met.end></met.end>. You will notice that for both sites, the dates are different. In this example they were edited by hand to include the dates that are available for that site and source. You must know your source prior. Only the source CRUNCEP has a check that will tell you if your dates are outside the range available. PEcAn will automatically populate these dates across sites according the original setting of start and end dates. In addition, you will notice that the <path></path> section contains the model specific meteorological data file. You can add that in by hand or you can you can leave the normal tags that met process workflow will use to process the data into your model specific format: <met> <source>AmerifluxLBL</source> <output>SIPNET</output> <username>pecan</username> </met> 12.2.5 (experimental) State Data Assimilation The following tags can be used for state data assimilation. More detailed information can be found here: State Data Assimilation Documentation <state.data.assimilation> <process.variance>TRUE</process.variance> <aqq.Init>1</aqq.Init> <bqq.Init>1</bqq.Init> <sample.parameters>FALSE</sample.parameters> <adjustment>TRUE</adjustment> <censored.data>FALSE</censored.data> <FullYearNC>TRUE</FullYearNC> <NC.Overwrite>FALSE</NC.Overwrite> <NC.Prefix>sipnet.out</NC.Prefix> <q.type>SINGLE</q.type> <free.run>FALSE</free.run> <Localization.FUN>Local.support</Localization.FUN> <scalef>1</scalef> <chains>5</chains> <state.variables> <variable> <variable.name>AbvGrndWood</variable.name> <unit>MgC/ha</unit> <min_value>0</min_value> <max_value>9999</max_value> </variable> <variable> <variable.name>LAI</variable.name> <unit></unit> <min_value>0</min_value> <max_value>9999</max_value> </variable> <variable> <variable.name>SoilMoistFrac</variable.name> <unit></unit> <min_value>0</min_value> <max_value>100</max_value> </variable> <variable> <variable.name>TotSoilCarb</variable.name> <unit>kg/m^2</unit> <min_value>0</min_value> <max_value>9999</max_value> </variable> </state.variables> <Obs_Prep> <Landtrendr_AGB> <AGB_input_dir>/projectnb/dietzelab/dongchen/Multi-site/download_500_sites/AGB</AGB_input_dir> <allow_download>TRUE</allow_download> <export_csv>TRUE</export_csv> <timestep> <unit>year</unit> <num>1</num> </timestep> </Landtrendr_AGB> <MODIS_LAI> <search_window>30</search_window> <export_csv>TRUE</export_csv> <run_parallel>TRUE</run_parallel> <timestep> <unit>year</unit> <num>1</num> </timestep> </MODIS_LAI> <SMAP_SMP> <search_window>30</search_window> <export_csv>TRUE</export_csv> <update_csv>FALSE</update_csv> <timestep> <unit>year</unit> <num>1</num> </timestep> </SMAP_SMP> <Soilgrids_SoilC> <timestep> <unit>year</unit> <num>1</num> </timestep> </Soilgrids_SoilC> <outdir>/projectnb/dietzelab/dongchen/All_NEON_SDA/test_OBS</outdir> <start.date>2012-07-15</start.date> <end.date>2021-07-15</end.date> </Obs_Prep> <spin.up> <start.date>2004/01/01</start.date> <end.date>2006/12/31</end.date> </spin.up> <forecast.time.step>1</forecast.time.step> <start.date>2004/01/01</start.date> <end.date>2006/12/31</end.date> </state.data.assimilation> process.variance : [optional] TRUE/FLASE flag for if process variance should be estimated (TRUE) or not (FALSE). If TRUE, a generalized ensemble filter will be used. If FALSE, an ensemble Kalman filter will be used. Default is FALSE. aqq.Init : [optional] The initial value of aqq used for estimate the Q distribution, the default value is 1 (note that, the aqq.init and bqq.init right now only work on the VECTOR q type, and we didn’t account for the variabilities of them across sites or variables, meaning we initialize the aqq and bqq given single value). bqq.Init : [optional] The initial value of bqq used for estimate the Q distribution, the default value is 1. sample.parameters : [optional] TRUE/FLASE flag for if parameters should be sampled for each ensemble member or not. This allows for more spread in the intial conditions of the forecast. adjustment : [optional] Bool variable decide if you want to adjust analysis results by the likelihood. censored.data : [optional] Bool variable decide if you want to do MCMC sampling for the forecast ensemble space, the default is FALSE. FullYearNC : [optional] Bool variable decide if you want to generate the full-year netcdf file when there is a overlap in time, the default is TRUE. NC.Overwrite : [optional] Bool variable decide if you want to overwrite the previous netcdf file when there is a overlap in time, the default is FALSE. NC.Prefix : [optional] The prefix for the generation of the full-year netcdf file, the default is sipnet.out. q.type : [optional] The type of process variance that will be estimated, the default is SINGLE. free.run : [optional] If it’s a free run without any observations, the default is FALSE. Localization.FUN : [optional] The localization function name for the localization operation, the default is Local.support. scalef : [optional] The scale parameter used for the localization operation, the smaller the value is, the sites are more isolated. chains : [optional] The number of chains needed to be estimated during the MCMC sampling process. NOTE: If TRUE, you must also assign a vector of trait names to pick.trait.params within the sda.enkf function. state.variable : [required] State variable that is to be assimilated (in PEcAn standard format, with pre-specified variable name, unit, and range). Four variables can be assimilated so far: including Aboveground biomass (AbvGrndWood), LAI, SoilMoistFrac, and Soil carbon (TotSoilCarb). Obs_Prep : [required] This section will be handled through the SDA_Obs_Assembler function, if you want to proceed with this function, this section is required. spin.up : [required] start.date and end.date for model spin up. NOTE: start.date and end.date are distinct from values set in the run tag because spin up can be done over a subset of the run. forecast.time.step : [optional] start.date and end.date for model spin up. start.date : [required?] start date of the state data assimilation (in YYYY/MM/DD format) end.date : [required?] end date of the state data assimilation (in YYYY/MM/DD format) NOTE: start.date and end.date are distinct from values set in the run tag because this analysis can be done over a subset of the run. 12.2.6 State Variables for State Data Assimilation The following tags can be used for documentation of state variables required for the SDA workflow. <state.data.assimilation> <state.variables> <variable> <variable.name>AbvGrndWood</variable.name> <unit>MgC/ha</unit> <min_value>0</min_value> <max_value>9999</max_value> </variable> <variable> <variable.name>LAI</variable.name> <unit></unit> <min_value>0</min_value> <max_value>9999</max_value> </variable> <variable> <variable.name>SoilMoistFrac</variable.name> <unit></unit> <min_value>0</min_value> <max_value>100</max_value> </variable> <variable> <variable.name>TotSoilCarb</variable.name> <unit>kg/m^2</unit> <min_value>0</min_value> <max_value>9999</max_value> </variable> </state.variables> </state.data.assimilation> variable : [required] Each of this section should include each state variables separately. variable.name : [required] The name of the state variable (same as what we call it in the model output file. for example, “SIPNET.out” file). unit : [required] The unit of the state variable (can be empty if it’s unitless). min_value : [required] The minimum range of the state variable. max_value : [required] The maximum range of the state variable. 12.2.7 Observation Preparation for State Data Assimilation The following tags can be used for observation preparation for the SDA workflow. <state.data.assimilation> <Obs_Prep> <Landtrendr_AGB> <AGB_indir>/projectnb/dietzelab/dongchen/Multi-site/download_500_sites/AGB</AGB_indir> <allow_download>TRUE</allow_download> <export_csv>TRUE</export_csv> <timestep> <unit>year</unit> <num>1</num> </timestep> </Landtrendr_AGB> <MODIS_LAI> <search_window>30</search_window> <export_csv>TRUE</export_csv> <run_parallel>TRUE</run_parallel> <timestep> <unit>year</unit> <num>1</num> </timestep> </MODIS_LAI> <SMAP_SMP> <search_window>30</search_window> <export_csv>TRUE</export_csv> <update_csv>FALSE</update_csv> <timestep> <unit>year</unit> <num>1</num> </timestep> </SMAP_SMP> <Soilgrids_SoilC> <timestep> <unit>year</unit> <num>1</num> </timestep> </Soilgrids_SoilC> <outdir>/projectnb/dietzelab/dongchen/All_NEON_SDA/test_OBS</outdir> <start.date>2012-07-15</start.date> <end.date>2021-07-15</end.date> </Obs_Prep> </state.data.assimilation> The Obs_Prep section is specifically designed for the SDA_OBS_Assembler function within the state.data.assimilation section, which helps construct the obs.mean and obs.cov objects more efficiently. Within the Obs_Prep section, the user needs to specify data streams that will be proceeded in the assembler function as DataSource_AbbreviationOfData (for example: Landtrendr_AGB for Landtrendr aboveground biomass observations, or Soilgrids_SoilC for soilgrids soil organic carbon concentration). There are four functions that can be used for preparing observations: MODIS_LAI_prep, Soilgrids_SoilC_prep, SMAP_SMP_prep, and Landtrendr_AGB_prep functions. Other than that, the output directory, and start and end date need to be set within the Obs_Prep section, note that if you choose to export csv file for any data, you will get the corresponding csv file just under the outdir, for the Rdata of obs.mean and obs.cov objects, they will be stored whthin the Rdata folder within the outdir, if the Rdata folder is not created, then the assembler will help to create this folder automatically. * outdir : [required] This tag is for every observation preparation function, which points to the directory where the csv file associated with each data stream should be generated, read, or updated. * start.date : [required] This tag defines the exact start point of time, which differs from the start.date in the state.data.assimilation section in a way that it is the time when first observation should be taken. * end.date : [required] This tag defines the exact end point of time, which differs from the end.date in the state.data.assimilation section in a way that it is the time when last observation should be taken. Within each data-specific section (for example, within Landtrendr_AGB section), there are few general settings need to be set like the export_csv and timestep arguments. * export_csv : [optional] This tag is for every observation preparation function, which decide if we want to export the csv file to the outdir. Normally the outdir should be given in order to set export_csv as TRUE. The default value is TRUE. * timestep : [optional] This tag defines the time unit and how many unit time per each time step. It supports year, month, week, and day as time unit. If you assign a general timestep just under the Obs_Prep section, all variable will be handled with the same timestep. If you assign each variable with each timestep, then the assembler function will create obs.mean and obs.cov with mixed temporal resolution. The default value is list(unit=“year”, num=1). There are also several settings that are data-specific, for example, the AGB_indir only applies to Landtrendr AGB data that points to the directory where the AGB files are stored. Beyond that, the allow_download is also AGB specific, which decide if you want to download the AGB files if some are missing. * AGB_indir : [required] This tag is only for Landtrendr_AGB_prep function, which points to the directory where the pre-downloaded AGB files existed. * allow_download : [optional] This tag is only for Landtrendr_AGB_prep function, which decide if we want to proceed to download the AGB files (that will take a while, and a lot of space) if some of them are detected to be empty. The default value is FALSE. For the MODIS LAI and SMAP soil moisture observations, the search_window specifies how many days you want to search for the data with desired dates. Beyond that, the update_csv is specifically used for the SMAP data, which decide if you want to reproduce formatted csv file based on the downloaded SMAP_gee.csv file. For the run_parallel in MODIS LAI settings, it specify if you want to proceed the function parallely. * search_window : [optional] This tag is used for LAI and SMAP observation preparation functions, which defines the search window within which the closest observation to the target date is selected. The default value is 30 days. * update_csv : [optional] This tag is used for SMAP preparation function only, which decide if we want to update the CSV file. Normally, we will only set it to be TRUE if we redownload the SMAP_GEE csv file from Google Earth Engine, the tutorial can be found in the SMAP_SMP_prep function itself. The default value is FALSE. * run_parallel : [optional] This tag defines if you want to proceed the MODIS LAI function parallely, the default value is FALSE. 12.2.8 (experimental) Brown Dog This section describes how to connect to Brown Dog. This facilitates processing and conversions of data. <browndog> <url>...</url> <username>...</username> <password>...</password> </browndog> url: (required) endpoint for Brown Dog to be used. username: (optional) username to be used with the endpoint for Brown Dog. password: (optional) password to be used with the endpoint for Brown Dog. This information is currently used by the following R functions: PEcAn.data.atmosphere::met.process – Generic function for processing meteorological input data. PEcAn.benchmark::load_data – Generic, versatile function for loading data in various formats. 12.2.9 (experimental) Benchmarking Coming soon… 12.2.10 Remote data module This section describes the tags required for configuring remote_process. <remotedata> <out_get_data>...</out_get_data> <source>...</source> <collection>...</collection> <scale>...</scale> <projection>...</projection> <qc>...</qc> <algorithm>...</algorithm> <credfile>...</credfile> <out_process_data>...</out_process_data> <overwrite>...</overwrite> </remotedata> out_get_data: (required) type of raw output requested, e.g, bands, smap source: (required) source of remote data, e.g., gee or AppEEARS collection: (required) dataset or product name as it is provided on the source, e.g. “COPERNICUS/S2_SR” for gee or “SPL3SMP_E.003” for AppEEARS scale: (optional) pixel resolution required for some gee collections, recommended to use 10 for Sentinel 2 projection: (optional) type of projection. Only required for AppEEARS polygon AOI type qc: (optional) quality control parameter, required for some gee collections overwrite: (optional) if TRUE database checks will be skipped and existing data of same type will be replaced entirely. When processed data is requested, the raw data required for creating it will also be replaced. By default FALSE These tags are only required if processed data is requested: out_process_data: (optional) type of processed output requested, e.g, LAI algorithm: (optional) algorithm used for processing data, currently only SNAP is implemented to estimate LAI from Sentinel-2 bands credfile: (optional) absolute path to JSON file containing Earthdata username and password, only required for AppEEARS pro_mimetype: (optional) MIME type of the processed file pro_formatname: (optional) format name of the processed file Additional information for the module are taken from the registration files located at data.remote/inst/registration The output data from the module are returned in the following tags: raw_id: input id of the raw file raw_path: absolute path to the raw file pro_id: input id of the processed file pro_path: absolute path to the processed file "],["workflow.html", "13 PEcAn workflow (web/workflow.R)", " 13 PEcAn workflow (web/workflow.R) How the workflow works How each module is called How to do outside of web interface Link to “folder structure” section below for detailed descriptions "],["workflow-readsettings.html", "13.1 Read Settings", " 13.1 Read Settings (TODO: Under construction…) "],["workflow-input.html", "13.2 Input Conversions", " 13.2 Input Conversions "],["workflow-input-data.html", "13.3 Input Data", " 13.3 Input Data Models require input data as drivers, parameters, and boundary conditions. In order to make a variety of data sources that have unique formats compatible with models, conversion scripts are written to convert them into a PEcAn standard format. That format is a netcdf file with variables names and specified to our standard variable table. Within the PEcAn repository, code pertaining to input conversion is in the MODULES directory under the data.atmosphere and data.land directories. "],["workflow-input-initial.html", "13.4 Initial Conditions", " 13.4 Initial Conditions 13.4.1 CONUS (NEON/FIA/BADM) Initial Conditions. To convert initial condition data into the PEcAn Standard and then into the model formats we follow three main steps: Downloading vegetation info -converting the vegetation info into .rd file format Creating ensemble members based on veg file -resamples veg file to create ensmeble members Converting ensemble members to model specific format Common Questions regarding IC Data: How do I know if my data product is supported by ic_process workflow? -The current data products supported by ic_process are: NEON, FIA, and BADM. That said you if your vegetation files are registered with BETY and abide by the BETY formats and column names you will be able to use ic_process to create ensemble members and convert the ensemble members to model specific format. See section 6.3.3 for more info. Can I use ic_process outside of the PEcAn workflow? -Short answer is yes, ic_process can be called as a function all by itself outside of do_conversions. What about soil initial conditions? -Please reference section 6.3.6 for more info. ic_process workflow: Required inputs for ic_process are: settings object with and sections (see pecan.xml section for more info), dir or location where you would to store the output files, input object that contains all info from settings\\(run\\)inputs$poolinitcond, and the overwrite setting the default is overwrite = FALSE. get_veg_module() This function will either download your vegetation info from: NEON_veg, FIA, BADM sources or query BETY for existing veg files previously downloaded. The input and dbfile ids of your veg file are then added to a list getveg.id. ens_veg_module() This function will create ensemble member ncdf files by resampling the veg file supplied in getveg.id. put_veg_module() This function will convert the ensemble member ncdf files into model specific format. Currently the supported models are ED2 and SIPNET. 13.4.2 North America (NA) Initial Conditions. To create initial condition files across North America, you will need to strictly follow the script located at ~/pecan/modules/assim.sequential/inst/anchor/IC_prep_anchorSites.Rmd. Within the script we will be following those main steps: 1. Loading settings.xml file and specify paths. 2. Downloading/extracting estimations of four major carbon/water pools (leaf, wood, soil C, soil water) into by-site and by-ensemble tables. 3. Doing unit conversion. For each ensemble of each site, we will be preparing the poolinfo object consisting of converted pool estimations. 4. We will finally be writing the NC files through the PEcAn.SIPNET::veg2model.SIPNET function. 5. Within the loop, we will store the NC file paths into the settings object and rewrite the settings into the XML file to the destination. Within the script we proposed the following new datasets for handling the NA initial condition preparations: The leaf carbon is initialized with MODIS LAI observations and the SLA for the corresponding PFT. The above ground biomass (AGB) is initialized with the 2010 global AGB map (DOI: https://doi.org/10.3334/ORNLDAAC/1763). The soil moisture (SM) is initialized with the SM estimations starting from 1978 (DOI: 10.24381/cds.d7782f18). The soil organic carbon (SOC) is initialized with ISCN SOC estimations (data already prepared on PEcAn, use PEcAn.data.land::iscn_soc to load) based on the level 2 ecoregion map (pre-downloaded using the following link: https://www.epa.gov/eco-research/ecoregions). "],["workflow-met.html", "13.5 Meteorological Data", " 13.5 Meteorological Data To convert meterological data into the PEcAn Standard and then into model formats we follow four main steps: Downloading raw data - Currently supported products - Example Code Converting raw data into a CF standard - Example Code Downscaling and gapfilling - Example Code Coverting to Model Specific format - Example Code Common Questions regarding Met Data: How do I add my Meterological data product to PEcAn? How do I use PEcAn to convert Met data outside the workflow? The main script that handles Met Processing, is met.process. It acts as a wrapper function that calls individual modules to facilitate the processing of meteorological data from it’s original form to a pecan standard, and then from that standard to model specific formats. It also handles recording these processes in the BETY database. Downloading raw data - Available Meteorological Drivers - Example Code to download Ameriflux data Converting raw data into a CF standard (if needed) - Example Code to convert from raw csv to CF standard Downscaling and gapfilling(if needed) - Example Code to gapfill Coverting to Model Specific format - Example Code to convert Standard into Sipnet format 13.5.1 Downloading Raw data (Description of Process) Given the information passed from the pecan.xml met.process will call the download.raw.met.module to facilitate the execution of the necessary functions to download raw data. <met> <source>AmerifluxLBL</source> <output>SIPNET</output> <username>pecan</username> </met> 13.5.2 Converting raw data to PEcAn standard 13.5.3 Downscaling and gapfilling (optional) 13.5.4 Converting from PEcAn standard to model-specific format "],["workflow-input-phenology.html", "13.6 Input phenological Data", " 13.6 Input phenological Data To enable the use of MODIS phenology data (MODIS Land Cover Dynamics (MCD12Q2)) to update the phenological parameters (leaf-on date) and (leaf-off date) at each restart timepoint: 1. Generate the phenological parameter CSV file by running PEcAn.data.remote::extract_phenology_MODIS. 2. Provide the generated phenological parameter CSV file to settings$run$inputs$leaf_phenology$path. "],["workflow-traits.html", "13.7 Traits", " 13.7 Traits (TODO: Under construction) "],["workflow-metaanalysis.html", "13.8 Meta Analysis", " 13.8 Meta Analysis (TODO: Under construction) "],["workflow-modelconfig.html", "13.9 Model Configuration", " 13.9 Model Configuration To enable the state data assimilation with sub-annual data, default conflict in model2netcdf should be TRUE. (TODO: Under construction) "],["workflow-modelrun.html", "13.10 Run Execution", " 13.10 Run Execution (TODO: Under construction) "],["workflow-postrun.html", "13.11 Post Run Analysis", " 13.11 Post Run Analysis (TODO: Under construction) ## Advanced Analysis {#workflow-advanced} (TODO: Under construction) "],["pecan-models.html", "14 PEcAn Models", " 14 PEcAn Models This section will contain information about all models and output variables that are supported by PEcAn. Model Name Available in the VM Prescribed Inputs Input Functions/Values Restart Function BioCro Yes Yes Yes No CLM No No No No DALEC Yes Yes Yes No ED2 Yes Yes Yes Yes FATES No Yes No GDAY No No No No LDNDC No Yes No No LINKAGES Yes Yes Yes Yes LPJ-GUESS No Yes No No MAESPA Yes Yes No No PRELES Yes Yes Partially No SiPNET Yes Yes Yes Yes STICS Yes Yes No No Available in the VM - Denotes if a model is publicly available with PEcAn. Prescribed Inputs - Denotes whether or not PEcAn can prescribe inputs. Input Functions/Values - Denotes whether or not PEcAn has functions to fully produce a model’s Input values. Restart Function - Denotes status of model data assimilation capabilities. Output Variables PEcAn converts all model outputs to a single Output Standards. This standard evolved out of MsTMIP project, which is itself based on NACP, LBA, and other model-intercomparison projects. This standard was expanded for the PalEON MIP and the needs of the PEcAn modeling community to support variables not in these standards. Model developers: do not add variables to your PEcAn output without first adding them to the PEcAn standard table! Also, do not create new variables equivalent to existing variables but just with different names or units. "],["models-biocro.html", "14.1 BioCro", " 14.1 BioCro Model Information Home Page https://github.com/ebimodeling/biocro/blob/0.951/README.md Source Code https://github.com/ebimodeling/biocro/tree/0.951 License University of Illinois/NCSA Open Source License Authors Fernando E. Miguez, Deepak Jaiswal, Justin McGrath, David LeBauer, Scott Rohde, Dan Wang PEcAn Integration David LeBauer, Chris Black, Kristina Riemer 14.1.1 Introduction BioCro is a model that estimates photosynthesis at the leaf, canopy, and ecosystem levels and determines plant biomass allocation and crop yields, using underlying physiological and ecological processes to do so. 14.1.2 PEcAn configuration file additions The following sections of the PEcAn XML are relevant to the BioCro model: model revision – Model version number run site/id – ID associated with desired site from BETYdb site entry inputs met/output – Set as BIOCRO met/path – Path to file containing meteorological data 14.1.3 Model specific input files List of inputs required by model, such as met, etc. 14.1.4 Model configuration files Genus-specific parameter files are secretly required. These are stored in the PEcAn.BIOCRO package and looked up under the hood. write.configs.BIOCRO looks for defaults in this order: first any file at a path specified by settings$pft$constants$file, next by matching the genus name in datasets exported by the BioCro package, and last by matching the genus name in PEcAn.BIOCRO’s extdata/defaults directory. When adding a new genus, it is necessary to provide a new default parameter file in PEcAn.BIOCRO inst/extdata/defaults and also (for v<1.0) update the call_biocro() function. BioCro uses a config.xml file similar to ED2. At this time, no other template files are required. 14.1.5 Installation notes BioCro can be run standalone using the model’s R package. Instructions for installing and using the package are in the GitHub repo’s README file. PEcAn works with v. 0.9x and 1.x. Support for v 2.x is not implemented. Support for v 0.9x is most robust and tested. To install, use remotes::install_github('ebimodeling/biocro@0.951') "],["models-clm.html", "14.2 CLM", " 14.2 CLM Model Information Home Page Source Code License Authors PEcAn Integration Introduction Introduction about model PEcAn configuration file additions Should list the model specific additions to the PEcAn file here Model specific input files List of inputs required by model, such as met, etc. Model configuration files MODEL is configured using 3 files which are placed in the run folder, as well as a symbolic link to the met file. file1 : template for this file is located at models/MODEL/inst/file1 and is not modified. file2 : template for this file is located at models/MODEL/inst/file2 and is not modified. file3 : template for this file is in models/MODEL/inst/file3 or it is specified in the <model> section as <template>. The values in this template are replaced by those computed in the earlier stages of PEcAN. Installation notes This section contains notes on how to compile the model. The notes for the VM might work on other machines or configurations as well. VM "],["models-dalec.html", "14.3 DALEC", " 14.3 DALEC Model Information Home Page Source Code License Authors PEcAn Integration Introduction Introduction about model PEcAn configuration file additions Should list the model specific additions to the PEcAn file here Model specific input files List of inputs required by model, such as met, etc. Model configuration files MODEL is configured using 3 files which are placed in the run folder, as well as a symbolic link to the met file. file1 : template for this file is located at models/MODEL/inst/file1 and is not modified. file2 : template for this file is located at models/MODEL/inst/file2 and is not modified. file3 : template for this file is in models/MODEL/inst/file3 or it is specified in the <model> section as <template>. The values in this template are replaced by those computed in the earlier stages of PEcAN. Installation notes This section contains notes on how to compile the model. The notes for the VM might work on other machines or configurations as well. VM "],["models-ed.html", "14.4 ED2", " 14.4 ED2 Model Information Home Page http://moorcroftlab.oeb.harvard.edu/ Source Code https://github.com/EDmodel/ED2 License Authors Paul Moorcroft, … PEcAn Integration Michael Dietze, Rob Kooper 14.4.1 Introduction Introduction about ED model 14.4.2 PEcAn configuration file additions The following sections of the PEcAn XML are relevant to the ED model: model id – BETY model ID. Each ID corresponds to a different revision of ED (see below) revision – The revision (a.k.a. release) number of ED (e.g. “r82”). “rgit” indicates the latest code on the ED repository. edin – Name of the template ED2IN configuration file. If this is a functional path that points to a specific file, that file is used. If no file is found following the path literally, the workflow will try the path relative to the PEcAn.ED2 package using system.file (recall that files in inst are moved in the package root, but all other directory structure is preserved). If this is omitted, PEcAn.ED2::write.configs.ED2 will look for a file called ED2IN.<revision> (e.g. ED2IN.rgit, ED2IN.r86) in the PEcAn.ED2 package. Example: <edin>ED2IN.rgit</edin> will use the ED2IN.rgit file shipped with PEcAn.ED2 regardless of the revision of ED used. (Note however that if a file called ED2IN.rgit exists in the workflow runtime directory, that file will be used instead). start.date, end.date – Run start and end date, respectively met.start, met.end – Start and end year of meteorology inputs. By default (if omitted), these are set to the years of start.date and end.date, respectively. Setting these values to a shorter interval than start.date and end.date will cause ED to loop the meteorology input over the specified years. This may be useful for, for example, spinning up ED under a set of constant climate conditions. phenol.scheme phenol phenol.start phenol.end all_pfts – (Logical) If false or missing (default), only run ED2 with the PFTs configured via PEcAn (i.e. in the <pfts> section of the XML). If true, run with all 17 of ED2’s PFTs, using ED2’s internal default parameters for all PFTs not configured through PEcAn. See below for more details. ed2in_tags – Named list of additional tags in the ED2IN to be modified. These modifications override any of those set by other parts of the PEcAn workflow. These tags must be in all caps. Any tags that are not already in the ED2IN file will be added; this makes this an effective way to run newer versions of ED2 that have new ED2IN parameters without having to provide an entire new ED2IN. For example: <model> <ed2in_tags> <IOOUTPUT>0</IOOUTPUT> <PLANT_HYDRO_SCHEME>0</PLANT_HYDRO_SCHEME> <ISTOMATA_SCHEME>0</ISTOMATA_SCHEME> <ISTRUCT_GROWTH_SCHEME>0</ISTRUCT_GROWTH_SCHEME> <TRAIT_PLASTICITY_SCHEME>0</TRAIT_PLASTICITY_SCHEME> </ed2in_tags> </model> barebones_ed2in – Whether or not to try to annotate the ED2IN file with comments. If “true”, skip all comments and only write the tags themselves. If “false” (default), try to transfer comments from the template file into the target file. jobtemplate prerun – String of commands to be added to the job.sh model execution script before the model is run. Multiple commands should be separated by proper bash syntax – i.e. either with && or ;. One common use of this argument is to load modules on some HPC systems – for instance: <prerun>module load git hdf5</prerun> If your particular version of ED is failing early during execution with a mysterious “Segmentation fault”, that may indicate that its process is exceeding its stack limit. In this case, you may need to remove the stack limit restriction with a prerun command like the following: <prerun>ulimit -s unlimited</prerun> postrun – Same as <prerun>, but for commands to be run after model execution. binary – The full path to the ED2 binary on the target machine. binary_args – Additional arguments to be passed to the ED2 binary. Some common arguments are: -s – Delay OpenMPI initialization until the last possible moment. This is needed when running ED2 in a Docker container. It is included by default when the host is rabbitmq. -f /path/to/ED2IN – Full path to a specific ED2IN namelist file. Typically, this is not needed because, by default, ED searches for the ED2IN in the current directory and the PEcAn workflow places the ED2IN file and a symbolic link to the ED executable in the same (run) directory for you. run/site lat – Latitude coordinate of site lon – Longitude coordinate of site inputs met/path – Path to ED_MET_DRIVER_HEADER file pss: [required] location of patch file css: [required] location of cohort file site: [optional] location of site file lu: [required] location of land use file thsums: [required] location of thermal sums file veg: [required] location of vegetation data soil: [required] location of soil data 14.4.3 PFT configuration in ED2 ED2 has more detailed PFTs than many models, and a more complex system for configuring these PFTs. ED2 has 17 PFTs, based roughly on growth form (e.g. tree vs. grass), biome (tropical vs. temperate), leaf morphology (broad vs. needleleaf), leaf phenology (evergreen vs. deciduous), and successional status (e.g. early, mid, or late). Each PFT is assigned an integer (1-17), which is used by the ED model to assign default model parameters. The mappings of these integers onto PFT definitions are not absolute, and may change as the ED2 source code evolves. Unfortunately, the only authoritative source for these PFT definitions for any given ED2 version is the Fortran source code of that version. The following is the mapping as of ED2 commit 24e6df6a (October 2018): C4 grass Early-successional tropical Mid-successional tropical Late-successional tropical Temperate C3 grass Northern pine Southern pine Late-successional conifer Early-successional temperate deciduous Mid-successional temperate deciduous Late-successional temperate deciduous Agricultural (crop) 1 Agricultural (crop) 2 Agricultural (crop) 3 Agricultural (crop) 4 Subtropical C3 grass (C4 grass with C3 photosynthesis) “Araucaria” (non-optimized southern pine), or liana ED2 parameter defaults are hard-coded in its Fortran source code. However, most parameters can be modified via an XML file (determined by the ED2IN IEDCNFGF field; usually config.xml in the same directory as the ED2IN file). The complete record of all parameters (defaults and user overrides) used by a given ED2 run is stored in a history.xml file (usually in the same directory as the ED2IN) – this is the file to check to make sure that an ED2 run is parameterized as you expect. As with other models, PEcAn can set ED2 parameters using its built-in trait meta analysis. The function specifically responsible for writing the config.xml is PEcAn.ED2::write.config.xml.ED2 (which is called as part of the more general PEcAn.ED2::write.config.ED2). The configuration process proceeds as follows: First, the mappings between PEcAn PFT names and ED2 PFT numbers are determined according to the following logic: If the PFT has a <ed2_pft_number> XML tag, that number is used. For example: <pft> <name>umbs.early_hardwood</name> <ed2_pft_number>9</ed2_pft_number> </pft> If <ed2_pft_number> is not provided, the code tries to cross-reference the PFT name against the pftmapping.csv data provided with the PEcAn.ED2 package. If the name is not matched (perfectly!), the function will exit with an error. Second, the PFT number from the previous step is used to write that PFT’s parameters to the config.xml. The order of precedence for parameters is as follows (from highest to lowest): Explicit user overrides. These are specified via a <constants> tag in the PFT definition in the pecan.xml. For example: <pft> <name>umbs.early_hardwood</name> <constants> <sla>36.3</sla> </constants> </pft> Note that these values are passed through PEcAn.ED2::convert.samples.ED, so they should generally be given in PEcAn’s default units rather than ED2’s. Samples from the PEcAn meta analysis. These are also converted via PEcAn.ED2::convert.samples.ED. ED2 defaults that PEcAn knows about. These are stored in the edhistory.csv file inside of PEcAn.ED2 This file is re-generated manually whenever there is a new version of ED2, so while we try our best to keep it up to date, there is no guarantee that it is. (Implicitly) Defaults in the ED2 Fortran source code. In general, our goal is to set all parameters through PEcAn (via steps 1-3), but if you are running PEcAn with new or experimental versions of ED2, you should be extra careful to make sure ED2 is running with the parameters you intend. Again, the best way to know which parameters ED2 is actually using is to check the history.xml file produced once the run starts. The ED2IN field INCLUDE_THESE_PFT controls which of these PFTs are included in a given ED2 run. By default, PEcAn will set this field to only include the PFTs specified by the user. This is the recommended behavior because it ensures that all PFTs in ED2 were parameterized (one way or another, at least partially) through PEcAn. However, if you would like ED2 to run with all 17 PFTs (NOTE: using ED2’s internal defaults for all PFTs not specified by the user!), you can set the <all_pfts> XML tag (in the <model> section) to true: <model> <all_pfts>true</all_pfts> </model> 14.4.4 Model specific input files List of inputs required by model, such as met, etc. 14.4.5 Model configuration files ED2 is configured using 2 files which are placed in the run folder. ED2IN : template for this file is located at models/ed/inst/ED2IN.<revision>. The values in this template that need to be modified are described below and are surrounded with @ symbols. config.xml : this file is generated by PEcAn. Some values are stored in the pecan.xml in <pfts><pft><constants> section as well as in <model> section. An example of the template can be found in ED2IN.r82 The ED2IN template can contain the following variables. These will be replaced with actual values when the model configuration is written. **@ENSNAME@** : run id of the simulation, used in template for NL%EXPNME **@START_MONTH@** : start of simulation UTC time, from <run><start.date>, used in template for NL%IMONTHA **@START_DAY@** : start of simulation UTC time, from <run><start.date>, used in template for NL%IDATEA **@START_YEAR@** : start of simulation UTC time, from <run><start.date>, used in template for NL%IYEARA **@END_MONTH@** : end of simulation UTC time, from <run><end.date>, used in template for NL%IMONTHZ **@END_DAY@** : end of simulation UTC time, from <run><end.date>, used in template for NL%IDATEZ **@END_YEAR@** : end of simulation UTC time, from <run><end.date>, used in template for NL%IYEARZ **@SITE_LAT@** : site latitude location, from <run><site><lat>, used in template for NL%POI_LAT **@SITE_LON@** : site longitude location, from <run><site><lon>, used in template for NL%POI_LON **@SITE_MET@** : met header location, from <run><site><met>, used in template for NL%ED_MET_DRIVER_DB **@MET_START@** : first year of met data, from <run><site><met.start>, used in template for NL%METCYC1 **@MET_END@** : last year of met data, from <run><site><met.end>, used in template for NL%METCYCF **@PHENOL_SCHEME@** : phenology scheme, if this variabe is 1 the following 3 fields will be used, otherwise they will be set to empty strings, from <model><phenol.scheme>, used in template for NL%IPHEN_SCHEME **@PHENOL_START@** : first year for phenology, from <model><phenol.start>, used in template for NL%IPHENYS1 and NL%IPHENYF1 @PHENOL_END@** : last year for phenology, from <model><phenol.end>, used in template for NL%IPHENYSF and NL%IPHENYFF @PHENOL@** : path and prefix of the prescribed phenology data, from * <model><phenol>, used in template for NL%PHENPATH **@SITE_PSSCSS@** : path and prefix of the previous ecosystem state, from <model><psscss>, used in template for NL%SFILIN **@ED_VEG@** : path and prefix of the vegetation database, used only to determine the land/water mask, from <model><veg>, used in template for NL%VEG_DATABASE **@ED_SOIL@** : path and prefix of the soil database, used to determine the soil type, from <model><soil>, used in template for NL%SOIL_DATABASE **@ED_INPUTS@** : input directory with dataset to initialise chilling degrees and growing degree days, which is used to drive the cold-deciduous phenology, from <model><inputs>, used in template for NL%THSUMS_DATABASE **@FFILOUT@** : path and prefix for analysis files, generated from <run><host><outdir>/run.id/analysis, used in template for NL%FFILOUT **@SFILOUT@** : path and prefix for history files, generated from <run><host><outdir>/run.id/history, used in template for NL%SFILOUT **@CONFIGFILE@** : XML file containing additional parameter settings, this is always “config.xml”, used in template for NL%IEDCNFGF @OUTDIR@** : location where output files are written (without the runid**), from <run><host><outdir>, should not be used. **@SCRATCH@** : local scratch space for outputs, generated /scratch/<username>/run$scratch, should not be used right now since it only works on ebi-cluster 14.4.6 Installation notes This section contains notes on how to compile the model. The notes for the VM might work on other machines or configurations as well. 14.4.6.1 VM 14.4.6.2 BU geo 14.4.6.3 TACC lonestar module load hdf5 curl -o ED.r82.tgz http://isda.ncsa.illinois.edu/~kooper/EBI/ED.r82.tgz tar zxf ED.r82.tgz rm ED.r82.tgz cd ED.r82/ED/build/bin curl -o include.mk.lonestar http://isda.ncsa.illinois.edu/~kooper/EBI/include.mk.lonestar make OPT=lonestar 14.4.6.4 TACC stampede module load hdf5 curl -o ED.r82.tgz http://isda.ncsa.illinois.edu/~kooper/EBI/ED.r82.tgz tar zxf ED.r82.tgz rm ED.r82.tgz cd ED.r82/ED/build/bin curl -o include.mk.stampede http://isda.ncsa.illinois.edu/~kooper/EBI/include.mk.stampede make OPT=stampede "],["models-gday.html", "14.5 GDAY", " 14.5 GDAY Model Information Home Page Source Code License Authors PEcAn Integration Introduction Introduction about model PEcAn configuration file additions Should list the model specific additions to the PEcAn file here Model specific input files List of inputs required by model, such as met, etc. Model configuration files MODEL is configured using 3 files which are placed in the run folder, as well as a symbolic link to the met file. file1 : template for this file is located at models/MODEL/inst/file1 and is not modified. file2 : template for this file is located at models/MODEL/inst/file2 and is not modified. file3 : template for this file is in models/MODEL/inst/file3 or it is specified in the <model> section as <template>. The values in this template are replaced by those computed in the earlier stages of PEcAN. Installation notes This section contains notes on how to compile the model. The notes for the VM might work on other machines or configurations as well. VM "],["models-ldndc.html", "14.6 LDNDC", " 14.6 LDNDC Model Information Home Page https://ldndc.imk-ifu.kit.edu/about/model.php Source Code License Authors Prof. Dr. Klaus Butterbach-Bahl, Dr. Edwin Haas, … PEcAn Integration Henri Kajasilta 14.6.1 Introduction LandscapeDNDC is designed to simulate biosphere/hydrosphere processes of forest, arable and grassland ecosystems. The design of LDNDC allows different models/modules to be plugged in, allowing the simulations for different ecosystems. The most up-to-date information on LDNDC can be found here, as well as the authors, users guide and documentation of the model: https://ldndc.imk-ifu.kit.edu/index.php Please note! The PEcAn setups here are written for the LDNDC version that has been downloaded on 2022-10-19. Some of the newer versions of LDNDC may have differences in the names of variables and parameters. PEcAn configuration file additions The following sections of the PEcAn XML are relevant or have influence at this development stage: ensemble variable: LAI, GPP, NPP, NEE, Respirations (AutoResp, HeteroResp, TotalResp), biomass of harvesting (harvest_carbon_flux), AGB and BGB (below_ground_carbon_content). model id: Corresponding the id of LDNDC in BETY. run inputs start_date: Start date of the simulation end_date: End date of the simulation Paths to meteorological drivers, events and initial conditions. Paths to airchemistry and groundwater files, may also be included, but are not required. 14.6.2 Model specific input files LDNDC takes multiple input files, and can also generate multiple output files. These notes on input files are written from the PEcAn integration point of view, and detailed information on input files can be found in the user guide, which is available via the links above. Input files: Project — Contains essential information in order to set up the simulation run. For example, the file contains paths to other files that will be used in the simulations, as well as the time period in which the simulations will take place. Setup — Defines which modules are used. Climate — Met data that is used in simulations. Speciesparameters — Species used in the simulations should be defined here and the file contains the parametrization for the species. Siteparameters — Works similarly to speciesparameters, but from the point of view of site parametrization. Event — Holds information about the events, which are essential in arable simulations. Site — Specific information about the site (e.g. carbon and nitrogen contents, hydrological characteristics). Airchemistry — Information about the air chemistry. 14.6.2.1 Model configuration files Due to the number of different input files, there are several templates that are used in the model configuration. The templates are located in models/ldndc/inst/. These templates wll be populated with parametrizations and initial conditions when configurations are written. The drivers and events on the other hand should be informed by giving a path to the driver/event file in pecan.xml. Many configurations for the model are (less surprisingly) written in write.configs.LDNDC. This is the file that may need to be modified in order to make the model to run appropriately in terms of the simulated species. Currently, there are a few crop species that the workflow recognizes (triticale, barley and oat), a couple of grass species (timothy and meadow) and one forest species (pipy). However, if other species options are needed, it is relatively easy to modify the code in configurations and add them so that the workflow can handle them. Also, the path for running the model binary is created in write.configs.LDNDC and will likely need some changes depending on the location of the model binaries/configurations on the user’s server. project.ldndc : The project file is populated in write.configs.LDNDC based on the input from the PEcAn settings. In addition to containing the correct names for the input files used in the simulation, the project file contains the start and end points for the simulation period. The file also specifies the path where the output files will be written. The other input files should be in the same directory as the project file when the model run is started. The output directory is created amongst the other outputs of the simulation. Simulations are run half-hourly by default and this is hard coded in the write.configs.LDNDC file. template.job : Will be filled in with the information needed to run the model in PEcAn. For example, calls the model binary and executes the project.ldndc file. speciesparameter_template.xml : Has a replaceable section. This section is filled in within write.configs.LDNDC. This file uses the given prior values for the species. Currently, there are a few species hard coded in write.configs.LDNDC. See the comment above. siteparameters.xml : This file is populated by given site(parameter) prior values. site.xml : This file is written based on the given initial condition file (netcdf). If no path is given in poolinitcond, then some default mineral clay soil settings will be written to this file. However, it is strongly recommended that some initial conditions based on the simulated site are provided. Variables that can be found from the initial conditions, but are not required: For each layer pH (-), volume_fraction_of_water_in_soil_at_field_capacity (m3 m-3), volume_fraction_of_condensed_water_in_soil_at_wilting_point (m3 m-3), soil_nitrogen_content (kg kg-1), soil_carbon_content (kg kg-1), mass_fraction_of_clay_in_soil (kg kg-1), mass_fraction_of_sand_in_soil (kg kg-1), mass_fraction_of_silt_in_soil (kg kg-1), soil_density (kg m-3), soil_hydraulic_conductivity_at_saturation (m s-1), stratum = (-) [number of how many stratums a soil layer has] Single value c2n_humus (ratio), [is written in siteparameter file] AGB = (kg m-2), [is written in events file] fractional_cover (%) [is written in events file] Model specific history (soil use history, e.g. arable) soil_type (e.g. ORMA, SALO) setup.xml : Contains information about which modules the model simulation is using. Default settings should be suitable for most of the purposes and are currently hard-coded. The setups differ for agricultural and forest sites. 14.6.3 Installation notes In order to obtain the LDNDC model, the credentials are required. The user can request them from the developers of the model. With the credentials, the pre-compiled LDNDC program can be downloaded here: https://ldndc.imk-ifu.kit.edu/download/download-model.php Once the necessary files have been obtained, the user should execute the installation script found in the ldndc-‘version-number’ directory. On linux, executing would happen with the command sh install.sh. A successful installation will create a .ldndc directory in the user’s home directory. (Note, that this .ldndc directory path will be used in write.configs.LDNDC.) Running the simulations is done by calling the ldndc executable (found in the /bin directory) and giving the path to the project file containing the specs of the simulation. Detailed instructions and how to play with these setups can be found in the user guide. "],["models-linkages.html", "14.7 LINKAGES", " 14.7 LINKAGES Model Information Home Page Source Code License Authors PEcAn Integration Introduction Introduction about model PEcAn configuration file additions Should list the model specific additions to the PEcAn file here Model specific input files List of inputs required by model, such as met, etc. Model configuration files MODEL is configured using 3 files which are placed in the run folder, as well as a symbolic link to the met file. file1 : template for this file is located at models/MODEL/inst/file1 and is not modified. file2 : template for this file is located at models/MODEL/inst/file2 and is not modified. file3 : template for this file is in models/MODEL/inst/file3 or it is specified in the <model> section as <template>. The values in this template are replaced by those computed in the earlier stages of PEcAN. Installation notes This section contains notes on how to compile the model. The notes for the VM might work on other machines or configurations as well. VM "],["models-lpjguess.html", "14.8 LPJ-GUESS", " 14.8 LPJ-GUESS Model Information Home Page Source Code License Authors PEcAn Integration Introduction Introduction about model PEcAn configuration file additions Should list the model specific additions to the PEcAn file here Model specific input files List of inputs required by model, such as met, etc. Model configuration files MODEL is configured using 3 files which are placed in the run folder, as well as a symbolic link to the met file. file1 : template for this file is located at models/MODEL/inst/file1 and is not modified. file2 : template for this file is located at models/MODEL/inst/file2 and is not modified. file3 : template for this file is in models/MODEL/inst/file3 or it is specified in the <model> section as <template>. The values in this template are replaced by those computed in the earlier stages of PEcAN. Installation notes This section contains notes on how to compile the model. The notes for the VM might work on other machines or configurations as well. VM "],["models-maespa.html", "14.9 MAESPA", " 14.9 MAESPA Model Information Home Page http://maespa.github.io/ Source Code http://maespa.github.io/download.html License Authors Belinda Medlyn and Remko Duursma PEcAn Integration Tony Gardella, Martim DeKauwe, Remki Duursma Introduction PEcAn configuration file additions Model specific input files Model configuration files MODEL is configured using 3 files which are placed in the run folder, as well as a symbolic link to the met file. file1 : template for this file is located at models/MODEL/inst/file1 and is not modified. file2 : template for this file is located at models/MODEL/inst/file2 and is not modified. file3 : template for this file is in models/MODEL/inst/file3 or it is specified in the <model> section as <template>. The values in this template are replaced by those computed in the earlier stages of PEcAN. Installation notes Installing the MAESPA model requires cloning the MAESPA Bitbucket Repository, executing the makefile, and ensuring that the Maeswarp R package is correctly installed. To clone and compile the model, execute this code at the command line git clone https://bitbucket.org/remkoduursma/maespa.git cd maespa make clean make maespa.out is your executable. Example input files can be found in the inputfiles directory. Executing measpa.out from within one of the example directories will produce output. MAESPA developers have also developed a wrapper package called Maeswrap. The usual R package installation method install.packages may present issues with downloading an unpacking a dependency package called rgl. Here are a couple of solutions: Solution 1 From the Command Line sudo apt-get install r-cran-rgl then from within R install.packages("Maeswrap") Solution 2 From the Command line sudo apt-get install libglu1-mesa-dev then from within R install.packages("Maeswrap") This section contains notes on how to compile the model. The notes for the VM might work on other machines or configurations as well. VM "],["models-preles.html", "14.10 PRELES", " 14.10 PRELES Model Information Home Page Source Code License Authors PEcAn Integration Introduction Introduction about model PEcAn configuration file additions Should list the model specific additions to the PEcAn file here Model specific input files List of inputs required by model, such as met, etc. Model configuration files MODEL is configured using 3 files which are placed in the run folder, as well as a symbolic link to the met file. file1 : template for this file is located at models/MODEL/inst/file1 and is not modified. file2 : template for this file is located at models/MODEL/inst/file2 and is not modified. file3 : template for this file is in models/MODEL/inst/file3 or it is specified in the <model> section as <template>. The values in this template are replaced by those computed in the earlier stages of PEcAN. Installation notes This section contains notes on how to compile the model. The notes for the VM might work on other machines or configurations as well. VM "],["models-sipnet.html", "14.11 SiPNET", " 14.11 SiPNET Model Information Home Page Source Code License Authors PEcAn Integration Michael Dietze, Rob Kooper Introduction Introduction about model PEcAn configuration file additions Should list the model specific additions to the PEcAn file here Model specific input files List of inputs required by model, such as met, etc. Model configuration files SIPNET is configured using 3 files which are placed in the run folder, as well as a symbolic link to the met file. sipnet.in : template for this file is located at models/sipnet/inst/sipnet.in and is not modified. sipnet.param-spatial : template for this file is located at models/sipnet/inst/template.param-spatial and is not modified. sipnet.param : template for this file is in models/sipnet/inst/template.param or it is specified in the <model> section as <default.param>. The values in this template are replaced by those computed in the earlier stages of PEcAN. Installation notes This section contains notes on how to compile the model. The notes for the VM might work on other machines or configurations as well. SIPNET version unk: if [ ! -e ${HOME}/sipnet_unk ]; then cd curl -o sipnet_unk.tar.gz http://isda.ncsa.illinois.edu/~kooper/PEcAn/models/sipnet_unk.tar.gz tar zxf sipnet_unk.tar.gz rm sipnet_unk.tar.gz fi cd ${HOME}/sipnet_unk/ make clean make sudo cp sipnet /usr/local/bin/sipnet.runk make clean SIPNET version 136: if [ ! -e ${HOME}/sipnet_r136 ]; then cd curl -o sipnet_r136.tar.gz http://isda.ncsa.illinois.edu/~kooper/EBI/sipnet_r136.tar.gz tar zxf sipnet_r136.tar.gz rm sipnet_r136.tar.gz sed -i 's#$(LD) $(LIBLINKS) \\(.*\\)#$(LD) \\1 $(LIBLINKS)#' ${HOME}/sipnet_r136/Makefile fi cd ${HOME}/sipnet_r136/ make clean make sudo cp sipnet /usr/local/bin/sipnet.r136 make clean VM "],["models-stics.html", "14.12 STICS", " 14.12 STICS Model Information Home Page https://www6.paca.inrae.fr/stics/ Source Code License Authors PEcAn Integration Istem Fer Introduction STICS (Simulateur mulTIdisciplinaire pour les Cultures Standard) is a crop model that has been developed since 1996 at INRA (French National Institute for Agronomic Research) in collaboration with other research (CIRAD, Irstea, Ecole des Mines de Paris, ESA, LSCE) or professional (ARVALIS, Terres Inovia, CTIFL, ITV, ITB, Agrotransferts, etc.) and teaching institutes or organizations. PEcAn configuration file additions Should list the model specific additions to the PEcAn file here Model specific input files List of inputs required by model, such as met, etc. Model configuration files STICS is configured using different XML files located in two fixed directories: config, plant and user defined workspace(s) directorie(s). A java app called JavaStics allows users to generate these files. Installation notes The software (JavaStics interface and STICS model) is available for download after a registration procedure (see procedure at http://www6.paca.inra.fr/stics_eng/ Download). VM "],["met-drivers.html", "15 Available Meteorological Drivers ", " 15 Available Meteorological Drivers "],["ameriflux.html", "15.1 Ameriflux", " 15.1 Ameriflux Scale: site Resolution: 30 or 60 min Availability: varies by site http:\\/\\/ameriflux.lbl.gov\\/data\\/data-availability\\/ Notes: Old ORNL server, use is deprecated "],["amerifluxlbl.html", "15.2 AmerifluxLBL", " 15.2 AmerifluxLBL Scale: site Resolution: 30 or 60 min Availability: varies by site http:\\/\\/ameriflux.lbl.gov\\/data\\/data-availability\\/ Notes: new Lawrence Berkeley Lab server "],["fluxnet2015.html", "15.3 Fluxnet2015", " 15.3 Fluxnet2015 Scale: site Resolution: 30 or 60 min Availability: varies by site http://fluxnet.fluxdata.org/sites/site-list-and-pages Notes: Fluxnet 2015 synthesis product. Does not cover all FLUXNET sites "],["narr.html", "15.4 NARR", " 15.4 NARR Scale: North America Resolution: 3 hr, approx. 32km \\(Lambert conical projection\\) Availability: 1979-present "],["cruncep.html", "15.5 CRUNCEP", " 15.5 CRUNCEP Scale: global Resolution: 6hr, 0.5 degree Availability: 1901-2010 "],["cmip5.html", "15.6 CMIP5", " 15.6 CMIP5 Scale: varies by model Resolution: 3 hr Availability: 2006-2100 Currently only GFDL available. Different scenerios and ensemble members can be set via Advanced Edit. "],["nldas.html", "15.7 NLDAS", " 15.7 NLDAS Scale: Lower 48 + buffer, Resolution: 1 hour, .125 degree Availability: 1980-present "],["gldas.html", "15.8 GLDAS", " 15.8 GLDAS Scale: Global Resolution: 3hr, 1 degree Availability: 1948-2010 "],["paleon.html", "15.9 PalEON", " 15.9 PalEON Scale: -100 to -60 W Lon, 35 to 50 N Latitude \\(US northern hardwoods + buffer\\) Resolution: 6hr, 0.5 degree Availability: 850-2010 "],["fluxnetlathuile.html", "15.10 FluxnetLaThuile", " 15.10 FluxnetLaThuile Scale: site Resolution: 30 or 60 min Availability: varies by site http:\\/\\/www.fluxdata.org\\/DataInfo\\/Dataset%20Doc%20Lib\\/SynthDataSummary.aspx Notes: 2007 synthesis. Fluxnet2015 supercedes this for sites that have been updated "],["geostreams.html", "15.11 Geostreams", " 15.11 Geostreams Scale: site Resolution: varies Availability: varies by site Notes: This is a protocol, not a single archive. The PEcAn functions currently default to querying [https://terraref.ncsa.illinois.edu/clowder/api/geostreams], which requires login and contains data from only two sites (Urbana IL and Maricopa AZ). However the interface can be used with any server that supports the Geostreams API. "],["era5.html", "15.12 ERA5", " 15.12 ERA5 Scale: Global Resolution: 3 hrs and 31 km Availability: 1950-present Notes: It’s important to know that the raw ERA5 tiles needs to be downloaded and registered in the database first. Inside the inst folder in the data.atmosphere package there are R files for downloading and registering files in the BETY. However, it assumes that you have registered and setup your API requirements. Check out how to setup your API [here] (https://confluence.ecmwf.int/display/CKB/How+to+download+ERA5#HowtodownloadERA5-3-DownloadERA5datathroughtheCDSAPI). In the inst folder you can find two files (ERA5_db_register.R and ERA5_USA_download.R). If you setup your ecmwf account as it’s explained in the link above, ERA5_USA_download.R will help you to download all the tiles with all the variables required for pecan extract.nc.ERA5 function to generate pecan standard met files. Besides installing the required packages for this file, it should work from top to bottom with no problem. After downloading the tiles, there is simple script in ERA5_db_register.R which helps you register your tiles in the bety. met.process later on uses that entery to find the required tiles for extracting met data for your sites. There are important points about this file. 1- Make sure you don’t change the site id in the script (which is the same the ParentSite in ERA5 registeration xml file). 2- Make sure the start and end date in that script matches the downloaded tiles. Set your ERA5.files.path to where you downloaded the tiles and then the rest of the script should be working fine. "],["icos-drought-2018.html", "15.13 ICOS Drought 2018", " 15.13 ICOS Drought 2018 Scale: site Resolution: 30 min Availability: Varies by site Notes: To use this option, set source as ICOS and a product tag containing drought2018 in pecan.xml "],["icos-ecosystem-archive.html", "15.14 ICOS Ecosystem Archive", " 15.14 ICOS Ecosystem Archive Scale: site Resolution: 30 min Availability: Varies by site Notes: To use this option, set source as ICOS and a product tag containing etc in pecan.xml "],["download-gfdl.html", "15.15 Download GFDL", " 15.15 Download GFDL The Downlad.GFDL function assimilates 3 hour frequency CMIP5 outputs generated by multiple GFDL models. GFDL developed several distinct modeling streams on the timescale of CMIP5 and AR5. These models include CM3, ESM2M and ESM2G with a spatial resolution of 2 degrees latitude by 2.5 degrees longitude. Each model has future outputs for the AR5 Representative Concentration Pathways ranging from 2006-2100. "],["cm3.html", "15.16 CM3", " 15.16 CM3 GFDL’s CMIP5 experiments with CM3 included many of the integrations found in the long-term CMIP5 experimental design. The focus of this physical climate model is on the role of aerosols, aerosol-cloud interactions, and atmospheric chemistry in climate variability and climate change. "],["esm2m-esm2g.html", "15.17 ESM2M & ESM2G", " 15.17 ESM2M & ESM2G Two new models representing ocean physics with alternative numerical frameworks to explore the implications of some of the fundamental assumptions embedded in these models. Both ESM2M and ESM2G utilize a more advanced land model, LM3, than was available in ESM2.1 including a variety of enhancements (Milly et al., in prep). GFDL’s CMIP5 experiments with Earth System Models included many of the integrations found in the long-term CMIP5 experimental design. The ESMs, by design, close the carbon cycle and are used to study the impact of climate change on ecosystems, ecosystem changes on climate and human activities on ecosystems. For more information please navigate here CM# ESM2M ESM2G rcp26 r1i1p1 r1i1p1 rcp45 r1i1p1, r3i1p1,r5i1p1 r1i1p1 r1i1p1 rcp60 r1i1p1 r1i1p1 rcp85 r1i1p1 r1i1p1 r1i1p1 "],["pecan-project-api.html", "16 PEcAn Project API ", " 16 PEcAn Project API "],["introduction-4.html", "16.1 Introduction", " 16.1 Introduction Welcome to the PEcAn Project API Documentation. The Predictive Ecosystem Analyser (PEcAn) Project is an open source framework initiated to meet the demands for more accessible, transparent & repeatable modeling of ecosystems. PEcAn can be considered as an ecoinformatics toolbox combined with a set of workflows that wrap around ecosystem models that allow users to effectively perform data synthesis, propagation of uncertainty through a model & ecological predictions in an integrated fashion using a diverse repository of data & models. Our API allows users to remotely interact with the PEcAn servers and leverage the functionalities provided by the PEcAn Project. It has been designed to follow common RESTful API conventions. Most operations are performed using the HTTP methods: GET (retrieve) & POST (create). Please note that the PEcAn Project API is currently under active development and is possible that any information in this document is subject to change. "],["authentication.html", "16.2 Authentication", " 16.2 Authentication Authentication to the PEcAn API occurs via Basic HTTP Auth. The credentials for using the API are the same as those used to log into PEcAn & BetyDB. Here is how you use basic HTTP auth with curl: $ curl --user '<username>:<password>' <api-endpoint> Authentication also depends on the PEcAn server that the user interacts with. Some servers, at the time of deployment have the AUTH_REQ = FALSE, meaning that such servers do not require user autertication for the usage of the PEcAn APIs. Regardless of the type of server, the endpoints defind under General section can be accessed without any authentication. "],["restful-api-endpoints.html", "16.3 RESTful API Endpoints", " 16.3 RESTful API Endpoints This page contains the high-level overviews & the functionalities offered by the different RESTful endpoints of the PEcAn API. For the most up-to-date documentation, you can visit the PEcAn API Documentation. The currently implemented functionalities include: General: GET /api/ping: Ping the server to check if it is live GET /api/status: Obtain general information about PEcAn & the details of the database host Models: GET /api/models/: Search for model(s) using search pattern based on model name & revision GET /api/models/{model_id}: Fetch the details of specific model Sites: GET /api/sites/: Search for site(s) using search pattern based on site name GET /api/sites/{site_id}: Fetch the details of specific site PFTs: GET /api/pfts/: Search for PFT(s) using search pattern based on PFT name, PFT type & Model type GET /api/pfts/{pft_id}: Fetch the details of specific PFT Formats: GET /api/formats/: Search for format(s) using search pattern based on format name & mime type GET /api/formats/{format_id}: Fetch the details of specific Format Inputs: GET /api/inputs/: Search for inputs needed for a PEcAn workflow based on model_id, site_id, format_id & host_id. GET /api/inputs/{input_id} *: Download the desired input file (if the input_id corresponds to a folder, an optional filename argument must be provided) Workflows: GET /api/workflows/: Retrieve a list of PEcAn workflows POST /api/workflows/: Submit a new PEcAn workflow GET /api/workflows/{id}: Obtain the details of a particular PEcAn workflow by supplying its ID GET /api/workflows/{id}/status: Obtain the status of a particular PEcAn workflow GET /api/workflows/{id}/file/{filename}: Download the desired file from a PEcAn workflow Runs: GET /api/runs: Get the list of all the runs GET /api/runs/{run_id}: Fetch the details of a specified PEcAn run GET /api/runs/{run_id}/input/{filename}: Download the desired input file for a run GET /api/runs/{run_id}/output/{filename}: Download the desired output file for a run GET /api/runs/{run_id}/graph/{year}/{y_var}: Plot the graph of desired output variables for a run * indicates that the particular API is under development & may not be ready for use "],["examples.html", "16.4 Examples:", " 16.4 Examples: 16.4.1 Prerequisites to interact with the PEcAn API Server 16.4.1.1 R Packages httr jsonlite xml2 16.4.1.2 Python Packages requests json xml Following are some example snippets to call the PEcAn API endpoints: 16.4.2 GET /api/ping 16.4.2.1 R Snippet res <- httr::GET("http://pecan.localhost/api/ping") print(jsonlite::fromJSON(rawToChar(res$content))) ## $request ## [1] "ping" ## $response ## [1] "pong" 16.4.2.2 Python Snippet response = requests.get("http://pecan.localhost/api/ping") print(json.dumps(response.json(), indent=2)) ## { ## "request": "ping", ## "response": "pong" ## } 16.4.3 GET /api/status 16.4.3.1 R Snippet res <- httr::GET("http://pecan.localhost/api/status") print(jsonlite::fromJSON(rawToChar(res$content))) ## $pecan_details$version ## [1] "1.7.0" ## $pecan_details$branch ## [1] "develop" ## $pecan_details$gitsha1 ## [1] "unknown" ## $host_details$hostid ## [1] 99 ## $host_details$hostname ## [1] "" ## $host_details$start ## [1] 99000000000 ## $host_details$end ## [1] 99999999999 ## $host_details$sync_url ## [1] "" ## $host_details$sync_contact ## [1] "" 16.4.3.2 Python Snippet response = requests.get("http://pecan.localhost/api/status") print(json.dumps(response.json(), indent=2)) ## { ## "pecan_details": { ## "version": "1.7.0", ## "branch": "develop", ## "gitsha1": "unknown" ## }, ## "host_details": { ## "hostid": 99, ## "hostname": "", ## "start": 99000000000, ## "end": 99999999999, ## "sync_url": "", ## "sync_contact": "" ## } ## } 16.4.4 GET /api/models/ 16.4.4.1 R Snippet # Search model(s) with `model_name` containing "sip" & `revision` containing "ssr" res <- httr::GET( "http://pecan.localhost/api/models/?model_name=sip&revision=ssr&ignore_case=TRUE", httr::authenticate("carya", "illinois") ) print(jsonlite::fromJSON(rawToChar(res$content))) ## $models ## model_id model_name revision ## 1 1000000022 SIPNET ssr ## $count ## [1] 1 16.4.4.2 Python Snippet # Search model(s) with `model_name` containing "sip" & `revision` containing "ssr" response = requests.get( "http://pecan.localhost/api/models/?model_name=sip&revision=ssr&ignore_case=TRUE", auth=HTTPBasicAuth('carya', 'illinois') ) print(json.dumps(response.json(), indent=2)) ## { ## "models": [ ## { ## "model_id": "1000000022", ## "model_name": "SIPNET", ## "revision": "ssr" ## } ## ], ## "count": 1 ## } 16.4.5 GET /api/models/{model_id} 16.4.5.1 R Snippet # Fetch the details of PEcAn model with id = 1000000022 res <- httr::GET( "http://pecan.localhost/api/models/1000000022", httr::authenticate("carya", "illinois") ) print(jsonlite::fromJSON(rawToChar(res$content))) ## $modeltype_id ## [1] 3 ## $model_type ## [1] "SIPNET" ## $model_id ## [1] 1000000022 ## $model_name ## [1] "SIPNET" ## $revision ## [1] "ssr" ## $inputs ## input required ## 1 met TRUE ## 2 poolinitcond FALSE 16.4.5.2 Python Snippet # Fetch the details of PEcAn model with id = 1000000022 response = requests.get( "http://pecan.localhost/api/models/1000000022", auth=HTTPBasicAuth('carya', 'illinois') ) print(json.dumps(response.json(), indent=2)) ## { ## "model_id": "1000000022", ## "model_name": "SIPNET", ## "revision": "ssr", ## "modeltype_id": 3, ## "model_type": "SIPNET" ## "inputs": [ ## { ## "input": "met", ## "required": TRUE ## }, ## { ## "input": "poolinitcond", ## "required": FALSE ## } ## ] ## } 16.4.6 GET /api/sites/ 16.4.6.1 R Snippet # Search site(s) with `site_name` containing "willow" res <- httr::GET( "http://pecan.localhost/api/sites/?sitename=willow&ignore_case=TRUE", httr::authenticate("carya", "illinois") ) print(jsonlite::fromJSON(rawToChar(res$content))) ## $sites ## id sitename ## 1 676 Willow Creek (US-WCr) ## 2 1108 Willow Creek (WC)-Chequamegon National Forest ## 3 1202 Tully_willow ## 4 1223 Saare SRF willow plantation ## 5 1000005151 Willow Creek (US-WCr) ## $count ## [1] 5 16.4.6.2 Python Snippet # Search site(s) with `site_name` containing "willow" response = requests.get( "http://pecan.localhost/api/models/?sitename=willow&ignore_case=TRUE", auth=HTTPBasicAuth('carya', 'illinois') ) print(json.dumps(response.json(), indent=2)) ## { ## "sites": [ ## { ## "id": 676, ## "sitename": "Willow Creek (US-WCr)" ## }, ## { ## "id": 1108, ## "sitename": "Willow Creek (WC)-Chequamegon National Forest" ## }, ## { ## "id": 1202, ## "sitename": "Tully_willow" ## }, ## { ## "id": 1223, ## "sitename": "Saare SRF willow plantation" ## }, ## { ## "id": 1000005151, ## "sitename": "Willow Creek (US-WCr)" ## } ## ], ## "count": 5 ## } 16.4.7 GET /api/sites/{site_id} 16.4.7.1 R Snippet # Fetch the details of PEcAn site with id = 676 res <- httr::GET( "http://pecan.localhost/api/sites/676", httr::authenticate("carya", "illinois") ) print(jsonlite::fromJSON(rawToChar(res$content))) ## $id ## [1] 676 ## $city ## [1] "Park Falls Ranger District" ## $state ## [1] "Wisconsin" ## $country ## [1] "US" ## $mat ## [1] 4 ## $map ## [1] 815 ## $soil ## [1] "" ## $som ## [1] "NA" ## $notes ## [1] "MF" ## $soilnotes ## [1] "" ## $sitename ## [1] "Willow Creek (US-WCr)" ## $greenhouse [1] FALSE ## $sand_pct ## [1] 42.52 ## $clay_pct ## [1] 20.17 ## $time_zone ## [1] "America/Chicago" 16.4.7.2 Python Snippet # Fetch the details of PEcAn site with id = 676 response = requests.get( "http://pecan.localhost/api/sites/676", auth=HTTPBasicAuth('carya', 'illinois') ) print(json.dumps(response.json(), indent=2)) ## { ## "id": 676, ## "city": "Park Falls Ranger District", ## "state": "Wisconsin", ## "country": "US", ## "mat": 4, ## "map": 815, ## "soil": "", ## "notes": "MF", ## "soilnotes": "", ## "sitename": "Willow Creek (US-WCr)", ## "greenhouse": false, ## "sand_pct": 42.52, ## "clay_pct": 20.17, ## "time_zone": "America/Chicago" ## } 16.4.8 GET /api/pfts/ 16.4.8.1 R Snippet # Search pft(s) of "plant" type with `pft_name` containing "temperate" & belonging to `model_type` "SIPNET" res <- httr::GET( "http://pecan.localhost/api/pfts/?pft_name=temperate&pft_type=plant&model_type=sipnet&ignore_case=TRUE", httr::authenticate("carya", "illinois") ) print(jsonlite::fromJSON(rawToChar(res$content))) ## $pfts ## model_type pft_id pft_name pft_type ## <chr> <S3: integer64> <chr> <chr> ## 1 SIPNET 41 temperate.deciduous plant ## 2 SIPNET 1000000105 temperate.deciduous.IF plant ## 3 SIPNET 1000000107 temperate.deciduous_SDA plant ## 4 SIPNET 1000000115 temperate.deciduous.ALL plant ## 5 SIPNET 1000000118 temperate.deciduous.ALL.NORMAL plant ## 6 SIPNET 2000000017 tundra.deciduous.NGEE_Arctic plant ## 7 SIPNET 2000000045 temperate.broadleaf.deciduous plant ## $count ## [1] 7 16.4.8.2 Python Snippet # Search pft(s) of "plant" type with `pft_name` containing "temperate" & belonging to `model_type` "SIPNET" response = requests.get( "http://pecan.localhost/api/pfts/?pft_name=temperate&pft_type=plant&model_type=sipnet&ignore_case=TRUE", auth=HTTPBasicAuth('carya', 'illinois') ) print(json.dumps(response.json(), indent=2)) ## { ## "pfts": [ ## { ## "model_type": "SIPNET", ## "pft_id": 41, ## "pft_name": "temperate.deciduous", ## "pft_type": "plant" ## }, ## ... ## ], ## "count": 7 ## } 16.4.9 GET /api/pfts/{pft_id} 16.4.9.1 R Snippet # Fetch the details of PEcAn PFT with id = 2000000045 res <- httr::GET( "http://pecan.localhost/api/pfts/2000000045", httr::authenticate("carya", "illinois") ) print(jsonlite::fromJSON(rawToChar(res$content))) ## $model_type ## [1] "SIPNET" ## $pft_id ## [1] 2000000045 ## $pft_name ## [1] "temperate.broadleaf.deciduous" ## $definition ## [1] "SIPNET Temperate Deciduous PFT with priors on all parameters" ## $pft_type ## [1] "plant" 16.4.9.2 Python Snippet # Fetch the details of PEcAn PFT with id = 2000000045 response = requests.get( "http://pecan.localhost/api/pfts/2000000045", auth=HTTPBasicAuth('carya', 'illinois') ) print(json.dumps(response.json(), indent=2)) ## { ## "model_type": "SIPNET", ## "pft_id": 2000000045, ## "pft_name": "temperate.broadleaf.deciduous", ## "definition": "SIPNET Temperate Deciduous PFT with priors on all parameters", ## "pft_type": "plant" ## } 16.4.10 GET /api/formats/ 16.4.10.1 R Snippet # Search format(s) with name containing 'ameriflux' & mime type containing 'csv' res <- httr::GET( "http://pecan.localhost/api/formats/?format_name=ameriflux&mimetype=csv&ignore_case=TRUE", httr::authenticate("carya", "illinois") ) print(jsonlite::fromJSON(rawToChar(res$content))) ## $formats ## mimetype format_id format_name ## 1 text/csv 19 AmeriFlux.level4.h ## 2 text/csv 20 AmeriFlux.level4.d ## 3 text/csv 21 AmeriFlux.level4.w ## 4 text/csv 22 AmeriFlux.level4.m ## 5 text/csv 35 AmeriFlux.level2.h ## 6 text/csv 36 AmeriFlux.level3.h ## $count ## [1] 6 16.4.10.2 Python Snippet # # Search format(s) with name containing 'ameriflux' & mime type containing 'csv' response = requests.get( "http://pecan.localhost/api/formats/?format_name=ameriflux&mimetype=csv&ignore_case=TRUE", auth=HTTPBasicAuth('carya', 'illinois') ) print(json.dumps(response.json(), indent=2)) ## { ## "formats": [ ## { ## "mimetype": "text/csv", ## "format_id": 19, ## "format_name": "AmeriFlux.level4.h" ## }, ## { ## "mimetype": "text/csv", ## "format_id": 20, ## "format_name": "AmeriFlux.level4.d" ## }, ## ... ## ], ## "count": 6 ## } 16.4.11 GET /api/formats/{format_id} 16.4.11.1 R Snippet # Fetch the details of PEcAn format with id = 19 res <- httr::GET( "http://pecan.localhost/api/formats/19", httr::authenticate("carya", "illinois") ) print(jsonlite::fromJSON(rawToChar(res$content))) ## $mimetype ## [1] "text/csv" ## $format_id ## [1] 19 ## $name ## [1] "AmeriFlux.level4.h" ## $notes ## [1] "Half-hourly AmeriFlux level 4 gap filled, partitioned, and flagged flux tower data. Variables description: Level 4 data are obtained from the level 3 products, data are ustar filtered, gap-filled using different methods (ANN and MDS) and partitioned (i.e. NEE, GPP, and Re). Flags with information regarding quality of the original and gapfilled data are added. Missing values: -9999." ## $header ## [1] "" ## $format_variables ## description name unit ## 1 Latent heat flux LE_f W m-2 ## 2 Sensible heat flux H_f W m-2 ## 3 air temperature Ta_f degrees C ## 4 Vapor Pressure Deficit VPD_f Pa ## 5 Cumulative ecosystem respiration over a specified time step Reco umol C02 m-2 s-1 ## 6 Net ecosystem exchange NEE_st_fMDS umol C m-2 s-1 16.4.11.2 Python Snippet # Fetch the details of PEcAn format with id = 19 response = requests.get( "http://pecan.localhost/api/formats/19", auth=HTTPBasicAuth('carya', 'illinois') ) print(json.dumps(response.json(), indent=2)) ## { ## "mimetype": "text/csv", ## "format_id": 19, ## "name": "AmeriFlux.level4.h", ## "notes": "Half-hourly AmeriFlux level 4 gap filled, partitioned, and flagged flux tower data. Variables description: ## Level 4 data are obtained from the level 3 products, data are ustar filtered, gap-filled using different methods (ANN and ## MDS) and partitioned (i.e. NEE, GPP, and Re). Flags with information regarding quality of the original and gapfilled data ## are added. Missing values: -9999.", ## "header": "", ## "format_variables": [ ## { ## "description": "Latent heat flux", ## "name": "LE_f", ## "unit": "W m-2" ## }, ## ... ## ] ## } 16.4.12 GET /api/inputs/ 16.4.12.1 R Snippet # Get the inputs needed for a workflow with model_id = 1000000022 & site_id = 676 res <- httr::GET( "http://pecan.localhost/api/inputs/?model_id=1000000022&site_id=676", httr::authenticate("carya", "illinois") ) print(jsonlite::fromJSON(rawToChar(res$content))) ## $inputs ## sitename model_name revision tag hostname file_name format_name mimetype ## 1 Willow Creek (US-WCr) SIPNET ssr met ebi-forecast.igb.illinois.edu wcr.clim Sipnet.climna text/csv ## 2 Willow Creek (US-WCr) SIPNET ssr met docker wcr.clim Sipnet.climna text/csv ## file_path id input_name start_date end_date ## 1 /home/share/data/dbfiles/ 235 2000-01-01 06:00:00 2007-01-01 05:59:00 ## 2 /data/sites/willow 2000000001 1998-01-01 00:00:00 2006-12-31 00:00:00 ## $count ## [1] 2 # Get the inputs needed for a workflow with format_id = 5000000002 (AMERIFLUX_BASE_HH) & host_id = 99000000001 (docker) res <- httr::GET( "http://pecan.localhost/api/inputs/?format_id=5000000002&host_id=99000000001", httr::authenticate("carya", "illinois") ) print(jsonlite::fromJSON(rawToChar(res$content))) ## $inputs ## sitename mimetype format_name hostname file_name ## 1 Niwot Ridge Forest/LTER NWT1 (US-NR1) text/csv AMERIFLUX_BASE_HH docker AMF_US-NR1_BASE_HH_15-5 ## file_path id input_name start_date end_date ## 1 /data/dbfiles/AmerifluxLBL_site_0-772 1000011238 AmerifluxLBL_site_0-772 1998-01-01 2016-12-31 ## $count ## [1] 1 16.4.12.2 Python Snippet # Get the inputs needed for a workflow with model_id = 1000000022 & site_id = 676 response = requests.get( "http://pecan.localhost/api/inputs/?model_id=1000000022&site_id=676", auth=HTTPBasicAuth('carya', 'illinois') ) print(json.dumps(response.json(), indent=2)) ## { ## "inputs": [ ## { ## "sitename": "Willow Creek (US-WCr)", ## "model_name": "SIPNET", ## "revision": "ssr", ## "tag": "met", ## "hostname": "ebi-forecast.igb.illinois.edu", ## "file_name": "wcr.clim", ## "format_name": "Sipnet.climna", ## "mimetype": "text/csv", ## "file_path": "/home/share/data/dbfiles/", ## "id": 235, ## "input_name": "", ## "start_date": "2000-01-01 06:00:00", ## "end_date": "2007-01-01 05:59:00" ## }, ## ... ## ], ## "count": 2 ## } # Get the inputs needed for a workflow with format_id = 5000000002 (AMERIFLUX_BASE_HH) & host_id = 99000000001 (docker) response = requests.get( "http://pecan.localhost/api/inputs/?format_id=5000000002&host_id=99000000001", auth=HTTPBasicAuth('carya', 'illinois') ) print(json.dumps(response.json(), indent=2)) ## { ## "inputs": [ ## { ## "sitename": "Niwot Ridge Forest/LTER NWT1 (US-NR1)", ## "hostname": "docker", ## "file_name": "AMF_US-NR1_BASE_HH_15-5", ## "format_name": "AMERIFLUX_BASE_HH", ## "mimetype": "text/csv", ## "file_path": "/data/dbfiles/AmerifluxLBL_site_0-772", ## "id": 1000011238, ## "input_name": "AmerifluxLBL_site_0-772", ## "start_date": "1998-01-01", ## "end_date": "2016-12-31" ## } ## ], ## "count": 1, ## } 16.4.13 GET /api/inputs/{input_id} 16.4.13.1 R Snippet # Download the input file with id = 99000000003 res <- httr::GET( "http://pecan.localhost/api/inputs/99000000003", httr::authenticate("carya", "illinois") ) writeBin(res$content, "test.2002.nc") # Download the file 'fraction.plantation' from the input directory with id = 295 res <- httr::GET( "http://pecan.localhost/api/inputs/295?filename=fraction.plantation", httr::authenticate("carya", "illinois") ) writeBin(res$content, "test.fraction.plantation") 16.4.13.2 Python Snippet # Download the input file for with id = 99000000003 response = requests.get( "http://pecan.localhost/api/inputs/99000000003", auth=HTTPBasicAuth('carya', 'illinois') ) with open("test.2002.nc", "wb") as file: file.write(response.content) # Download the file 'fraction.plantation' from the input directory with id = 295 response = requests.get( "http://pecan.localhost/api/inputs/295?filename=fraction.plantation", auth=HTTPBasicAuth('carya', 'illinois') ) with open("test.2002.nc", "wb") as file: file.write(response.content) 16.4.14 GET /api/workflows/ 16.4.14.1 R Snippet # Get workflow(s) that use `model_id` = 1000000022 [SIPNET] & `site_id` = 676 [Willow Creek (US-WCr)] res <- httr::GET( "http://pecan.localhost/api/workflows/?model_id=1000000022&site_id=676", httr::authenticate("carya", "illinois") ) print(jsonlite::fromJSON(rawToChar(res$content))) ## $workflows ## id folder started_at site_id model_id hostname start_date end_date ## 1 1000009900 /fs/data2/output//PEcAn_1000009900 2018-11-09 08:56:37 676 1000000022 geo.bu.edu 2004-01-01 2004-12-31 ## 2 1000009172 /fs/data2/output//PEcAn_1000009172 2018-04-11 18:14:52 676 1000000022 test-pecan.bu.edu 2004-01-01 2004-12-31 ## ... ## $count ## [1] 5 16.4.14.2 Python Snippet # Get workflow(s) that use `model_id` = 1000000022 [SIPNET] & `site_id` = 676 [Willow Creek (US-WCr)] response = requests.get( "http://pecan.localhost/api/workflows/?model_id=1000000022&site_id=676", auth=HTTPBasicAuth('carya', 'illinois') ) print(json.dumps(response.json(), indent=2)) ## { ## "workflows": [ ## { ## "id": 1000009172, ## "folder": "/fs/data2/output//PEcAn_1000009900", ## "started_at": "2018-11-09 08:56:37", ## "site_id": 676, ## "model_id": 1000000022, ## "hostname": "geo.bu.edu", ## "start_date": "2004-01-01", ## "end_date": "2004-12-31" ## }, ## ... ## ], ## "count": 5 ## } 16.4.15 POST /api/workflows/ 16.4.15.1 R Snippet # Submit a workflow in XML format for execution xmlFile <- "pecan/tests/api.sipnet.xml" xml_string <- paste0(xml2::read_xml(xmlFile)) res <- httr::POST( "http://pecan.localhost/api/workflows/", httr::authenticate("carya", "illinois"), httr::content_type("application/xml"), body = xml_string ) print(jsonlite::fromJSON(rawToChar(res$content))) ## $workflow_id ## [1] 99000000001 ## $status ## [1] "Submitted successfully" 16.4.15.2 Python Snippet # Submit a workflow in XML format for execution xml_file = "pecan/tests/api.sipnet.xml" root = xml.etree.ElementTree.parse(xml_file).getroot() response = requests.post( "http://pecan.localhost/api/workflows/", auth=HTTPBasicAuth('carya', 'illinois'), headers = {'Content-Type': 'application/xml'}, data = xml.etree.ElementTree.tostring(root, encoding='unicode', method='xml') ) print(json.dumps(response.json(), indent=2)) ## { ## "workflow_id": "99000000001", ## "status": "Submitted successfully" ## } 16.4.16 GET /api/workflows/{id} 16.4.16.1 R Snippet # Get details of workflow with `id` = '1000009172' res <- httr::GET( "http://pecan.localhost/api/workflows/1000009172", httr::authenticate("carya", "illinois") ) print(jsonlite::fromJSON(rawToChar(res$content))) ## $id ## [1] "1000009172" ## $folder ## [1] "/fs/data2/output//PEcAn_1000009172" ## $hostname ## [1] "test-pecan.bu.edu" ## $user_id ## [1] "NA" ## $properties ## $properties$end ## [1] "2004/12/31" ## $properties$pft ## $properties$pft[[1]] ## [1] "soil.IF" ## $properties$pft[[2]] ## [1] "temperate.deciduous.IF" ## $properties$email ## [1] "" ## $properties$notes ## [1] "" ## $properties$start ## [1] "2004/01/01" ## $properties$siteid ## [1] "676" ## $properties$modelid ## [1] "1000000022" ## $properties$hostname ## [1] "test-pecan.bu.edu" ## $properties$sitename ## [1] "WillowCreek(US-WCr)" ## $properties$input_met ## [1] "AmerifluxLBL.SIPNET" ## $properties$pecan_edit ## [1] "on" ## $properties$sitegroupid ## [1] "1000000022" ## $properties$fluxusername ## [1] "pecan" ## $properties$input_poolinitcond ## [1] "-1" 16.4.16.2 Python Snippet # Get details of workflow with `id` = '1000009172' response = requests.get( "http://pecan.localhost/api/workflows/1000009172", auth=HTTPBasicAuth('carya', 'illinois') ) print(json.dumps(response.json(), indent=2)) ## { ## "id": "1000009172", ## "folder": "/fs/data2/output//PEcAn_1000009172", ## "hostname": "test-pecan.bu.edu", ## "user_id": "NA", ## "properties": { ## "end": "2004/12/31", ## "pft": [ ## "soil.IF", ## "temperate.deciduous.IF" ## ], ## "email": "", ## "notes": "", ## "start": "2004/01/01", ## "siteid": "676", ## "modelid": "1000000022", ## "hostname": "test-pecan.bu.edu", ## "sitename": "WillowCreek(US-WCr)", ## "input_met": "AmerifluxLBL.SIPNET", ## "pecan_edit": "on", ## "sitegroupid": "1000000022", ## "fluxusername": "pecan", ## "input_poolinitcond": "-1" ## } ## } 16.4.17 GET /api/workflows/{id}/status 16.4.17.1 R Snippet # Get list of run belonging to the workflow with `workflow_id` = '99000000001' res <- httr::GET( "http://pecan.localhost/api/workflows/99000000001/status", httr::authenticate("carya", "illinois") ) print(jsonlite::fromJSON(rawToChar(res$content))) ## $workflow_id ## [1] "99000000001" ## $status ## [1] "TRAIT 2020-07-22 07:02:33 2020-07-22 07:02:35 DONE " ## [2] "META 2020-07-22 07:02:35 2020-07-22 07:02:38 DONE " ## [3] "CONFIG 2020-07-22 07:02:38 2020-07-22 07:02:40 DONE " ## [4] "MODEL 2020-07-22 07:02:40 2020-07-22 07:04:07 DONE " ## [5] "OUTPUT 2020-07-22 07:04:07 2020-07-22 07:04:08 DONE " ## [6] "ENSEMBLE 2020-07-22 07:04:08 2020-07-22 07:04:09 DONE " ## [7] "SENSITIVITY 2020-07-22 07:04:09 2020-07-22 07:04:16 DONE " ## [8] "FINISHED 2020-07-22 07:04:16 2020-07-22 07:04:16 DONE " 16.4.17.2 Python Snippet # Get list of run belonging to the workflow with `workflow_id` = '99000000001' response = requests.get( "http://pecan.localhost/api/workflows/99000000001/status", auth=HTTPBasicAuth('carya', 'illinois') ) print(json.dumps(response.json(), indent=2)) ## { ## "workflow_id": "99000000001", ## "status": [ ## "TRAIT 2020-07-22 07:02:33 2020-07-22 07:02:35 DONE ", ## "META 2020-07-22 07:02:35 2020-07-22 07:02:38 DONE ", ## "CONFIG 2020-07-22 07:02:38 2020-07-22 07:02:40 DONE ", ## "MODEL 2020-07-22 07:02:40 2020-07-22 07:04:07 DONE ", ## "OUTPUT 2020-07-22 07:04:07 2020-07-22 07:04:08 DONE ", ## "ENSEMBLE 2020-07-22 07:04:08 2020-07-22 07:04:09 DONE ", ## "SENSITIVITY 2020-07-22 07:04:09 2020-07-22 07:04:16 DONE ", ## "FINISHED 2020-07-22 07:04:16 2020-07-22 07:04:16 DONE " ## ] ## } 16.4.18 GET /api/workflows/{id}/file/{filename} 16.4.18.1 R Snippet # Download the 'ensemble.ts.99000000017.NPP.2002.2002.Rdata' output file for the workflow with id = 99000000031 res <- httr::GET( "http://pecan.localhost/api/workflows/99000000031/file/ensemble.ts.99000000017.NPP.2002.2002.Rdata", httr::authenticate("carya", "illinois") ) writeBin(res$content, "test.ensemble.ts.99000000017.NPP.2002.2002.Rdata") 16.4.18.2 Python Snippet # Download the 'ensemble.ts.99000000017.NPP.2002.2002.Rdata' output file for the workflow with id = 99000000031 response = requests.get( "http://pecan.localhost/api/workflows/99000000031/file/ensemble.ts.99000000017.NPP.2002.2002.Rdata", auth=HTTPBasicAuth('carya', 'illinois') ) with open("test.ensemble.ts.99000000017.NPP.2002.2002.Rdata", "wb") as file: file.write(response.content) 16.4.19 GET /api/runs/ 16.4.19.1 R Snippet # Get list of run belonging to the workflow with `workflow_id` = '1000009172' res <- httr::GET( "http://pecan.localhost/api/runs/?workflow_id=1000009172", httr::authenticate("carya", "illinois") ) print(jsonlite::fromJSON(rawToChar(res$content))) ## $runs ## runtype ensemble_id workflow_id id model_id site_id parameter_list start_time ## finish_time ## 1 ensemble 1000017624 1000009172 1002042201 1000000022 796 ensemble=1 2005-01-01 ## 00:00:00 2011-12-31 00:00:00 ## ... ## $count ## [1] 50 16.4.19.2 Python Snippet # Get list of run belonging to the workflow with `workflow_id` = '1000009172' response = requests.get( "http://pecan.localhost/api/runs/?workflow_id=1000009172", auth=HTTPBasicAuth('carya', 'illinois') ) print(json.dumps(response.json(), indent=2)) ## { ## "runs": [ ## { ## "runtype": "ensemble", ## "ensemble_id": 1000017624, ## "workflow_id": 1000009172, ## "id": 1002042201, ## "model_id": 1000000022, ## "site_id": 796, ## "parameter_list": "ensemble=1", ## "start_time": "2005-01-01", ## "finish_time": "2011-12-31" ## }, ## ... ## ] ## "count": 50, ## "next_page": "http://pecan.localhost/api/workflows/?workflow_id=1000009172&offset=50&limit=50" ## } 16.4.20 GET /api/runs/{run_id} 16.4.20.1 R Snippet # Get details of run belonging with `id` = '99000000282' res <- httr::GET( "http://pecan.localhost/api/runs/99000000282", httr::authenticate("carya", "illinois") ) print(jsonlite::fromJSON(rawToChar(res$content))) ## $runtype ## [1] "sensitivity analysis" ## $ensemble_id ## [1] 99000000016 ## $workflow_id ## [1] 99000000031 ## $id ## [1] 99000000282 ## $model_id ## [1] 1000000014 ## $site_id ## [1] 772 ## $start_time ## [1] "2002-01-01" ## $finish_time ## [1] "2002-12-31" ## $parameter_list ## [1] "quantile=MEDIAN,trait=all,pft=temperate.coniferous" ## $started_at ## [1] "2020-07-22 07:02:40" ## $finished_at ## [1] "2020-07-22 07:02:57" ## $inputs ## $inputs$info ## [1] "README.txt" ## $inputs$others ## [1] "sipnet.clim" "sipnet.in" "sipnet.param" "sipnet.param-spatial" ## $outputs ## $outputs$logfile ## [1] "logfile.txt" ## $outputs$info ## [1] "README.txt" ## $outputs$years ## $outputs$years$`2002` ## $outputs$years$`2002`$data ## [1] "2002.nc" ## $outputs$years$`2002`$variables ## $outputs$years$`2002`$variables$GPP ## [1] "Gross Primary Productivity" ## $outputs$years$`2002`$variables$NPP ## [1] "Net Primary Productivity" ## ... 16.4.20.2 Python Snippet # Get details of run with `id` = '1002042201' response = requests.get( "http://pecan.localhost/api/runs/1002042201", auth=HTTPBasicAuth('carya', 'illinois') ) print(json.dumps(response.json(), indent=2)) ## { ## "runtype": "ensemble", ## "ensemble_id": 1000017624, ## "workflow_id": 1000009172, ## "id": 1002042201, ## "model_id": 1000000022, ## "site_id": 796, ## "parameter_list": "ensemble=1", ## "start_time": "2005-01-01", ## "finish_time": "2011-12-31", ## "inputs": { ## "info": "README.txt", ## "others": [ ## "sipnet.clim", ## "sipnet.in", ## "sipnet.param", ## "sipnet.param-spatial" ## ] ## } ## "outputs": { ## "logfile": "logfile.txt", ## "info": "README.txt", ## "years": { ## "2002": { ## "data": "2002.nc", ## "variables": { ## "GPP": "Gross Primary Productivity", ## "NPP": "Net Primary Productivity", ## ... ## } ## } ## } ## } ## } 16.4.21 GET /api/runs/{run_id}/input/{filename} 16.4.21.1 R Snippet # Download the 'sipnet.in' input file for the run with id = 99000000282 res <- httr::GET( "http://pecan.localhost/api/runs/99000000282/input/sipnet.in", httr::authenticate("carya", "illinois") ) writeBin(res$content, "test.sipnet.in") 16.4.21.2 Python Snippet # Download the 'sipnet.in' input file for the run with id = 99000000282 response = requests.get( "http://pecan.localhost/api/runs/99000000282/input/sipnet.in", auth=HTTPBasicAuth('carya', 'illinois') ) with open("test.sipnet.in", "wb") as file: file.write(response.content) 16.4.22 GET /api/runs/{run_id}/output/{filename} 16.4.22.1 R Snippet # Download the '2002.nc' output file for the run with id = 99000000282 res <- httr::GET( "http://pecan.localhost/api/runs/99000000282/output/2002.nc", httr::authenticate("carya", "illinois") ) writeBin(res$content, "test.2002.nc") 16.4.22.2 Python Snippet # Download the '2002.nc' output file for the run with id = 99000000282 response = requests.get( "http://pecan.localhost/api/runs/99000000282/output/2002.nc", auth=HTTPBasicAuth('carya', 'illinois') ) with open("test.2002.nc", "wb") as file: file.write(response.content) 16.4.23 GET /api/runs/{run_id}/graph/{year}/{y_var} 16.4.23.1 R Snippet # Plot the Gross Primary Productivity vs Time for the run with ID `99000000282` for the year 2002 res <- httr::GET( "http://pecan.localhost/api/runs/99000000282/graph/2002/GPP", httr::authenticate("carya", "illinois") ) writeBin(res$content, "test.png") 16.4.23.2 Python Snippet # Plot the Gross Primary Productivity vs Time for the run with ID `99000000282` for the year 2002 response = requests.get( "http://pecan.localhost/api/runs/99000000282/graph/2002/GPP", auth=HTTPBasicAuth('carya', 'illinois') ) with open("test.png", "wb") as file: file.write(response.content) "],["database-sync.html", "17 Database synchronization", " 17 Database synchronization The database synchronization consists of 2 parts: - Getting the data from the remote servers to your server - Sharing your data with everybody else "],["how-does-it-work.html", "17.1 How does it work?", " 17.1 How does it work? Each server that runs the BETY database will have a unique machine_id and a sequence of ID’s associated. Whenever the user creates a new row in BETY it will receive an ID in the sequence. This allows us to uniquely identify where a row came from. This is information is crucial for the code that works with the synchronization since we can now copy those rows that have an ID in the sequence specified. If you have not asked for a unique ID your ID will be 99. The synchronization code itself is split into two parts, loading data with the load.bety.sh script and exporting data using dump.bety.sh. If you do not plan to share data, you only need to use load.bety.sh to update your database. "],["set-up.html", "17.2 Set up", " 17.2 Set up Requests for new machine ID’s is currently handled manually. To request a machine ID contact Rob Kooper kooper@illinois.edu. In the examples below this ID is referred to as ‘my siteid’. To setup the database to use this ID you need to call load.bety in ‘CREATE’ mode (replacing with the ID if your site) sudo -u postgres {$PECAN}/scripts/load.bety.sh -c -u -m <my siteid> WARNING: At the moment running CREATE deletes all current records in the database. If you are running from the VM this includes both all runs you have done and all information that the database is prepopulated with (e.g. input and model records). Remote records can be fetched (see below), but local records will be lost (we’re working on improving this!) "],["fetch-latest-data.html", "17.3 Fetch latest data", " 17.3 Fetch latest data When logged into the machine you can fetch the latest data using the load.bety.sh script. The script will check what site you want to get the data for and will remove all data in the database associated with that id. It will then reinsert all the data from the remote database. The script is configured using environment variables. The following variables are recognized: - DATABASE: the database where the script should write the results. The default is bety. - OWNER: the owner of the database (if it is to be created). The default is bety. - PG_OPT: additional options to be added to psql (default is nothing). - MYSITE: the (numerical) ID of your site. If you have not requested an ID, use 99; this is used for all sites that do not want to share their data (i.e. VM). 99 is in fact the default. - REMOTESITE: the ID of the site you want to fetch the data from. The default is 0 (EBI). - CREATE: If ‘YES’, this indicates that the existing database (bety, or the one specified by DATABASE) should be removed. Set to YES (in caps) to remove the database. THIS WILL REMOVE ALL DATA in DATABASE. The default is NO. - KEEPTMP: indicates whether the downloaded file should be preserved. Set to YES (in caps) to keep downloaded files; the default is NO. - USERS: determines if default users should be created. Set to YES (in caps) to create default users with default passwords. The default is NO. All of these variables can be specified as command line arguments as well, to see the options use -h. load.bety.sh -h ./scripts/load.bety.sh [-c YES|NO] [-d database] [-h] [-m my siteid] [-o owner] [-p psql options] [-r remote siteid] [-t YES|NO] [-u YES|NO] -c create database, THIS WILL ERASE THE CURRENT DATABASE, default is NO -d database, default is bety -h this help page -m site id, default is 99 (VM) -o owner of the database, default is bety -p additional psql command line options, default is empty -r remote site id, default is 0 (EBI) -t keep temp folder, default is NO -u create carya users, this will create some default users dump.bety.sh -h ./scripts/dump.bety.sh [-a YES|NO] [-d database] [-h] [-l 0,1,2,3,4] [-m my siteid] [-o folder] [-p psql options] [-u YES|NO] -a use anonymous user, default is YES -d database, default is bety -h this help page -l level of data that can be dumped, default is 3 -m site id, default is 99 (VM) -o output folder where dumped data is written, default is dump -p additional psql command line options, default is -U bety -u should unchecked data be dumped, default is NO "],["sharing-data.html", "17.4 Sharing data", " 17.4 Sharing data Sharing your data requires a few steps. First, before entering any data, you will need to request an ID from the PEcAn developers. Simply open an issue at github and we will generate an ID for you. If possible, add the URL of your data host. You will now need to synchronize the database again and use your ID. For example if you are given ID=42 you can use the following command: MYID=42 REMOTEID=0 ./scripts/load.bety.sh. This will load the EBI database and set the ID’s such that any data you insert will have the right ID. To share your data you can now run the dump.bey.sh. The script is configured using environment variables, the following variables are recognized: - DATABASE: the database where the script should write the results. The default is bety. - PG_OPT: additional options to be added to psql (default is nothing). - MYSITE: the ID of your site. If you have not requested an ID, use 99, which is used for all sites that do not want to share their data (i.e. VM). 99 is the default. - LEVEL: the minimum access-protection level of the data to be dumped (0=private, 1=restricted, 2=internal collaborators, 3=external collaborators, 4=public). The default level for exported data is level 3. - note that currently only the traits and yields tables have restrictions on sharing. If you share data, records from other (meta-data) tables will be shared. If you wish to extend the access_level to other tables please submit a feature request. - UNCHECKED: specifies whether unchecked traits and yields be dumped. Set to YES (all caps) to dump unchecked data. The default is NO. - ANONYMOUS: specifies whether all users be anonymized. Set to YES (all caps) to keep the original users (INCLUDING PASSWORD) in the dump file. The default is NO. - OUTPUT: the location of where on disk to write the result file. The default is ${PWD}/dump. NOTE: If you want your dumps to be accessible to other PEcAn servers you need to perform the following additional steps Open pecan/scripts/load.bety.sh In the DUMPURL section of the code add a new record indicating where you are dumping your data. Below is the example for SITE number 1 (Boston University) elif [ "${REMOTESITE}" == "1" ]; then DUMPURL="http://psql-pecan.bu.edu/sync/dump/bety.tar.gz" Check your Apache settings to make sure this location is public Commit this code and submit a Pull Request From the URL in the Pull Request, PEcAn administrators will update the machines table, the status map, and notify other users to update their cron jobs (see Automation below) Plans to simplify this process are in the works "],["automation.html", "17.5 Automation", " 17.5 Automation Below is an example of a script to synchronize PEcAn database instances across the network. db.sync.sh #!/bin/bash ## make sure psql is in PATH export PATH=/usr/pgsql-9.3/bin/:$PATH ## move to export directory cd /fs/data3/sync ## Dump Data MYSITE=1 /home/dietze/pecan/scripts/dump.bety.sh ## Load Data from other sites MYSITE=1 REMOTESITE=2 /home/dietze/pecan/scripts/load.bety.sh MYSITE=1 REMOTESITE=5 /home/dietze/pecan/scripts/load.bety.sh MYSITE=1 REMOTESITE=0 /home/dietze/pecan/scripts/load.bety.sh ## Timestamp sync log echo $(date +%c) >> /home/dietze/db.sync.log Typically such a script is set up to run as a cron job. Make sure to schedule this job (crontab -e) as the user that has database privileges (typically postgres). The example below is a cron table that runs the sync every hour at 12 min after the hour. MAILTO=user@yourUniversity.edu 12 * * * * /home/dietze/db.sync.sh "],["database-maintentance.html", "17.6 Database maintentance", " 17.6 Database maintentance All databases need maintenance performed on them. Depending upon the database type this can happen automatically, or it needs to be run through a scheduler or manually. The BETYdb database is Postgresql and it needs to be reindexed and vacuumed on a regular basis. Reindexing introduces efficiencies back into the database by reorganizing the indexes. Vacuuming the database frees up resources to the database by rearranging and compacting the database. Both of these operations are necessary and safe. As always if there’s a concern, a backup of the database should be made ahead of time. While running the reindexing and vacuuming commands, users will notice a slowdown at times. Therefore it’s better to run these maintenance tasks during off hours. 17.6.1 Reindexing the database As mentioned above, reindexing allows the database to become more efficient. Over time as data gets updated and deleted, the indexes become less efficient. This has a negative inpact on executed statements. Reindexing makes the indexes efficient again (at least for a while) allowing faster statement execution and reducing the overall load on the database. The reindex.bety.sh script is provided to simplify reindexing the database. reindex.bety.sh -h ./reindex.bety.sh [-c datalog] [-d database] [-h] [-i table names] [-p psql options] [-q] [-s] [-t tablename] -c catalog, database catalog name used to search for tables, default is bety -d database, default is bety -h this help page -i table names, list of space-separated table names to skip over when reindexing -p additional psql command line options, default is -U bety -q the reindexing should be quiet -s reindex the database after reindexing the tables (this should be done sparingly) -t tablename, the name of the one table to reindex If the database is small enough it’s reasonable to reindex the entire database at one time. To do this manually run or schedule the REINDEX statement. For example: reindex.bety.sh -s For larger databases it may be desireable to reindex entire tables at a time. An efficient way to do this is to reindex the larger tables and then the entire database. For example: reindex.bety.sh -t traits; reindex.bety.sh -t yields; reindex.bety.sh -s For very large databases it may be desirable to reindex one or more individual indexes before reindexing tables and the databases. In this case running specific psql commands to reindex those specific indexes, followed by reindexing the table is a possible approach. For example: psql -U bety -c "REINDEX INDEX index_yields_on_citation_id; REINDEX INDEX index_yields_on_cultivar_id;" reindex.bety.sh -t yields; Splitting up the indexing commands over time allows the database to operate efficiently with minimal impact on users. One approach is to schedule the reindexing of large, complex tables at a spcific off-time during the week, followed by a general reindexing and excluding those large tables on a weekend night. Please refere to the Automation section above for information on using cron to schedule reindexing commands. 17.6.2 Vacuuming the database Vacuuming the BETYdb Postgresql database reduces the amount of resources it uses and introduces its own efficiencies. Over time, modified and deleted records leave ‘holes’ in the storage of the database. This is a common feature for most databases. Each database has its own way of handing this, in Postgresql it’s the VACUUM command. The VACUUM command performs two main operations: cleaning up tables to make memory use more efficient, and analyze tables for optimum statement execution. The use of the keyword ANALYZE indicates the second operation should take place. The vacuum.bety.sh script is provided to simplify vacuuming the database. vacuum.bety.db -h ./vacuum.bety.sh [-c datalog] [-d database] [-f] [-h] [-i table names] [-n] [-p psql options] [-q] [-s] [-t tablename] [-z] -c catalog, database catalog name used to search for tables, default is bety -d database, default is bety -f perform a full vacuum to return resources to the system. Specify rarely, if ever -h this help page -i table names, list of space-separated table names to skip over when vacuuming -n only vacuum the tables and do not analyze, default is to first vacuum and then analyze -p additional psql command line options, default is -U bety -q the export should be quiet -s skip vacuuming the database after vacuuming the tables -t tablename, the name of the one table to vacuum -z only perform analyze, do not perform a regular vacuum, overrides -n and -f, sets -s For small databases with light loads it may be possible to set aside a time for a complete vacuum. During this time, commands executed against the database might fail (a temporary condition as the database gets cleaned up). The following commands can be used to perform all the vaccum operations in one go. vacuum.bety.sh -f Generally it’s not desireable to have down time. If the system running the database doesn’t need resources that the database is using returned to it, a FULL vacuum can be avoided. This is the default behavior of the script vacuum.bety.sh In larger databases, vacuuming the entire database can take a long time causing a negative impact on users. This means that individual tables need to be vacuumed. How often a vacuum needs to be performed is dependent upon a table’s activity. The more frequently updates and deletes occur on a table, the more frequent the vaccum should be. For large tables it may be desireable to separate the table cleanup from the analysis. An example for completely vacuuming and analyzing a table is: psql -U bety -c "VACUUM traits; VACUUM ANALYZE traits;" Similar to indexes, vacuuming the most active tables followed by general database vacuuming and vacuum analyze may be a desireable approach. Also note that it isn’t necessary to run VACUUM ANALYZE for each vacuum performed. Separating the commands and performing a VACUUM ANALYZE after several regular vacuums may be sufficient, with less load on the database. If the BETYdb database is running on a system with limited resources, or with resources that have become limited, the VACCUM command can return resources to the system from the database. The normal vacuuming process releases resources back to the database for reuse, but not to the system; generally this isn’t a problem. Postgresql has a VACUUM keyword FULL that returns resources back to the system. Requesting a FULL vacuum will lock the table being vacuumed while it is being re-written preventing any statements from being executed against it. If performing VECUUM FULL against the entire database, only the table being actively worked on is locked. To minimize the impact a VACUUM FULL has on users, it’s best to perform a normal vacuum before a FULL vacuum. If this approach is taken, there sould be a minimal time gap between the normal VACUUM and the VACUUM FULL commands. A normal vacuum allows changes to be made thus requiring the full vacuum to handle those changes, extending it’s run time. Reducing the time between the two commands lessens the work VACUUM FULL needs to do. psql -U bety -c "VACUUM yields; VACUUM FULL yields; VACUUM ANALYZE yields;" Give its impact, it’s typically not desireable to perform a VACUUM FULL after every normal vacuum; it should be done on an “as needed” basis or infrequently. "],["troubleshooting-1.html", "17.7 Troubleshooting", " 17.7 Troubleshooting There are several possibilities if a scheduled cron job apepars to be running but isn’t producing the expected results. The following are suggestions on what to try to resolve the issue. 17.7.1 Username and password The user that scheduled a cron job may not have access permissions to the database. This can be easily confirmed by running the command line from the cron job while logged in as the user that scheduled the job. An error message will be shown if the user doesn’t have permissions. To resolve this, be sure to include a valid database user (not a BETYdb user) with their credentials on the command in crontab. 17.7.2 db_hba.conf file Iit’s possible that the machine hosting the docker image of the database doesn’t have permissions to access the database. This may due to the cron job running on a machine that is not the docker instance of the database. It may be necessary to look at the loga on the hosting machine to determine if database access permissions are causing a problem. Logs are stored in different locations depending upon the Operating System of the host and upon other environmental factors. This document doesn’t provide information on where to find the logs. To begin, it’s best to look at the contents of the relevent database configuration file. The following command will display the contents of the db_hba.conf file. psql -U postgres -qAt -c "show hba_file" | xargs grep -v -E '^[[:space:]]*#' This command should return a series of text lines. For each row except those begining with ‘local’, the fourth item describes the machines that can access the database. In some cases an IP mask is specified in the fifth that further restricts the machines that have access. The special work ‘all’ in the fourth column grants permissions to all machines. The last column on each line contains the authentication option for the machine(s) specified in the fourth column (with a possible fifth column IP mask modifier). Ensure that the host machine is listed under the fourth column (machine addresse range, or ‘all’), is also included in the IP mask if one was specified, and finally that any authentication option are not set to ‘reject’. If the host machine is not included the db_hba.conf file will need to be updated to allow access. "],["network-status-map.html", "17.8 Network Status Map", " 17.8 Network Status Map https://pecan2.bu.edu/pecan/status.php Nodes: red = down, yellow = out-of-date schema, green = good Edges: red = fail, yellow = out-of-date sync, green = good "],["tasks.html", "17.9 Tasks", " 17.9 Tasks Following is a list of tasks we plan on working on to improve these scripts: - pecanproject/bety#368 allow site-specific customization of information and UI elements including title, contacts, logo, color scheme. "],["standalone-tools-modules.html", "18 Standalone tools (modules)", " 18 Standalone tools (modules) Radiative transfer modeling and remote sensing (modules/rtm); vignette Photosynthesis (modules/photosynthesis); vignette Allometry (modules/allometry); vignette Load data (modules/benchmark – PEcAn.benchmark::load_data) "],["LoadData.html", "18.1 Loading Data in PEcAn", " 18.1 Loading Data in PEcAn If you are loading data in to PEcAn for benchmarking, using the Benchmarking shiny app [provide link?] is recommended. Data can be loaded manually using the load_data function which in turn requires providing data format information using query.format.vars and the path to the data using query.file.path. Below is a description of the load_data function an a simple example of loading data manually. 18.1.1 Inputs Required data.path: path to the data that is the output of the function query.file.path (see example below) format: R list object that is the output of the function query.format.vars (see example below) Optional start_year = NA: end_year = NA: site = NA vars.used.index=NULL 18.1.2 Output R data frame containing the requested variables converted in to PEcAn standard name and units and time steps in POSIX format. 18.1.3 Example The data for this example has already been entered in to the database. To add new data go to new data documentation. To load the Ameriflux data for the Harvard Forest (US-Ha1) site. Create a connection to the BETY database. This can be done using R function bety = PEcAn.DB::betyConnect(php.config = "pecan/web/config.php") where the complete path to the config.php is specified. See here for an example config.php file. Look up the inputs record for the data in BETY. To find the input ID, either look at The url of the record (see image above) In R run library(dplyr) input_name = "AmerifluxLBL_site_0-758" #copied directly from online input.id = tbl(bety,"inputs") %>% filter(name == input_name) %>% pull(id) Additional arguments to query.format.vars are optional If you only want to load a subset of dates in the data, specify start and end year, otherwise all data will be loaded. If you only want to load a select list of variables from the data, look up their IDs in BETY, otherwise all variables will be loaded. In R run format = PEcAn.DB::query.format.vars(bety, input.id) Examine the resulting R list object to make sure it returned the correct information. The example format contains the following objects: $file_name [1] "AMERIFLUX_BASE_HH" $mimetype [1] "csv" $skip [1] 2 $header [1] 1 $na.strings [1] "-9999" "-6999" "9999" "NA" $time.row [1] 4 $site [1] 758 $lat [1] 42.5378 $lon [1] -72.1715 $time_zone [1] "America/New_York" The first 4 rows of the table format$vars looks like this: bety_name variable_id input_name input_units storage_type column_number bety_units mstmip_name mstmip_units pecan_name pecan_units air_pressure 554 PA kPa 19 Pa Psurf Pa Psurf Pa airT 86 TA celsius 4 degrees C Tair K Tair K co2atm 135 CO2_1 umol mol-1 20 umol mol-1 CO2air micromol mol-1 CO2air micromol mol-1 datetime 5000000001 TIMESTAMP_START ymd_hms %Y%m%d%H%M 1 ymd_hms NA NA datetime ymd_hms Get the path to the data data.path = PEcAn.DB::query.file.path( input.id = input.id, host_name = PEcAn.remote::fqdn(), con = bety) Load the data data = PEcAn.benchmark::load_data(data.path = data.path, format = format) "],["remote-data-module.html", "18.2 Remote data module", " 18.2 Remote data module Remote data module retrieves remote sensing data from MODISTools, Google Earth Engine and AppEEARS, as well as from the NASA’s Land Processes Distributed Active Archive Center (LP DAAC) data server. For currently available R functions see here, and for the Python functions see RpTools. The downloaded data can be used while performing further analyses in PEcAn. 18.2.0.1 Google Earth Engine Google Earth Engine is a cloud-based platform for performing analysis on satellite data. It provides access to a large data catalog through an online JavaScript code editor and a Python API. Datasets currently available for use in PEcAn via Google Earth Engine are, Sentinel-2 MSI gee2pecan_s2(). It is possible to estimate Leaf Area Index (LAI) from Sentinel-2 data using the ESA SNAP algorithm. SMAP Global Soil Moisture Data gee2pecan_smap() Landsat 8 Surface Reflectance gee2pecan_l8() Global Forest Canopy Height, 2019 gee2pecan_gedi() 18.2.0.2 AppEEARS AppEEARS (Application for Extracting and Exploring Analysis Ready Samples) is an online tool which provides an easy to use interface for downloading analysis ready remote sensing data. Products available on AppEEARS. Note: AppEEARS uses a task based system for processing the data request, it is possible for a task to run for long hours before it gets completed. The module checks the task status after every 60 seconds and saves the files when the task gets completed. 18.2.0.3 LP DAAC Data Pool LP DAAC (Land Processes Distributed Active Archive Center) Data Pool is a NASA Earthdata login-enabled server located at the USGS Earth Resources Observation and Science (EROS) Center that archives and distributes land data products. Similar to AppEEARS, using this source also requires an Earthdata account (see below). Currently this pipeline is implemented and tested only for the GEDI dataset. For more information about the data you are downloading, including documentation and how to properly cite the data, please visit https://lpdaac.usgs.gov/. 18.2.0.4 Set-Up instructions (first time and one time only): Sign up for the Google Earth Engine. Follow the instructions here to sign up for using GEE. You need to have your own GEE account for using the GEE download functions in this module. Sign up for NASA Earthdata. Using AppEEARS and LP DAAC Data Pool requires an Earthdata account visit this page to create your own account. Install the RpTools package. Python codes required by this module are stored in a Python package named “RpTools” using this requires Python3 and the package manager pip3 to be installed in your system. To install the package, Navigate to pecan/modules/data.remote/inst/RpTools If you are inside the pecan directory, this can be done by, cd modules/data.remote/inst/RpTools Use pip3 to install the package. “-e” flag is used to install the package in an editable or develop mode, so that changes made to the code get updated in the package without reinstalling. pip3 install -e . Authenticate GEE. The GEE API needs to be authenticated using your credentials. The credentials will be stored locally on your system. This can be done by, #this will open a browser and ask you to sign in with the Google account registered for GEE earthengine authenticate Alternate way, python3 import ee ee.Authenticate() Save the Earthdata credentials. If you wish to use AppEEARS or LP DAAC data pool you will have to store your username and password inside a JSON file and then pass its file path as an argument in remote_process 18.2.0.5 Usage guide: This module is accesible using the R function remote_process which uses the Python package “RpTools” (located at data.remote/inst/RpTools) for downloading and processing data. RpTools has a function named rp_control which controls two other functions, get_remote_data which controls the scripts which are used for downloading data from the source. For example, gee2pecan_s2 downloads bands from Sentinel 2 using GEE. process_remote_data which controls the scripts responsible for processing the raw data. For example, bands2lai_snap uses the downloaded bands to compute LAI using the SNAP algorithm. Workflow of the module 18.2.1 Configuring remote_process remote_process is configured using remote data tags in the pecan.xml. The required tags are described below, <remotedata> <out_get_data>...</out_get_data> <source>...</source> <collection>...</collection> <scale>...</scale> <projection>...</projection> <qc>...</qc> <algorithm>...</algorithm> <credfile>...</credfile> <out_process_data>...</out_process_data> <overwrite>...</overwrite> </remotedata> out_get_data: (required) type of raw output requested, e.g, bands, smap source: (required) source of remote data, e.g., gee or appeears collection: (required) dataset or product name as it is provided on the source, e.g. “COPERNICUS/S2_SR” for gee or “SPL3SMP_E.003” for appeears scale: (optional) pixel resolution required for some gee collections, recommended to use 10 for Sentinel 2 scale Information about how GEE handles scale can be found out here projection: (optional) type of projection. Only required for appeears polygon AOI type qc: (optional) quality control parameter, required for some gee collections overwrite: (optional) if TRUE database checks will be skipped and existing data of same type will be replaced entirely. When processed data is requested, the raw data required for creating it will also be replaced. By default FALSE If you don’t want to enter your Earthdata credentials everytime you use AppEEARS or LP DAAC use the following tag too: credfile: (optional) absolute path to JSON file containing Earthdata username and password, only required when using AppEEARS and LP DAAC data pool. The contents of this file could be as simple as the following: { "username": "yourEARTHDATAusername", "password": "yourEARTHDATApassword" } These tags are only required if processed data (i.e. further processing after downloading the data) is requested: out_process_data: (optional) type of processed output requested, e.g, lai algorithm: (optional) algorithm used for processing data, currently only SNAP is implemented to estimate LAI from Sentinel-2 bands Additional information are taken from the registration files located at pecan/modules/data.remote/inst/registration, each source has its own registration file. This is so because there isn’t a standardized way to retrieve all image collections from GEE and each image collection may require its own way of performing quality checks, etc whereas all of the products available on AppEEARS can be retrieved using its API in a standardized way. GEE registration file (register.GEE.xml) : collection original_name original name of the image collection, e.g. COPERNICUS/S2_SR pecan_name short form of original name using which the collection is represented in PEcAn, e.g. s2 coord coord_type coordinate type supported by the collection scale the default value of the scale can be specified here qc the default value of the qc parameter can be specified here raw_format format details of the raw file id id of the format name name of the format mimetype MIME type pro_format format details of the processed file when the collection is used to create a processed file id id of the format name name of the format mimetype MIME type AppEEARS and LP DAAC Data Pool registration files (register.APPEEARS.xml and register.LPDAACDATAPOOL.xml) : coord coord_type coordinate type supported by the product raw_format format details of the output file id id of the format name name of the format mimetype MIME type Remaining input data: start date, end date: these are taken from the run tag in pecan.xml outdir: from the outdir tag in pecan.xml Area of interest: the coordinates and site name are found out from BETY using siteid present in the run tag. These are then used to create a GeoJSON file which is used by the download functions. The output data from the module are returned in the following tags: raw_id: input id of the raw file raw_path: absolute path to the raw file pro_id: input id of the processed file pro_path: absolute path to the processed file Output files: The output files are of netCDF type and are stored in a directory inside the specified outdir with the following naming convention: source_site_siteid The output files are created with the following naming convention: source_collection_scale_projection_qc_site_siteid_TimeStampOfFileCreation Whenever a data product is requested the output files are stored in the inputs table of BETYdb. Subsequently when the same product is requested again with a different date range but with the same qc, scale, projection the previous file in the db would be extended. The DB would always contain only one file of the same type. As an example, if a file containing Sentinel 2 bands for start date: 2018-01-01, end date: 2018-06-30 exists in the DB and the same product is requested again for a different date range one of the following cases would happen, New dates are ahead of the existing file: For example, if the requested dates are start: 2018-10-01, end: 2018-12-31 in this case the previous file will be extended forward meaning the effective start date of the file to be downloaded would be the day after the end date of the previous file record, i.e. 2018-07-01. The new and the previous file would be merged and the DB would now be having data for 2018-01-01 to 2018-12-31. New dates are preceding of the existing file: For example, if the requested dates are start: 2017-01-01, end: 2017-06-30 in this case the effective end date of the new download would be the day before the start date of the existing file, i.e., 2017-12-31. The new and the previous file would be merged and the file in the DB would now be having data for 2017-01-01 to 2018-06-30. New dates contain the date range of the existing file: For example, if the requested dates are start: 2016-01-01, end: 2019-06-30 here the existing file would be replaced entirely with the new file. A more efficient way of doing this could be to divide your request into two parts, i.e, first request for 2016-01-01 to 2018-01-01 and then for 2018-06-30 to 2019-06-30. When a processed data product such as SNAP-LAI is requested, the raw product (here Sentinel 2 bands) used to create it would also be stored in the DB. If the raw product required for creating the processed product already exists for the requested time period, the processed product would be created for the entire time period of the raw file. For example, if Sentinel 2 bands are present in the DB for 2017-01-01 to 2017-12-31 and SNAP-LAI is requested for 2017-03-01 to 2017-07-31, the output file would be containing LAI for 2017-01-01 to 2017-12-31. 18.2.1.1 Creating Polygon based sites A polygon site can be created in the BETYdb using the following way, PEcAn.DB::db.query("insert into sites (country, sitename, geometry) values ('country_name', 'site_name', ST_SetSRID(ST_MakePolygon(ST_GeomFromText('LINESTRING(lon lat elevation)')), crs));", con) Example, db.query("insert into sites (country, sitename, geometry) values ('FI', 'Qvidja_ca6cm', ST_SetSRID(ST_MakePolygon(ST_GeomFromText('LINESTRING(22.388957339620813 60.287395608412218 14.503780364990234, 22.389600591651835 60.287182336733203 14.503780364990234, 22.38705422266651 60.285516177775868 14.503780364990234, 22.386575219445195 60.285763643883932 14.503780364990234, 22.388957339620813 60.287395608412218 14.503780364990234 )')), 4326));", con) 18.2.1.2 Example use (GEE) This example will download Sentinel 2 bands and then use the SNAP algorithm to compute Leaf Area Index. Add remotedata tag to pecan.xml and configure it. <remotedata> <out_get_data>bands</out_get_data> <source>gee</source> <collection>COPERNICUS/S2_SR</collection> <scale>10</scale> <qc>1</qc> <algorithm>snap</algorithm> <out_process_data>LAI</out_process_data> </remotedata> Store the contents of pecan.xml in a variable named settings and pass it to remote_process. PEcAn.data.remote::remote_process(settings) The output netCDF files(bands and LAI) will be saved at outdir and their records would be kept in the inputs table of BETYdb. 18.2.1.3 Example use (AppEEARS) This example will download the layers of a SMAP product(SPL3SMP_E.003) Add remotedata tag to pecan.xml and configure it. <remotedata> <out_get_data>smap</out_get_data> <source>appeears</source> <collection>SPL3SMP_E.003</collection> <projection>native</projection> <algorithm></algorithm> <credfile>path/to/jsonfile/containingcredentials</credfile> </remotedata> Store the contents of pecan.xml in a variable named settings and pass it to remote_process. PEcAn.data.remote::remote_process(settings) The output netCDF file will be saved at outdir and its record would be kept in the inputs table of BETYdb. 18.2.1.4 Example use GEDI (LP DAAC data pool) <remotedata> <out_get_data>gedi</out_get_data> <source>lpdaacdatapool</source> <collection>GEDI02_B.002</collection> <credfile>path/to/jsonfile/containingcredentials</credfile> </remotedata> Store the contents of pecan.xml in a variable named settings and pass it to remote_process. PEcAn.data.remote::remote_process(settings) 18.2.1.5 Adding new GEE image collections Once you have the Python script for downloading the collection from GEE, please do the following to integrate it with this module. Make sure that the function and script names are same and named in the following way: gee2pecan_pecancodeofimagecollection pecancodeofimagecollection can be any name which you want to use for representing the collection is an easier way. Additionaly, ensure that the function accepts and uses the following arguments, geofile - (str) GeoJSON file containing AOI information of the site outdir - (str) path where the output file has to be saved start - (str) start date in the form YYYY-MM-DD end - (str) end date in the form YYYY-MM-DD scale and qc if applicable. Make sure the output file is of netCDF type and follows the naming convention described above. Store the Python script at pecan/modules/data.remote/inst/RpTools/RpTools Update the register.GEE.xml file. After performing these steps the script will be integrated with the remote data module and would be ready to use. "],["shiny.html", "19 Shiny ", " 19 Shiny "],["testing-the-shiny-server.html", "19.1 Testing the Shiny Server", " 19.1 Testing the Shiny Server Shiny can be difficult to debug because, when run as a web service, the R output is hidden in system log files that are hard to find and read. One useful approach to debugging is to use port forwarding, as follows. First, on the remote machine (including the VM), make sure R’s working directory is set to the directory of the Shiny app (e.g., setwd(/path/to/pecan/shiny/WorkflowPlots), or just open the app as an RStudio project). Then, in the R console, run the app as: shiny::runApp(port = XXXX) # E.g. shiny::runApp(port = 5638) Then, on your local machine, open a terminal and run the following command, matching XXXX to the port above and YYYY to any unused port on your local machine (any 4-digit number should work). ssh -L YYYY:localhost:XXXX <remote connection> # E.g., for the PEcAn VM, given the above port: # ssh -L 5639:localhost:5638 carya@localhost -p 6422 Now, in a web browser on your local machine, browse to localhost:YYYY (e.g., localhost:5639) to run whatever app you started with shiny::runApp in the previous step. All of the output should display in the R console where the shiny::runApp command was executed. Note that this includes any print, message, logger.*, etc. statements in your Shiny app. If the Shiny app hits an R error, the backtrace should include a line like Hit error at of server.R#LXX – that XX being a line number that you can use to track down the error. To return from the error to a normal R prompt, hit <Control>-C (alternatively, the “Stop” button in RStudio). To restart the app, run shiny::runApp(port = XXXX) again (keeping the same port). Note that Shiny runs any code in the pecan/shiny/<app> directory at the moment the app is launched. So, any changes you make to the code in server.R and ui.R or scripts loaded therein will take effect the next time the app is started. If for whatever reason this doesn’t work with RStudio, you can always run R from the command line. Also, note that the ability to forward ports (ssh -L) may depend on the ssh configuration of your remote machine. These instructions have been tested on the PEcAn VM (v.1.5.2+). "],["debugging-shiny-apps.html", "19.2 Debugging Shiny Apps", " 19.2 Debugging Shiny Apps When developing shiny apps you can run the application from rstudio and place breakpoints int he code. To do this you will need to do the following steps first (already done on the VM) before starting rstudio: - echo “options(shiny.port = 6438)” >> ${HOME}/.Rprofile - echo “options(shiny.launch.browser = ‘FALSE’)” >> ${HOME}/.Rprofile Next you will need to create a tunnel for port 6438 to the VM, which will be used to open the shiny app, the following command will creat this tunnel: ssh -l carya -p 6422 -L 6438:localhost:6438 localhost. Now you can from rstudio run your application using shiny::runApp() and it will show the output from the application in your console. You can now place breakpoints and evaluate the output. "],["checking-log-files.html", "19.3 Checking Log Files", " 19.3 Checking Log Files To create Log files on the VM, execute the following: sudo -s echo "preserve_logs true;" >> /etc/shiny-server/shiny-server.conf service shiny-server restart Then within the directory /var/log/shiny-server you will see log files for your specific shiny apps. "],["adding-to-pecan.html", "20 Adding to PEcAn", " 20 Adding to PEcAn Case studies Adding a model Adding input data Adding data through the web interface Adding new species, PFTs, and traits from a new site Add a site Add some species Add PFT Add trait data Adding a benchmark Adding a met driver Reference (How to edit records in bety) Models Species PFTs Traits Inputs DB files Variables Formats (Link each section to relevant Bety tables) "],["adding-model.html", "20.1 Adding An Ecosystem Model", " 20.1 Adding An Ecosystem Model Adding a model to PEcAn involves two activities: Updating the PEcAn database to register the model Writing the interface modules between the model and PEcAn Note that coupling a model to PEcAn should not require any changes to the model code itself. A key aspect of our design philosophy is that we want it to be easy to add models to the system and we want to using the working version of the code that is used by all other model users, not a special branch (which would rapidly end up out-of-date). 20.1.1 Using PEcAn Database To run a model within PEcAn requires that the PEcAn database has sufficient information about the model. This includes a MODEL_TYPE designation, the types of inputs the model requires, the location of the model executable, and the plant functional types used by the model. The instructions in this section assume that you will be specifying this information using the BETYdb web-based interface. This can be done either on your local VM (localhost:3280/bety or localhost:6480/bety) or on a server installation of BETYdb. However you interact with BETYdb, we encourage you to set up your PEcAn instance to support database syncs so that these changes can be shared and backed-up across the PEcAn network. The figure below summarizes the relevant database tables that need to be updated to add a new model and the primary variables that define each table. 20.1.2 Define MODEL_TYPE The first step to adding a model is to create a new MODEL_TYPE, which defines the abstract model class. This MODEL_TYPE is used to specify input requirements, define plant functional types, and keep track of different model versions. The MODEL_TYPE is created by selecting Runs > Model Type and then clicking on New Model Type. The MODEL_TYPE name should be identical to the MODEL package name (see Interface Module below) and is case sensitive. 20.1.3 MACHINE The PEcAn design acknowledges that the same model executables and input files may exist on multiple computers. Therefore, we need to define the machine that that we are using. If you are running on the VM then the local machine is already defined as pecan. Otherwise, you will need to select Runs > Machines, click New Machine, and enter the URL of your server (e.g. pecan2.bu.edu). 20.1.4 MODEL Next we are going to tell PEcAn where the model executable is. Select Runs > Files, and click ADD. Use the pull down menu to specify the machine you just defined above and fill in the path and name for the executable. For example, if SIPNET is installed at /usr/local/bin/sipnet then the path is /usr/local/bin/ and the file (executable) is sipnet. Now we will create the model record and associate this with the File we just registered. The first time you do this select Runs > Models and click New Model. Specify a descriptive name of the model (which doesn’t have to be the same as MODEL_TYPE), select the MODEL_TYPE from the pull down, and provide a revision identifier for the model (e.g. v3.2.1). Once the record is created select it from the Models table and click EDIT RECORD. Click on “View Related Files” and when the search window appears search for the model executable you just added (if you are unsure which file to choose you can go back to the Files menu and look up the unique ID number). You can then associate this Model record with the File by clicking on the +/- symbol. By contrast, clicking on the name itself will take you to the File record. In the future, if you set up the SAME MODEL VERSION on a different computer you can add that Machine and File to PEcAn and then associate this new File with this same Model record. A single version of a model should only be entered into PEcAn once. If a new version of the model is developed that is derived from the current version you should add this as a new Model record but with the same MODEL_TYPE as the original. Furthermore, you should set the previous version of the model as Parent of this new version. 20.1.5 FORMATS The PEcAn database keep track of all the input files passed to models, as well as any data used in model validation or data assimilation. Before we start to register these files with PEcAn we need to define the format these files will be in. To create a new format see Formats Documentation. 20.1.6 MODEL_TYPE -> Formats For each of the input formats you specify for your model, you will need to edit your MODEL_TYPE record to add an association between the format and the MODEL_TYPE. Go to Runs > Model Type, select your record and click on the Edit button. Next, click on “Edit Associated Formats” and choose the Format you just defined from the pull down menu. If the Input box is checked then all matching Input records will be displayed in the PEcAn site run selection page when you are defining a model run. In other words, the set of model inputs available through the PEcAn web interface is model-specific and dynamically generated from the associations between MODEL_TYPEs and Formats. If you also check the Required box, then the Input will be treated as required and PEcAn will not run the model if that input is not available. Furthermore, on the site selection webpage, PEcAn will filter the available sites and only display pins on the Google Map for sites that have a full set of required inputs (or where those inputs could be generated using PEcAn’s workflows). Similarly, to make a site appear on the Google Map, all you need to do is specify Inputs, as described in the next section, and the point should automatically appear on the map. 20.1.7 INPUTS After a file Format has been created then input files can be registered with the database. Creating Inputs can be found under How to insert new Input data. 20.1.8 Add Plant Functional Types (PFTs) Since many of the PEcAn tools are designed to keep track of parameter uncertainties and assimilate data into models, to use PEcAn with a model it is important to define Plant Functional Types for the sites or regions that you will be running the model. Create a new PFT entry by selecting Data > PFTs and then clicking on New PFT. Give the PFT a descriptive name (e.g., temperate deciduous). PFTs are MODEL_TYPE specific, so choose your MODEL_TYPE from the pull down menu. 20.1.8.1 Species Within PEcAn there are no predefined PFTs and user can create new PFTs very easily at whatever taxonomic level is most appropriate, from PFTs for individual species up to one PFT for all plants globally. To allow PEcAn to query its trait database for information about a PFT, you will want to associate species with the PFT record by choosing Edit and then “View Related Species”. Species can be searched for by common or scientific name and then added to a PFT using the +/- button. 20.1.8.2 Cultivars You can also define PFTs whose members are cultivars instead of species. This is designed for analyses where you want to want to perform meta-analysis on within-species comparisons (e.g. cultivar evaluation in an agricultural model) but may be useful for other cases when you want to specify different priors for some member of a species. You cannot associate both species and cultivars with the same PFT, but the cultivars in a cultivar PFT may come from different species, potentially including all known cultivars from some of the species, if you wish to and have thought about how to interpret the results. It is not yet possible to add a cultivar PFT through the BETYdb web interface. See this GithHub comment for an example of how to define one manually in PostgreSQL. 20.1.9 Adding Priors for Each Variable In addition to adding species, a PFT is defined in PEcAn by the list of variables associated with the PFT. PEcAn takes a fundamentally Bayesian approach to representing model parameters, so variables are not entered as fixed constants but as prior probability distributions. There are a wide variety of priors already defined in the PEcAn database that often range from very diffuse and generic to very informative priors for specific PFTs. These pre-existing prior distributions can be added to a PFT. Navigate to the PFT from Data > PFTs and selecting the edit button in the Actions column for the chosen PFT. Click on “View Related Priors” button and search through the list for desired prior distributions. The list can be filtered by adding terms into the search box. Add a prior to the PFT by clicking on the far left button for the desired prior, changing it to an X. Save this by scrolling to the bottom of the PFT page and hitting the Update button. 20.1.9.1 Creating new prior distributions A new prior distribution can be created for a pre-existing variable, if a more constrained or specific one is known. Select Data > Priors then “New Prior” In the Citation box, type in or select an existing reference that indicates how the prior was defined. There are a number of unpublished citations in current use that simply state the expert opinion of an individual Fill the Variable box by typing in part or all of a pre-existing variable’s name and selecting it The Phylogeny box allows one to specify what taxonomic grouping the prior is defined for, at it is important to note that this is just for reference and doesn’t have to be specified in any standard way nor does it have to be monophyletic (i.e. it can be a functional grouping) The prior distribution is defined by choosing an option from the drop-down Distribution box, and then specifying values for both Parameter a and Parameter b. The exact meaning of the two parameters depends on the distribution chosen. For example, for the Normal distribution a and b are the mean and standard deviation while for the Uniform they are the minimum and maximum. All parameters are defined based on their standard parameterization in the R language Specify the prior sample size in N if the prior is based on observed data (independent of data in the PEcAn database) When this is done, scroll down and hit the Create button The new prior distribution can then be added a PFT as described in the “Adding Priors for Each Variable” section. 20.1.9.2 Creating new variables It is important to note that the priors are defined for the variable name and units as specified in the Variables table. If the variable name or units is different within the model it is the responsibility of write.configs.MODEL function to handle name and unit conversions (see Interface Modules below). This can also include common but nonlinear transformations, such as converting SLA to LMA or changing the reference temperature for respiration rates. To add a new variable, select Data > Variables and click the New Variable button. Fill in the Name field with the desired name for the variable and the units in the Units field. There are additional fields, such as Standard Units, Notes, and Description, that can be filled out if desired. When done, hit the Create button. The new variable can be used to create a prior distribution for it as in the “Creating new prior distributions” section. 20.1.10 Interface Modules 20.1.10.1 Setting up the module directory (required) PEcAn assumes that the interface modules are available as an R package in the models directory named after the model in question. The simplest way to get started on that R package is to make a copy the template directory in the pecan/models folder and re-name it to the name of your model. In the code, filenames, and examples below you will want to substitute the word MODEL for the name of your model (note: R is case-sensitive). If you do not want to write the interface modules in R then it is fairly simple to set up the R functions describe below to just call the script you want to run using R’s system command. Scripts that are not R functions should be placed in the inst folder and R can look up the location of these files using the function system.file which takes as arguments the local path of the file within the package folder and the name of the package (typically PEcAn.MODEL). For example "],["example-met-conversion-wrapper-function.html", "20.2 Example met conversion wrapper function", " 20.2 Example met conversion wrapper function met2model.MODEL <- function(in.path, in.prefix, outfolder, start_date, end_date){ myMetScript <- system.file(“inst/met2model.MODEL.sh”, “PEcAn.MODEL”) system(paste(myMetScript, file.path(in.path, in.prefix), outfolder, start_date, end_date)) } would execute the following at the Linux command line inst/met2model.MODEL.sh in.path/in.prefix outfolder start_date end_date ` 20.2.0.1 DESCRIPTION Within the module folder open the DESCRIPTION file and change the package name to PEcAn.MODEL. Fill out other fields such as Title, Author, Maintainer, and Date. 20.2.0.2 NAMESPACE Open the NAMESPACE file and change all instances of MODEL to the name of your model. If you are not going to implement one of the optional modules (described below) at this time then you will want to comment those out using the pound sign #. For a complete description of R NAMESPACE files see here. If you create additional functions in your R package that you want to be used make sure you include them in the NAMESPACE as well (internal functions don’t need to be declared) 20.2.0.3 Building the package Once the package is defined you will then need to add it to the PEcAn build scripts. From the root of the pecan directory, go into the scripts folder and open the file build.sh. Within the section of code that includes PACKAGES= add model/MODEL to the list of packages to compile. If, in writing your module, you add any other R packages to the system you will want to make sure those are listed in the DESCRIPTION and in the script scripts/install.dependencies.R. Next, from the root pecan directory open all/DESCRIPTION and add your model package to the Suggests: list. At any point, if you want to check if PEcAn can build your MODEL package successfully, just go to the linux command prompt and run scripts/build.sh. You will need to do this before the system can use these packages. 20.2.0.4 write.config.MODEL (required) This module performs two primary tasks. The first is to take the list of parameter values and model input files that it receives as inputs and write those out in whatever format(s) the MODEL reads (e.g. a settings file). The second is to write out a shell script, jobs.sh, which, when run, will start your model run and convert its output to the PEcAn standard (netCDF with metadata currently equivalent to the MsTMIP standard). Within the MODEL directory take a close look at inst/template.job and the example write.config.MODEL to see an example of how this is done. It is important that this script writes or moves outputs to the correct location so that PEcAn can find them. The example function also shows an example of writing a model-specific settings/config file, also by using a template. You are encouraged to read the section above on defining PFTs before writing write.config.MODEL so that you understand what model parameters PEcAn will be passing you, how they will be named, and what units they will be in. Also note that the (optional) PEcAn input/driver processing scripts are called by separate workflows, so the paths to any required inputs (e.g. meteorology) will already be in the model-specific format by the time write.config.MODEL receives that info. 20.2.0.5 Output Conversions The module model2netcdf.MODEL converts model output into the PEcAn standard (netCDF with metadata currently equivalent to the MsTMIP standard). This function was previously required, but now that the conversion is called within jobs.sh it may be easier for you to convert outputs using other approaches (or to just directly write outputs in the standard). Whether you implement this function or convert outputs some other way, please note that PEcAn expects all outputs to be broken up into ANNUAL files with the year number as the file name (i.e. YEAR.nc), though these files may contain any number of scalars, vectors, matrices, or arrays of model outputs, such as time-series of each output variable at the model’s native timestep. Note: PEcAn reads all variable names from the files themselves so it is possible to add additional variables that are not part of the MsTMIP standard. Similarly, there are no REQUIRED output variables, though time is highly encouraged. We are shortly going establish a canonical list of PEcAn variables so that if users add additional output variables they become part of the standard. We don’t want two different models to call the same output with two different names or different units as this would prohibit the multi-model syntheses and comparisons that PEcAn is designed to facilitate. 20.2.0.6 met2model.MODEL met2model.MODEL(in.path, in.prefix, outfolder, start_date, end_date) Converts meteorology input files from the PEcAn standard (netCDF, CF metadata) to the format required by the model. This file is optional if you want to load all of your met files into the Inputs table as described in How to insert new Input data, which is often the easiest way to get up and running quickly. However, this function is required if you want to benefit from PEcAn’s meteorology workflows and model run cloning. You’ll want to take a close look at [Adding-an-Input-Converter] to see the exact variable names and units that PEcAn will be providing. Also note that PEcAn splits all meteorology up into ANNUAL files, with the year number explicitly included in the file name, and thus what PEcAn will actually be providing is in.path, the input path to the folder where multiple met files may stored, and in.prefix, the start of the filename that precedes the year (i.e. an individual file will be named <in.prefix>.YEAR.nc). It is valid for in.prefix to be blank. The additional REQUIRED arguments to met2model.MODEL are outfolder, the output folder where PEcAn wants you to write your meteorology, and start_date and end_date, the time range the user has asked the meteorology to be processed for. 20.2.0.7 Commit changes Once the MODEL modules are written, you should follow the Using-Git instructions on how to commit your changes to your local git repository, verify that PEcAn compiles using scripts/build.sh, push these changes to Github, and submit a pull request so that your model module is added to the PEcAn system. It is important to note that while we encourage users to make their models open, adding the PEcAn interface module to the Github repository in no way requires that the model code itself be made public. It does, however, allow anyone who already has a copy of the model code to use PEcAn so we strongly encourage that any new model modules be committed to Github. "],["NewInput.html", "20.3 Adding input data", " 20.3 Adding input data 20.3.1 Input records in BETY All model input data or data used for model calibration/validation must be registered in the BETY database. Before creating a new Input record, you must make sure that the format type of your data is registered in the database. If you need to make a new format record, see Creating a new format record in BETY. 20.3.2 Create a database file record for the input data An input record contains all the metadata required to identify the data, however, this record does not include the location of the data file. Since the same data may be stored in multiple places, every file has its own dbfile record. From your BETY interface: Create a DBFILES entry for the path to the file From the menu click RUNS then FILES Click “New File” Select the machine your file is located at Fill in the File Path where your file is located (aka folder or directory) NOT including the name of the file itself Fill in the File Name with the name of the file itself. Note that some types of input records will refer to be ALL the files in a directory and thus File Name can be blank Click Update 20.3.3 Creating a new Input record in BETY From your BETY interface: Create an INPUT entry for your data From the menu click RUNS then INPUTS Click “New Input” Select the SITE that this data is associated with the input data set Other required fields are a unique name for the input, the start and end dates of the data set, and the format of the data. If the data is not in a currently known format you will need to create a NEW FORMAT and possibly a new input converter. Instructions on how to do add a converter can be found here Input conversion. Instructions on how to add a format record can be found here Parent ID is an optional variable to indicated that one dataset was derived from another. Click “Create” Associate the DBFILE with the INPUT In the RUNS -> INPUTS table, search and find the input record you just created Click on the EDIT icon Select “View related Files” In the Search window, search for the DBFILE you just created Once you have found the DBFILE, click on the “+” icon to add the file Click on “Update” at the bottom when you are done. 20.3.4 Adding a new input converter Three Types of data conversions are discussed below: Meteorological data, Vegetation data, and Soil data. Each section provides instructions on how to convert data from their raw formats into a PEcAn standard format, whether it be from a database or if you have raw data in hand. Also, see PEcAn standard formats. 20.3.4.1 Meterological Data 20.3.4.1.1 Adding a function to PEcAn to convert a met data source In general, you will need to write a function to download the raw met data and one to convert it to the PEcAn standard. Downloading raw data function are named download.<source>.R. These functions are stored within the PEcAn directory: /modules/data.atmosphere/R. Conversion function from raw to standard are named met2CF.<source>.R. These functions are stored within the PEcAn directory: /modules/data.atmosphere/R. Current Meteorological products that are coupled to PEcAn can be found in our Available Meteorological Drivers page. Note: Unless you are also adding a new model, you will not need to write a script to convert from PEcAn standard to PEcAn models. Those conversion scripts are written when a model is added and can be found within each model’s PEcAn directory. Standards dimesion, names, nad units can be found here: Input Standards 20.3.4.1.2 Adding Single-Site Specific Meteorological Data Perhaps you have meteorological data specific to one site, with a unique format that you would like to add to PEcAn. Your steps would be to: 1. write a script or function to convert your files into the netcdf PEcAn standard 2. insert that file as an input record for your site following these instructions 20.3.4.1.3 Processing Met data outside of the workflow using PEcAn functions Perhaps you would like to obtain data from one of the sources coupled to PEcAn on its own. To do so you can run PEcAn functions on their own. 20.3.4.1.3.1 Example 1: Processing data from a database Download Amerifluxlbl from Niwot Ridge for the year 2004: raw.file <-PEcAn.data.atmosphere::download.AmerifluxLBL(sitename = "US-NR1", outfolder = ".", start_date = "2004-01-01", end_date = "2004-12-31") Using the information returned as the object raw.file you will then convert the raw files into a standard file. Open a connection with BETY. You may need to change the host name depending on what machine you are hosting BETY. You can find the hostname listed in the machines table of BETY. con <- PEcAn.DB::db.open( params = list( driver = RPostgres::Postgres(), dbname = 'bety', host ='localhost', user = "bety", password = "bety") ) Next you will set up the arguments for the function in.path <- '.' in.prefix <- raw.file$dbfile.name outfolder <- '.' format.id <- 5000000002 format <- PEcAn.DB::query.format.vars(format.id=format.id,bety = con) lon <- -105.54 lat <- 40.03 format$time_zone <- "America/Chicago" Note: The format.id can be pulled from the BETY database if you know the format of the raw data. Once these arguments are defined you can execute the met2CF.csv function PEcAn.data.atmosphere::met2CF.csv(in.path = in.path, in.prefix =in.prefix, outfolder = ".", start_date ="2004-01-01", end_date = "2004-12-01", lat= lat, lon = lon, format = format) 20.3.4.1.3.2 Example 2: Processing data from data already in hand If you have Met data already in hand and you would like to convert into the PEcAn standard follow these instructions. Update BETY with file record, format record and input record according to this page How to Insert new Input Data If your data is in a csv format you can use the met2CF.csvfunction to convert your data into a PEcAn standard file. Open a connection with BETY. You may need to change the host name depending on what machine you are hosting BETY. You can find the hostname listed in the machines table of BETY. con <- PEcAn.DB::db.open( params = list( driver = RPostgres::Postgres(), dbname = 'bety', host ='localhost', user = "bety", password = "bety") ) Prepare the arguments you need to execute the met2CF.csv function in.path <- 'path/where/the/raw/file/lives' in.prefix <- 'prefix_of_the_raw_file' outfolder <- 'path/to/where/you/want/to/output/thecsv/' format.id <- formatid of the format your created format <- PEcAn.DB::query.format.vars(format.id=format.id, bety = con) lon <- longitude of your site lat <- latitude of your site format$time_zone <- time zone of your site start_date <- Start date of your data in "y-m-d" end_date <- End date of your data in "y-m-d" Next you can execute the function: PEcAn.data.atmosphere::met2CF.csv(in.path = in.path, in.prefix =in.prefix, outfolder = ".", start_date = start_date, end_date = end_date, lat= lat, lon = lon, format = format) 20.3.4.2 Vegetation Data Vegetation data will be required to parameterize your model. In these examples we will go over how to produce a standard initial condition file. The main function to process cohort data is the ic_process.R function. As of now however, if you require pool data you will run a separate function, pool_ic_list2netcdf.R. 20.3.4.2.0.1 Example 1: Processing Veg data from data in hand. In the following example we will process vegetation data that you have in hand using PEcAn. First, you’ll need to create a input record in BETY that will have a file record and format record reflecting the location and format of your file. Instructions can be found in our How to Insert new Input Data page. Once you have created an input record you must take note of the input id of your record. An easy way to take note of this is in the URL of the BETY webpage that shows your input record. In this example we use an input record with the id 1000013064 which can be found at this url: https://psql-pecan.bu.edu/bety/inputs/1000013064# . Note that this is the Boston University BETY database. If you are on a different machine, your url will be different. With the input id in hand you can now edit a pecan XML so that the PEcAn function ic_process will know where to look in order to process your data. The inputs section of your pecan XML will look like this. As of now ic_process is set up to work with the ED2 model so we will use ED2 settings and then grab the intermediary Rds data file that is created as the standard PEcAn file. For your Inputs section you will need to input your input id wherever you see the useic flag. <inputs> <css> <source>FFT</source> <output>css</output> <username>pecan</username> <id>1000013064</id> <useic>TRUE</useic> <metadata> <trk>1</trk> <age>70</age> <area>400</area> </metadata> </css> <pss> <source>FFT</source> <output>pss</output> <username>pecan</username> <id>1000013064</id> <useic>TRUE</useic> </pss> <site> <source>FFT</source> <output>site</output> <username>pecan</username> <id>1000013064</id> <useic>TRUE</useic> </site> <met> <source>CRUNCEP</source> <output>ED2</output> </met> <lu> <id>294</id> </lu> <soil> <id>297</id> </soil> <thsum> <id>295</id> </thsum> <veg> <id>296</id> </veg> </inputs> This IC workflow also supports generating ensembles of initial conditions from posterior estimates of DBH. To do this the tags below can be inserted to the pecan.xml: <css> <source>PalEON</source> <output>css</output> <id>1000015682</id> <useic>TRUE</useic> <ensemble>20</ensemble> <metadata> <area>1256.637</area> <n.patch>3</n.patch> </metadata> </css> Here the id should point to a file that has MCMC samples to generate the ensemble from. The number between the <ensemble> tag defines the number of ensembles requested. The workflow will populate the settings list run$inputs tag with ensemble member information. E.g.: <inputs> <css> <path1>...</path1> <path2>...</path2> <path3>...</path3> ... <pathN>...</pathN> </css> <pss> <path> <path1>...</path1> <path2>...</path2> <path3>...</path3> ... <pathN>...</pathN> </path> </pss> <site> <path> <path1>...</path1> <path2>...</path2> <path3>...</path3> ... <pathN>...</pathN> </path> </site> <met>...</met> <lu>...</lu> <soil>...</soil> <thsum>...</thsum> <veg>...</veg> </inputs> Once you edit your PEcAn.xml you can than create a settings object using PEcAn functions. Your pecan.xml must be in your working directory. settings <- PEcAn.settings::read.settings("pecan.xml") settings <- PEcAn.settings::prepare.settings(settings, force=FALSE) You can then execute the ic_process function to convert data into a standard Rds file: input <- settings$run$inputs dir <- "." ic_process(settings, input, dir, overwrite = FALSE) Note that the argument dir is set to the current directory. You will find the final ED2 file there. More importantly though you will find the .Rds file within the same directory. 20.3.4.2.0.2 Example 3 Pool Initial Condition files If you have pool vegetation data, you’ll need the pool_ic_list2netcdf.R function to convert the pool data into PEcAn standard. The function stands alone and requires that you provide a named list of netcdf dimensions and values, and a named list of variables and values. Names and units need to match the standard_vars.csv table found here. #Create a list object with necessary dimensions for your site input<-list() dims<- list(lat=-115,lon=45, time= 1) variables<- list(SoilResp=8,TotLivBiom=295) input$dims <- dims input$vals <- variables Once this is done, set outdir to where you’d like the file to write out to and a siteid. Siteid in this can be used as an file name identifier. Once part of the automated workflow siteid will reflect the site id within the BET db. outdir <- "." siteid <- 772 pool_ic_list2netcdf(input = input, outdir = outdir, siteid = siteid) You should now have a netcdf file with initial conditions. 20.3.4.3 Soil Data 20.3.4.3.0.1 Example 1: Converting Data in hand Local data that has the correct names and units can easily be written out in PEcAn standard using the function soil2netcdf. soil.data <- list(volume_fraction_of_sand_in_soil = c(0.3,0.4,0.5), volume_fraction_of_clay_in_soil = c(0.3,0.3,0.3), soil_depth = c(0.2,0.5,1.0)) soil2netcdf(soil.data,"soil.nc") At the moment this file would need to be inserted into Inputs manually. By default, this function also calls soil_params, which will estimate a number of hydraulic and thermal parameters from texture. Be aware that at the moment not all model couplers are yet set up to read this file and/or convert it to model-specific formats. 20.3.4.3.0.2 Example 2: Converting PalEON data In addition to location-specific soil data, PEcAn can extract soil texture information from the PalEON regional soil product, which itself is a subset of the MsTMIP Unified North American Soil Map. If this product is installed on your machine, the appropriate step in the do_conversions workflow is enabled by adding the following tag under <inputs> in your pecan.xml <soil> <id>1000012896</id> </soil> In the future we aim to extend this extraction to a wider range of soil products. 20.3.4.3.0.3 Example 3: Extracting soil properties from gSSURGO database In addition to location-specific soil data, PEcAn can extract soil texture information from the gSSURGO data product. This product needs no installation and it extract soil proeprties for the lower 48 states in U.S. In order to let the pecan know that you’re planning to use gSSURGO, you can the following XML tag under input in your pecan xml file. <inputs> <soil> <source>gSSURGO</source> </soil> </inputs> "],["adding-data-web.html", "20.4 Pecan Data Ingest via Web Interface", " 20.4 Pecan Data Ingest via Web Interface This tutorial explains the process of ingesting data into PEcAn via our Data-Ingest Application. In order to ingest data, the users must first select data that they wish to upload. Then, they enter metadata to help PEcAn parse and load the data into the main PEcAn workflow. 20.4.1 Loading Data 20.4.1.1 Selecting Ingest Method The Data-Ingest application is capable of loading data from the DataONE data federation and from the user’s local machine. The first step in the workflow is therefore to select an upload method. The application defaults to uploading from DataONE. To upload data from a local device, simply select the radio button titled Local Files. 20.4.1.2 DataONE Upload Example The DataONE download feature allows the user to download data at a given doi or DataONE specific package id. To do so, enter the doi or identifier in the Import From DataONE field and select download. The download process may take a couple of minutes to run depending on the number of files in the dataONE package. This may be a convenient option if the user does not wish to download files directly to their local machine. Once the files have been successfully downloaded from DataONE, they are displayed in a table. Before proceeding to the next step, the user can select a file to ingest by clicking on the corresponding row in the data table. 20.4.2 Local Upload Example To upload local files, the user should first select the Local Files button. From there, the user can upload files from their local machines by selecting Browse or by dragging and dropping files into the text box. The files will begin uploading automatically. From there, the user should select a file to ingest and then select the Next Step button. After this step, the workflow is identical for both methods. However, please note that if it becomes necessary to switch from loading data via DataONE to uploading local files after the first step, please restart the application. ### 2. Creating an Input Record Creating an input record requires some basic metadata about the file that is being ingested. Each entry field is briefly explained below. Site: To link the selected file with a site, the user can scroll or type to search all the sites in PEcAn. See Example: Parent: To link the selected file with another dataset, type to search existing datasets in the Parent field. Name: this field should be autofilled by selecting a file in step 1. Format: If the selected file has an existing format name, the user can search and select in the Format field. If the selected file’s format is not already in pecan, the user can create a new format by selecting Create New Format. Once this new format is created, it will automatically populate the Format box and the Current Mimetype box (See Section 3). Mimetype: If the format already exists, select an existing mimetype. Start and End Date and Time: Inputs can be entered manually or by using the user interface. See example Notes: Describe the data that is being uploaded. Please include any citations or references. 20.4.3 3. Creating a format record If it is necessary to add a new format to PEcAn, the user should fill out the form attached to the Create New Format button. The inputs to this form are described below: Mimetype: type to search existing mimetypes. If the mimetype is not in that list, please click on the link Create New Mimetype and create a new mimetype via the BETY website. New Format Name: Add the name of the new format. Please exclude spaces from the name. Instead please use underscores “_“. Header: If there is space before the first line of data in the dataset, please select Yes Skip: The number of lines in the header that should be skipped before the data. Please enter notes that describe the format. Example: ### 4. Formats_Variables Record The final step in the ingest process is to register a formats-variables record. This record links pecan variables with variables from the selected data. Variable: PEcAn variable that is equivalent to variable in selected file. Name: The variable name in the imported data need only be specified if it differs from the BETY variable name. Unit: Should be in a format parseable by the udunits library and need only be secified if the units of the data in the file differ from the BETY standard. Storage Type: Storage type need only be specified if the variable is stored in a format other than would be expected (e.g. if numeric values are stored as quoted character strings). Additionally, storage_type stores POSIX codes that are used to store any time variables (e.g. a column with a 4-digit year would be %Y). Column Number: Vector of integers that list the column numbers associated with variables in a dataset. Required for text files that lack headers. Finally, the path to the ingest data is displayed in the Select Files box. "],["NewFormat.html", "20.5 Creating a new format", " 20.5 Creating a new format 20.5.1 Formats in BETY The PEcAn database keeps track of all the input files passed to models, as well as any data used in model validation or data assimilation. Before we start to register these files with PEcAn we need to define the format these files will be in. The main goal is to take all the meta-data we have about a data file and create a record of it that pecan can use as a guide when parsing the data file. This information is stored in a Format record in the bety database. Make sure to read through the current Formats before deciding to make a new one. 20.5.2 Creating a new format in BETY If the Format you are looking for is not available, you will need to create a new record. Before entering information into the database, you need to be able to answer the following questions about your data: What is the file MIME type? We have a suit of functions for loading in data in open formats such as CSV, txt, netCDF, etc. PEcAn has partnered with the NCSA BrownDog project to create a service that can read and convert as many data formats as possible. If your file type is less common or a proprietary type, you can use the BrownDog DAP to convert it to a format that can be used with PEcAn. If BrownDog cannot convert your data, you will need to contact us about writing a data specific load function. What variables does the file contain? What are the variables named? What are the variable units? How do the variable names and units in the data map to PEcAn variables in the BETY database? See below for an example. It is most likely that you will NOT need to add variables to BETY. However, identifying the appropriate variables matches in the database may require some work. We are always available to help answer your questions. Is there a timestamp on the data? What are the units of time? Here is an example using a fake dataset: example_data This data started out as an excel document, but was saved as a CSV file. To create a Formats record for this data, in the web interface of BETY, select Runs > Formats and click New Format. You will need to fill out the following fields: MIME type: File type (you can search for other formats in the text field) Name: The name of your format (this can be whatever you want) Header: Boolean that denotes whether or not your data contains a header as the first line of the data. (1 = TRUE, 0 = FALSE) Skip: The number of lines above the data that should be skipped. For example, metadata that should not be included when reading in the data or blank spaces. Notes: Any additional information about the data such as sources and citations. Here is the Formats record for the example data: format_record_1 When you have finished this section, hit Create. The final record will be displayed on the screen. 20.5.2.1 Formats -> Variables After a Format entry has been created, you are encouraged to edit the entry to add relationships between the file’s variables and the Variables table in PEcAn. Not only do these relationships provide meta-data describing the file format, but they also allow PEcAn to search and (for some MIME types) read files. To enter this data, select Edit Record and on the edit screen select View Related Variable. Here is the record for the example data after adding related variables: format_record_2 20.5.2.1.1 Name and Unit For each variable in the file you will want at a minimum to specify the NAME of the variable within your file and match that to the equivalent Variable in the pulldown. Make sure to search for your variables under Data > Variables before suggesting that we create a new variable record. This may not always be a straightforward process. For example bety contains a record for Net Primary Productivity: var_record This record does not have the same variable name or the same units as NPP in the example data. You may have to do some reading to confirm that they are the same variable. In this case - Both the data and the record are for Net Primary Productivity (the notes section provides additional resources for interpreting the variable.) - The units of the data can be converted to those of the vairiable record (this can be checked by running udunits2::ud.are.convertible(\"g C m-2 yr-1\", \"Mg C ha-1 yr-1\")) Differences between the data and the variable record can be accounted for in the data Formats record. Under Variable, select the variable as it is recorded in bety. Under Name, write the name the variable has in your data file. Under Unit, write the units the variable has in your data file. NOTE: All units must be written in a udunits compliant format. To check that your units can be read by udunits, in R, load the udunits2 package and run udunits2::is.parseable(\"g C m-2 yr-1\") If the name or the units are the same, you can leave the Name and Unit fields blank. This is can be seen with the variable LAI. 20.5.2.1.2 Storage Type Storage Type only needs to be specified if the variable is stored in a format other than what would be expected (e.g. if numeric values are stored as quoted character strings). One such example is time variables. PEcAn converts all dates into POSIX format using R functions such as strptime. These functions require that the user specify the format in which the date is written. The default is \"%Y-%m-%d %H:%M:%S\" which would look like \"2017-01-01 00:00:00\" A list of date formats can be found in the R documentation for the function strptime Below are some commonly used codes: %d Day of the month as decimal number (01–31). %D Date format such as %m/%d/%y. %H Hours as decimal number (00–23). %m Month as decimal number (01–12). %M Minute as decimal number (00–59). %S Second as integer (00–61), allowing for up to two leap-seconds (but POSIX-compliant implementations will ignore leap seconds). %T Equivalent to %H:%M:%S. %y Year without century (00–99). On input, values 00 to 68 are prefixed by 20 and 69 to 99 by 19 – that is the behaviour specified by the 2004 and 2008 POSIX standards, but they do also say ‘it is expected that in a future version the default century inferred from a 2-digit year will change’. %Y Year with century. 20.5.2.1.3 Column Number If your data is in text format with variables in a standard order then you can specify the Column Number for the variable. This is required for text files that lack headers. 20.5.2.2 Retrieving Format Information To acquire Format information from a Format record, use the R function query.format.vars 20.5.2.2.1 Inputs bety: connection to BETY input.id=NA and/or format.id=NA: Input or Format record ID from BETY At least one must be specified. Defaults to format.id if both provided. var.ids=NA: optional vector of variable IDs. If provided, limits results to these variables. 20.5.2.2.2 Output R list object containing many things. Fill this in. "],["NewBenchmark.html", "20.6 Creating a new benchmark reference run", " 20.6 Creating a new benchmark reference run The purpose of the reference run record in BETY is to store all the settings from a run that are necessary in exactly recreating it. The pecan.xml file is the home of absolutely all the settings for a particular run in pecan. However, much of the information in the pecan.xml file is server and user specific and more importantly, the pecan.xml files are stored on individual servers and may not be available to the public. When a run that is performed using pecan is registered as a reference run, the settings that were used to make that run are made available to all users through the database. All completed runs are not automatically registered as reference runs. To register a run, navigate to the benchmarking section of the workflow visualizations Shiny app. "],["editing-records.html", "20.7 Editing records", " 20.7 Editing records Models Species PFTs Traits Inputs DB files Variables Formats (Link each section to relevant Bety tables) "],["troubleshooting-and-debugging-pecan.html", "21 Troubleshooting and Debugging PEcAn ", " 21 Troubleshooting and Debugging PEcAn "],["cookies-and-pecan-web-pages.html", "21.1 Cookies and pecan web pages", " 21.1 Cookies and pecan web pages You may need to disable cookies specifically for the pecan webserver in your browser. This shouldn’t be a problem running from the virtual machine, but your installation of php can include a ‘PHPSESSID’ that is quite long, and this can overflow the params field of the workflows table, depending on how long your hostname, model name, site name, etc are. "],["warning-mkdir-function.mkdir-no-such-file-or-directory.html", "21.2 Warning: mkdir() [function.mkdir]: No such file or directory", " 21.2 Warning: mkdir() [function.mkdir]: No such file or directory If you are seeing: Warning: mkdir() [function.mkdir]: No such file or directory in /path/to/pecan/web/runpecan.php at line 169 it is because you have used a relative path for $output_folder in system.php. "],["after-creating-a-new-pft-the-tag-for-pft-not-passed-to-config.xml-in-ed.html", "21.3 After creating a new PFT the tag for PFT not passed to config.xml in ED", " 21.3 After creating a new PFT the tag for PFT not passed to config.xml in ED This is a result of the rather clunky way we currently have adding PFTs to PEcAn. This is happening because you need to edit the ./pecan/models/ed/data/pftmapping.csv file to include your new PFTs. This is what the file looks like: PEcAn;ED ebifarm.acru;11 ebifarm.acsa3;11 ... You just need to edit this file (in a text editor, no Excel) and add your PFT names and associated number to the end of the file. Once you do this, recompile PEcAn and it should then work for you. We currently need to reference this file in order to properly set the PFT number and maintain internal consistency between PEcAn and ED2. "],["debugging.html", "21.4 Debugging", " 21.4 Debugging How to identify the source of a problem. 21.4.1 Using tests/workflow.R This script, along with model-specific settings files in the tests folder, provide a working example. From inside the tests folder, R CMD --vanilla -- --settings pecan.<model>.xml < workflow.R should work. The next step is to add debugonce(<broken.function.name>) before running the test workflow. This allows you can step through the function and evaluate the different objects as they are created and/or transformed. See tests README for more information. "],["useful-scripts.html", "21.5 Useful scripts", " 21.5 Useful scripts The following scripts (in qaqc/vignettes identify, respectively: relationships among functions across packages function inputs and outputs (e.g. that will identify which functions and outputs are used in a workflow). "],["database.html", "22 BETY Database Administration", " 22 BETY Database Administration This section provides additional details about the BETY database used by PEcAn. It will discuss best practices for setting up the BETY database, how to backup the database and how to restore the database. "],["database-setup.html", "22.1 Best practices", " 22.1 Best practices When using the BETY database in non testing mode, it is best not to use the default users. This is accomplished when running the initialize of the database. When the database is initally created the database will be created with some default users (best known is the carya user) as well as the guestuser that can be used in the BETY web application. To disable these users you will either need to disable the users from the web interface, or you can reinitialize the database and remove the -u flag from the command line (the -u flag will create the default users). To disable the guestuser as well you can remove the -g flag from the command line, or disable the account from BETY. The default installation of BETY and PEcAn will assume there is a database called bety with a default username and password. The default installation will setup the database account to not have any superuser abilities. It is also best to limit access to the postgres database from trusted hosts, either by using firewalls, or configuring postgresql to only accept connections from a limited set of hosts. "],["backup-of-bety-database.html", "22.2 Backup of BETY database", " 22.2 Backup of BETY database It is good practice to make sure you backup the BETY database. Just creating a copy of the files on disk is not enough to ensure you have a valid backup. Most likely if you do this you will end up with a corrupted backup of the database. To backup the database you can use the pg_dump command, which will make sure the database id backed up in a consistent state. You can run sudo -u postgres pg_dump -d bety -Z 9 -f bety.sql.gz, this will create a compressed file that can be used to resotore the database. In the PEcAn distribution in scripts folder there is a script called backup.bety.sh. This script will create the backup of the database. It will create multiple backups allowing you to restore the database from one of these copies. The database will be backed up to one of the following files: - bety-d-X, daily backup, where X is the day of the month. - bety-w-X, weekly backup, where X is the week number in the year - bety-m-X, montly backup, where X is the month of the year - bety-y-X, yearly backup, where X is the actual year. Using this scheme, we can restore the database using any of the files generated. It is recommeneded to run this script using a cronjob at midnight such that you have a daily backup of the database and do not have to remember to create these backups. When running this script (either cron or by hand) make sure to place the backups on a different machine than the machine that holds the database in case of a larger system failure. "],["restore-of-bety-database.html", "22.3 Restore of BETY database", " 22.3 Restore of BETY database Hopefully this section will never need to be used. Following are 5 steps that have been used to restore the database. Before you start it is worth it to read up online a bit on restoring the database as well as join the slack channel and ask any of the people there for help. stop apache (BETY/PEcAn web apps) service httpd stop or service apache2 stop backup database (you know just incase) pg_dump -d bety > baddb.sql drop database sudo -u postgres psql -c 'drop database bety' create database sudo -u postgres psql -c 'create database bety with owner bety' load database (assuming dump is called bety.sql.gz) zcat bety.sql.gz | grep -v search_path | sudo -u postgres psql -d bety start apache again service httpd start or service apache2 start If during step 5 there is a lot of errors, it is helpful to add -v ON_ERROR_STOP=1 to the end of the command. This will stop the restore at the first error and will help with debugging the issue. "],["workflow-modules.html", "23 Workflow modules", " 23 Workflow modules NOTE: As of PEcAn 1.2.6 – needs to be updated significantly "],["overview-1.html", "23.1 Overview", " 23.1 Overview Workflow inputs and outputs (click to open in new page, then zoom). Code used to generate this image is provided in qaqc/vignettes/module_output.Rmd "],["load-settings.html", "23.2 Load Settings", " 23.2 Load Settings 23.2.1 read.settings(\"/home/pecan/pecan.xml\") loads settings create directories generates new xml, put in output folder "],["query-database.html", "23.3 Query Database", " 23.3 Query Database 23.3.1 get.trait.data() Queries the database for both the trait data and prior distributions associated with the PFTs specified in the settings file. The list of variables that are queried is determined by what variables have priors associated with them in the definition of the pft. Likewise, the list of species that are associated with a PFT determines what subset of data is extracted out of all data matching a given variable name. "],["meta-analysis.html", "23.4 Meta Analysis", " 23.4 Meta Analysis 23.4.1 run.meta.analysis() The meta-analysis code begins by distilling the trait.data to just the values needed for the meta-analysis statistical model, with this being stored in madata.Rdata. This reduced form includes the conversion of all error statistics into precision (1/variance), and the indexing of sites, treatments, and greenhouse. In reality, the core meta-analysis code can be run independent of the trait database as long as input data is correctly formatted into the form shown in madata. The evaluation of the meta-analysis is done using a Bayesian statistical software package called JAGS that is called by the R code. For each trait, the R code will generate a [trait].model.bug file that is the JAGS code for the meta-analysis itself. This code is generated on the fly, with PEcAn adding or subtracting the site, treatment, and greenhouse terms depending upon the presence of these effects in the data itself. Meta-analyses are run, and summary plots are produced. "],["write-configuration-files.html", "23.5 Write Configuration Files", " 23.5 Write Configuration Files 23.5.1 write.configs(model) writes out a configuration file for each model run ** writes 500 configuration files for a 500 member ensemble ** for n traits, writes 6 * n + 1 files for running default Sensitivity Analysis (number can be changed in the pecan settings file) "],["start-runs.html", "23.6 Start Runs", " 23.6 Start Runs 23.6.1 start.runs(model) This code starts the model runs using a model specific run function named start.runs.model. If the ecosystem model is running on a remote server, this module also takes care of all of the communication with the remote server and its run queue. Each of your subdirectories should now have a [run.id].out file in it. One instance of the model is run for each configuration file generated by the previous write configs module. "],["get-model-output.html", "23.7 Get Model Output", " 23.7 Get Model Output 23.7.1 get.model.output(model) This code first uses a model-specific model2netcdf.model function to convert the model output into a standard output format (MsTMIP). Then it extracts the data for requested variables specified in the settings file as settings$ensemble$variable, averages over the time-period specified as start.date and end.date, and stores the output in a file output.Rdata. The output.Rdata file contains two objects, sensitivity.output and ensemble.output, that is the model prediction for the parameter sets specified in sa.samples and ensemble.samples. In order to save bandwidth, if the model output is stored on a remote system PEcAn will perform these operations on the remote host and only return the output.Rdata object. "],["ensemble-analysis.html", "23.8 Ensemble Analysis", " 23.8 Ensemble Analysis 23.8.1 run.ensemble.analysis() This module makes some simple graphs of the ensemble output. Open ensemble.analysis.pdf to view the ensemble prediction as both a histogram and a boxplot. ensemble.ts.pdf provides a timeseries plot of the ensemble mean, meadian, and 95% CI "],["sensitivity-analysis-variance-decomposition.html", "23.9 Sensitivity Analysis, Variance Decomposition", " 23.9 Sensitivity Analysis, Variance Decomposition 23.9.1 run.sensitivity.analysis() This function processes the output of the previous module into sensitivity analysis plots, sensitivityanalysis.pdf, and a variance decomposition plot, variancedecomposition.pdf . In the sensitivity plots you will see the parameter values on the x-axis, the model output on the Y, with the dots being the model evaluations and the line being the spline fit. The variance decomposition plot is discussed more below. For your reference, the R list object, sensitivity.results, stored in sensitivity.results.Rdata, contains all the components of the variance decomposition table, as well as the the input parameter space and splines from the sensitivity analysis (reminder: the output parameter space from the sensitivity analysis was in outputs.R). The variance decomposition plot contains three columns, the coefficient of variation (normalized posterior variance), the elasticity (normalized sensitivity), and the partial standard deviation of each model parameter. This graph is sorted by the variable explaining the largest amount of variability in the model output (right hand column). From this graph identify the top-tier parameters that you would target for future constraint. "],["glossary.html", "23.10 Glossary", " 23.10 Glossary Inputs: data sets that are used, and file paths leading to them Parameters: e.g. info set in settings file Outputs: data sets that are dropped, and the file paths leading to them "],["installation-details.html", "24 Installation details", " 24 Installation details This chapter contains details about installing and maintaining the uncontainerized version of PEcAn on a virtual machine or a server. If you are running PEcAn inside of Docker, many of the particulars will be different and you should refer to the docker chapter instead of this one. "],["pecanvm.html", "24.1 PEcAn Virtual Machine", " 24.1 PEcAn Virtual Machine See also other VM related documentation sections: Maintaining your PEcAn VM Connecting to the VM via SSH Connecting to bety on the VM via SSh Using Amazon Web Services for a VM (AWS) Creating a Virtual Machine VM Desktop Conversion Install RStudio Desktop The PEcAn virtual machine consists of all of PEcAn pre-compiled within a Linux operating system and saved in a “virtual machine” (VM). Virtual machines allow for running consistent set-ups without worrying about differences between operating systems, library dependencies, compiling the code, etc. Install VirtualBox This is the software that runs the virtual machine. You can find the download link and instructions at http://www.virtualbox.org. NOTE: On Windows you may see a warning about Logo testing, it is okay to ignore the warning. Download the PEcAn VM You can find the download link at http://opensource.ncsa.illinois.edu/projects/artifacts.php?key=PECAN, under the “Files” header. Click the “.ova” file to begin the download. Note that the file is ~7 GB, so this download can take several minutes to hours depending on your connection speed. Also, the VM requires >4 GB of RAM to operate correctly. Please check current usage of RAM and shutdown processes as needed. Import the VM Once the download is complete, open VirtualBox. In the VirtualBox menus, go to “File” → “Import Appliance” and locate the downloaded “.ova” file. For Virtualbox version 5.x: In the Appliance Import Settings, make sure you select “Reinitialize the MAC address of all network cards” (picture below). This is not selected by default and can result in networking issues since multiple machines might claim to have the same network MAC Address. For Virtualbox versions starting with 6.0, there is a slightly different interface (see figure). Select “Generate new MAC addresses for all network adapters” from the MAC Address Policy: NOTE: If you experience network connection difficulties in the VM with this enabled, try re-importing the VM without this setting selected). Finally, click “Import” to build the Virtual Machine from its image. Launch PEcAn Double click the icon for the PEcAn VM. A terminal window will pop up showing the machine booting up which may take a minute. It is done booting when you get to the pecan login: prompt. You do not need to login as the VM behaves like a server that we will be accessing through you web browser. Feel free to minimize the VM window. If you do want to login to the VM, the credentials are as follows: username: carya, password: illinois (after the pecan tree, [Carya illinoinensis][pecan-wikipedia]). Open the PEcAn web interface With the VM running in the background, open any web browser on the same machine and navigate to localhost:6480/pecan/ to start the PEcAn workflow. (NOTE: The trailing backslash may be necessary depending on your browser) To ssh into the VM, open up a terminal on your machine and execute ssh -l carya -p 6422 localhost. Username and password are the same as when you log into the machine. "],["aws-setup.html", "24.2 AWS Setup", " 24.2 AWS Setup ***********Mirror of earlier section in installation section?********************* The following are Mike’s rough notes from a first attempt to port the PEcAn VM to the AWS. This was done on a Mac These notes are based on following the instructions here 24.2.1 Convert PEcAn VM AWS allows upload of files as VMDK but the default PEcAn VM is in OVA format If you haven’t done so already, download the PEcAn VM Split the OVA file into OVF and VMDK files tar xf <ovafile> 24.2.2 Set up an account on AWS After you have an account you need to set up a user and save your access key and secret key In my case I created a user named ‘carya’ Note: the key that ended up working had to be made at https://console.aws.amazon.com/iam/home#security_credential, not the link above. 24.2.3 Install EC2 command line tools wget http://s3.amazonaws.com/ec2-downloads/ec2-api-tools.zip sudo mkdir /usr/local/ec2 sudo unzip ec2-api-tools.zip -d /usr/local/ec2 If need be, download and install JDK export JAVA_HOME=$(/usr/libexec/java_home) export EC2_HOME=/usr/local/ec2/ec2-api-tools-<version> export PATH=$PATH:$EC2_HOME/bin Then set your user credentials as environment variables: export AWS_ACCESS_KEY=xxxxxxxxxxxxxx export AWS_SECRET_KEY=xxxxxxxxxxxxxxxxxxxxxx Note: you may want to add all the variables set in the above EXPORT commands above into your .bashrc or equivalent. 24.2.4 Create an AWS S3 ‘bucket’ to upload VM to Go to https://console.aws.amazon.com/s3 and click “Create Bucket” In my case I named the bucket ‘pecan’ 24.2.5 Upload In the code below, make sure to change the PEcAn version, the name of the bucket, and the name of the region. Make sure that the PEcAn version matches the one you downloaded. Also, you may want to choose a considerably larger instance type. The one chosen below is that corresponding to the AWS Free Tier ec2-import-instance PEcAn_1.2.6-disk1.vmdk --instance-type t2.micro --format VMDK --architecture x86_64 --platform Linux --bucket pecan --region us-east-1 --owner-akid $AWS_ACCESS_KEY --owner-sak $AWS_SECRET_KEY Make sure to note the ID of the image since you’ll need it to check the VM status. Once the image is uploaded it will take a while (typically about an hour) for Amazon to convert the image to one it can run. You can check on this progress by running ec2-describe-conversion-tasks <image.ID> 24.2.6 Configuring the VM On the EC2 management webpage, https://console.aws.amazon.com/ec2, if you select Instances on the left hand side (LHS) you should be able to see your new PEcAn image as an option under Launch Instance. Before launching, you will want to update the firewall to open up additional ports that PEcAn needs – specifically port 80 for the webpage. Port 22 (ssh/sftp) should be open by default. Under “Security Groups” select “Inbound” then “Edit” and then add “HTTP”. Select “Elastic IPs” on the LHS, and “Allocate New Address” in order to create a public IP for your VM. Next, select “Network Interfaces” on the LHS and then under Actions select “Associate Addresses” then choose the Elastic IP you just created. See also http://docs.aws.amazon.com/AmazonVPC/latest/GettingStartedGuide/GetStarted.html 24.2.7 Set up multiple instances (optional) For info on setting up multiple instances with load balancing see: http://docs.aws.amazon.com/ElasticLoadBalancing/latest/DeveloperGuide/gs-ec2VPC.html Select “Load Balancers” on the LHS, click on “Create Load Balancer”, follow Wizard keeping defaults. To be able to launch multiple VMs: Under “Instances” convert VM to an Image. When done, select Launch, enable multiple instances, and associate with the previous security group. Once running, go back to “Load Balancers” and add the instances to the load balancer. Each instance can be accessed individually by it’s own public IP, but external users should access the system more generally via the Load Balancers DNS. 24.2.8 Booting the VM Return to “Instances” using the menu on the LHS. To boot the VM select “Actions” then “Instance State” then “Start”. In the future, once you have the VM loaded and configured this last step is the only one you will need to repeat to turn your VM on and off. The menu provided should specify the Public IP where the VM has launched "],["shiny-setup.html", "24.3 Shiny Setup", " 24.3 Shiny Setup Installing and configuring Shiny for PEcAn authors - Alexey Shiklomanov - Rob Kooper NOTE: Instructions are only tested for CentOS 6.5 and Ubuntu 16.04 NOTE: Pretty much every step here requires root access. 24.3.1 Install the Shiny R package and Shiny server Follow the instructions on the Shiny download page for the operating system you are using. 24.3.2 Modify the shiny configuration file The Shiny configuration file is located in /etc/shiny-server/shiny-server.conf. Comment out the entire file and add the following, replacing <username> with your user name and <location> with the URL location you want for your app. This will allow you to run Shiny apps from your web browser at https://your.server.edu/shiny/your-location run as shiny; server { listen 3838; location /<location>/ { run as <username>; site_dir /path/to/your/shiny/app; log_dir /var/log/shiny-server; directory_index on; } } For example, my configuration on the old test-pecan looks like this. run as shiny; server { listen 3838; location /ashiklom/ { run as ashiklom; site_dir /home/ashiklom/fs-data/pecan/shiny/; log_dir /var/log/shiny-server; directory_index on; } } …and I can access my Shiny apps at, for instance, https://test-pecan.bu.edu/shiny/ashiklom/workflowPlots. You can add as many location <loc> { ... } fields as you would like. run as shiny; server { listen 3838; location /ashiklom/ { ... } location /bety/ { ... } } If you change the configuration, for example to add a new location, you will need to restart Shiny server. If you are setting up a new instance of Shiny, skip this step and continue with the guide, since there are a few more steps to get Shiny working. If there is an instance of Shiny already running, you can restart it with: ## On CentOS sudo service shiny-server stop sudo service shiny-server start ## On Ubuntu sudo systemctl stop shiny-server.service sudo systemctl start shiny-server.service 24.3.3 Set the Apache proxy Create a file with the following name, based on the version of the operating system you are using: Ubuntu 16.04 (pecan1, pecan2, test-pecan) – /etc/apache2/conf-available/shiny.conf CentOS 6.5 (psql-pecan) – /etc/httpd/conf.d/shiny.conf Into this file, add the following: ProxyPass /shiny/ http://localhost:3838/ ProxyPassReverse /shiny/ http://localhost:3838/ RedirectMatch permanent ^/shiny$ /shiny/ 24.3.3.1 Ubuntu only: Enable the new shiny configuration sudo a2enconf shiny This will create a symbolic link to the newly created shiny.conf file inside the /etc/apache2/conf-enabled directory. You can do ls -l /etc/apache2/conf-enabled to confirm that this worked. 24.3.4 Enable and start the shiny server, and restart apache 24.3.4.1 On CentOS sudo ln -s /opt/shiny-server/config/init.d/redhat/shiny-server /etc/init.d sudo service shiny-server stop sudo service shiny-server start sudo service httpd restart You can check that Shiny is running with service shiny-server status. 24.3.4.2 On Ubuntu Enable the Shiny server service. This will make sure Shiny runs automatically on startup. sudo systemctl enable shiny-server.service Restart Apache. sudo apachectl restart Start the Shiny server. sudo systemctl start shiny-server.service If there are problems, you can stop the shiny-server.service with… sudo systemctl stop shiny-server.service …and then use start again to restart it. 24.3.5 Troubleshooting Refer to the log files for shiny (/var/log/shiny-server.log) and httpd (on CentOS, /var/log/httpd/error-log; on Ubuntu, /var/log/apache2/error-log). 24.3.6 Further reading Shiny server configuration reference "],["thredds-setup.html", "24.4 Thredds Setup", " 24.4 Thredds Setup Installing and configuring Thredds for PEcAn authors - Rob Kooper NOTE: Instructions are only tested for Ubuntu 16.04 on the VM, if you have instructions for CENTOS/RedHat please update this documentation NOTE: Pretty much every step here requires root access. 24.4.1 Install the Tomcat 8 and Thredds webapp The Tomcat 8 server can be installed from the default Ubuntu repositories. The thredds webapp will be downloaded and installed from unidata. First step is to install Tomcat 8 and configure it. The flag -Dtds.content.root.path should point to the location of where the thredds folder is located. This needs to be writeable by the user for tomcat. -Djava.security.egd is a special flag to use a different random number generator for tomcat. The default would take to long to generate a random number. apt-get -y install tomcat8 openjdk-8-jdk echo JAVA_OPTS=\\"-Dtds.content.root.path=/home/carya \\${JAVA_OPTS}\\" >> /etc/default/tomcat8 echo JAVA_OPTS=\\"-Djava.security.egd=file:/dev/./urandom \\${JAVA_OPTS}\\" >> /etc/default/tomcat8 service tomcat8 restart Next is to install the webapp. mkdir /home/carya/thredds chmod 777 /home/carya/thredds wget -O /var/lib/tomcat8/webapps/thredds.war ftp://ftp.unidata.ucar.edu/pub/thredds/4.6/current/thredds.war Finally we configure Apache to prox the thredds server cat > /etc/apache2/conf-available/thredds.conf << EOF ProxyPass /thredds/ http://localhost:8080/thredds/ ProxyPassReverse /thredds/ http://localhost:8080/thredds/ RedirectMatch permanent ^/thredds$ /thredds/ EOF a2enmod proxy_http a2enconf thredds service apache2 reload 24.4.1.1 Customize the Thredds server To customize the thredds server for your installation edit the file in /home/carya/thredds/threddsConfig.xml. For example the following file is included in the VM. <?xml version="1.0" encoding="UTF-8"?> <threddsConfig> <!-- all options are commented out in standard install - meaning use default values --> <!-- see http://www.unidata.ucar.edu/software/thredds/current/tds/reference/ThreddsConfigXMLFile.html --> <serverInformation> <name>PEcAn</name> <logoUrl>/pecan/images/pecan_small.jpg</logoUrl> <logoAltText>PEcAn</logoAltText> <abstract>Scientific Data</abstract> <keywords>meteorology, atmosphere, climate, ocean, earth science</keywords> <contact> <name>Rob Kooper</name> <organization>NCSA</organization> <email>kooper@illinois.edu</email> <!--phone></phone--> </contact> <hostInstitution> <name>PEcAn</name> <webSite>http://www.pecanproject.org/</webSite> <logoUrl>/pecan/images/pecan_small.jpg</logoUrl> <logoAltText>PEcAn Project</logoAltText> </hostInstitution> </serverInformation> <!-- The <catalogRoot> element: For catalogs you don't want visible from the /thredds/catalog.xml chain of catalogs, you can use catalogRoot elements. Each catalog root config catalog is crawled and used in configuring the TDS. <catalogRoot>myExtraCatalog.xml</catalogRoot> <catalogRoot>myOtherExtraCatalog.xml</catalogRoot> --> <!-- * Setup for generated HTML pages. * * NOTE: URLs may be absolute or relative, relative URLs must be relative * to the webapp URL, i.e., http://server:port/thredds/. --> <htmlSetup> <!-- * CSS documents used in generated HTML pages. * The CSS document given in the "catalogCssUrl" element is used for all pages * that are HTML catalog views. The CSS document given in the "standardCssUrl" * element is used in all other generated HTML pages. * --> <standardCssUrl>tds.css</standardCssUrl> <catalogCssUrl>tdsCat.css</catalogCssUrl> <openDapCssUrl>tdsDap.css</openDapCssUrl> <!-- * The Google Analytics Tracking code you would like to use for the * webpages associated with THREDDS. This will not track WMS or DAP * requests for data, only browsing the catalog. --> <googleTrackingCode></googleTrackingCode> </htmlSetup> <!-- The <TdsUpdateConfig> element controls if and how the TDS checks for updates. The default is for the TDS to check for the current stable and development release versions, and to log that information in the TDS serverStartup.log file as INFO entries. <TdsUpdateConfig> <logVersionInfo>true</logVersionInfo> </TdsUpdateConfig> --> <!-- The <CORS> element controls Cross-Origin Resource Sharing (CORS). CORS is a way to allow a website (such as THREDDS) to open up access to resources to web pages and applications running on a different domain. One example would be allowing a web-application to use fonts from a separate host. For TDS, this can allow a javascript app running on a different site to access data on a THREDDS server. For more information see: https://en.wikipedia.org/wiki/Cross-origin_resource_sharing The elements below represent defaults. Only the <enabled> tag is required to enable CORS. The default allowed origin is '*', which allows sharing to any domain. <CORS> <enabled>false</enabled> <maxAge>1728000</maxAge> <allowedMethods>GET</allowedMethods> <allowedHeaders>Authorization</allowedHeaders> <allowedOrigin>*</allowedOrigin> </CORS> --> <!-- The <CatalogServices> element: - Services on local TDS served catalogs are always on. - Services on remote catalogs are set with the allowRemote element below. They are off by default (recommended). --> <CatalogServices> <allowRemote>false</allowRemote> </CatalogServices> <!-- Configuring the CDM (netcdf-java library) see http://www.unidata.ucar.edu/software/netcdf-java/reference/RuntimeLoading.html <nj22Config> <ioServiceProvider class="edu.univ.ny.stuff.FooFiles"/> <coordSysBuilder convention="foo" class="test.Foo"/> <coordTransBuilder name="atmos_ln_sigma_coordinates" type="vertical" class="my.stuff.atmosSigmaLog"/> <typedDatasetFactory datatype="Point" class="gov.noaa.obscure.file.Flabulate"/> </nj22Config> --> <!-- CDM uses the DiskCache directory to store temporary files, like uncompressed files. <DiskCache> <alwaysUse>false</alwaysUse> <scour>1 hour</scour> <maxSize>1 Gb</maxSize> </DiskCache> --> <!-- Caching open NetcdfFile objects. default is to allow 50 - 100 open files, cleanup every 11 minutes <NetcdfFileCache> <minFiles>50</minFiles> <maxFiles>100</maxFiles> <scour>11 min</scour> </NetcdfFileCache> --> <!-- The <HTTPFileCache> element: allow 10 - 20 open datasets, cleanup every 17 minutes used by HTTP Range requests. <HTTPFileCache> <minFiles>10</minFiles> <maxFiles>20</maxFiles> <scour>17 min</scour> </HTTPFileCache> --> <!-- Writing GRIB indexes. <GribIndexing> <setExtendIndex>false</setExtendIndex> <alwaysUseCache>false</alwaysUseCache> </GribIndexing> --> <!-- Persist joinNew aggregations to named directory. scour every 24 hours, delete stuff older than 90 days <AggregationCache> <scour>24 hours</scour> <maxAge>90 days</maxAge> <cachePathPolicy>NestedDirectory</cachePathPolicy> </AggregationCache> --> <!-- How to choose the template dataset for an aggregation. latest, random, or penultimate <Aggregation> <typicalDataset>penultimate</typicalDataset> </Aggregation> --> <!-- The Netcdf Subset Service is off by default. <NetcdfSubsetService> <allow>false</allow> <scour>10 min</scour> <maxAge>-1 min</maxAge> </NetcdfSubsetService> --> <!-- <Opendap> <ascLimit>50</ascLimit> <binLimit>500</binLimit> <serverVersion>opendap/3.7</serverVersion> </Opendap> --> <!-- The WCS Service is off by default. Also, off by default (and encouraged) is operating on a remote dataset. <WCS> <allow>false</allow> <allowRemote>false</allowRemote> <scour>15 min</scour> <maxAge>30 min</maxAge> </WCS> --> <!-- <WMS> <allow>false</allow> <allowRemote>false</allowRemote> <maxImageWidth>2048</maxImageWidth> <maxImageHeight>2048</maxImageHeight> </WMS> --> <!-- <NCISO> <ncmlAllow>false</ncmlAllow> <uddcAllow>false</uddcAllow> <isoAllow>false</isoAllow> </NCISO> --> <!-- CatalogGen service is off by default. <CatalogGen> <allow>false</allow> </CatalogGen> --> <!-- DLwriter service is off by default. As is support for operating on remote catalogs. <DLwriter> <allow>false</allow> <allowRemote>false</allowRemote> </DLwriter> --> <!-- DqcService is off by default. <DqcService> <allow>false</allow> </DqcService> --> <!-- Link to a Viewer application on the HTML page: <Viewer>my.package.MyViewer</Viewer> --> <!-- Add a DataSource - essentially an IOSP with access to Servlet request parameters <datasetSource>my.package.DatsetSourceImpl</datasetSource> --> <!-- set FeatureCollection logging <FeatureCollection> <RollingFileAppender> <MaxFileSize>1 MB</MaxFileSize> <MaxBackups>5</MaxBackups> <Level>INFO</Level> </RollingFileAppender> </FeatureCollection> --> <!-- Configure how the NetCDF-4 C library is discovered and used. libraryPath: The directory in which the native library is installed. libraryName: The name of the native library. This will be used to locate the proper .DLL, .SO, or .DYLIB file within the libraryPath directory. useForReading: By default, the native library is only used for writing NetCDF-4 files; a pure-Java layer is responsible for reading them. However, if this property is set to true, then it will be used for reading NetCDF-4 (and HDF5) files as well. --> <!-- <Netcdf4Clibrary> <libraryPath>/usr/local/lib</libraryPath> <libraryName>netcdf</libraryName> <useForReading>false</useForReading> </Netcdf4Clibrary> --> </threddsConfig> 24.4.2 Update the catalog For example to update the catalog with the latest data, run the following command from the root crontab. This cronjob will also synchronize the database with remote servers and dump your database (by default in /home/carya/dump) 0 * * * * /home/carya/pecan/scripts/cron.sh -o /home/carya/dump 24.4.3 Troubleshooting Refer to the log files for Tomcat (/var/log/tomcat8/*) and Thredds (/home/carya/thredds/logs). 24.4.4 Further reading Thredds reference "],["osinstall.html", "24.5 OS Specific Installations", " 24.5 OS Specific Installations Ubuntu CentOS OSX Install BETY THIS PAGE IS DEPRECATED Install Models Install Data 24.5.1 Ubuntu These are specific notes for installing PEcAn on Ubuntu (14.04) and will be referenced from the main installing PEcAn page. You will at least need to install the build environment and Postgres sections. If you want to access the database/PEcAn using a web browser you will need to install Apache. To access the database using the BETY interface, you will need to have Ruby installed. This document also contains information on how to install the Rstudio server edition as well as any other packages that can be helpful. 24.5.1.1 Install build environment sudo -s # point to latest R echo "deb http://cran.rstudio.com/bin/linux/ubuntu `lsb_release -s -c`/" > /etc/apt/sources.list.d/R.list apt-key adv --keyserver keyserver.ubuntu.com --recv-keys E084DAB9 # update package list apt-get -y update # install packages needed for PEcAn apt-get -y install build-essential gfortran git r-base-core r-base-dev jags liblapack-dev libnetcdf-dev netcdf-bin bc libcurl4-gnutls-dev curl udunits-bin libudunits2-dev libgmp-dev python-dev libgdal1-dev libproj-dev expect # install packages needed for ED2 apt-get -y install openmpi-bin libopenmpi-dev # install requirements for DALEC apt-get -y install libgsl0-dev # install packages for webserver apt-get -y install apache2 libapache2-mod-php5 php5 # install packages to compile docs apt-get -y install texinfo texlive-latex-base texlive-latex-extra texlive-fonts-recommended # install devtools echo 'install.packages("devtools")' | R --vanilla # done as root exit 24.5.1.2 Install Postgres Documentation: http://trac.osgeo.org/postgis/wiki/UsersWikiPostGIS21UbuntuPGSQL93Apt sudo -s # point to latest PostgreSQL echo "deb http://apt.postgresql.org/pub/repos/apt `lsb_release -s -c`-pgdg main" > /etc/apt/sources.list.d/pgdg.list wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - # update package list apt-get -y update # install packages for postgresql (using a newer version than default) apt-get -y install libdbd-pgsql postgresql postgresql-client libpq-dev postgresql-9.4-postgis-2.1 postgresql-9.4-postgis-2.1-scripts # install following if you want to run pecan through the web apt-get -y install php5-pgsql # enable bety user to login with trust by adding the following lines after # the ability of postgres user to login in /etc/postgresql/9.4/main/pg_hba.conf local   all             bety                                    trust host    all             bety            127.0.0.1/32            trust host    all             bety            ::1/128                 trust # Once done restart postgresql /etc/init.d/postgresql restart exit To install the BETYdb database .. 24.5.1.3 Apache Configuration PEcAn # become root sudo -s # get index page rm /var/www/html/index.html ln -s ${HOME}/pecan/documentation/index_vm.html /var/www/html/index.html # setup a redirect cat > /etc/apache2/conf-available/pecan.conf << EOF Alias /pecan ${HOME}/pecan/web <Directory ${HOME}/pecan/web> DirectoryIndex index.php Options +ExecCGI Require all granted </Directory> EOF a2enconf pecan /etc/init.d/apache2 restart # done as root exit 24.5.1.4 Apache Configuration BETY sudo -s # install all ruby related packages apt-get -y install ruby2.0 ruby2.0-dev libapache2-mod-passenger # link static content ln -s ${HOME}/bety/public /var/www/html/bety # setup a redirect cat > /etc/apache2/conf-available/bety.conf << EOF RailsEnv production RailsBaseURI /bety PassengerRuby /usr/bin/ruby2.0 <Directory /var/www/html/bety> Options +FollowSymLinks Require all granted </Directory> EOF a2enconf bety /etc/init.d/apache2 restart 24.5.1.5 Rstudio-server NOTE This will allow anybody to login to the machine through the rstudio interface and run any arbitrary code. The login used however is the same as the system login/password. wget http://download2.rstudio.org/rstudio-server-0.98.1103-amd64.deb # bceome root sudo -s # install required packages apt-get -y install libapparmor1 apparmor-utils libssl0.9.8 # install rstudio dpkg -i rstudio-server-* rm rstudio-server-* echo "www-address=127.0.0.1" >> /etc/rstudio/rserver.conf echo "r-libs-user=~/R/library" >> /etc/rstudio/rsession.conf rstudio-server restart # setup rstudio forwarding in apache a2enmod proxy_http cat > /etc/apache2/conf-available/rstudio.conf << EOF ProxyPass /rstudio/ http://localhost:8787/ ProxyPassReverse /rstudio/ http://localhost:8787/ RedirectMatch permanent ^/rstudio$ /rstudio/ EOF a2enconf rstudio /etc/init.d/apache2 restart # all done, exit root exit 24.5.1.6 Additional packages HDF5 Tools, netcdf, GDB and emacs sudo apt-get -y install hdf5-tools cdo nco netcdf-bin ncview gdb emacs ess nedit 24.5.2 CentOS/RedHat These are specific notes for installing PEcAn on CentOS (7) and will be referenced from the main installing PEcAn page. You will at least need to install the build environment and Postgres sections. If you want to access the database/PEcAn using a web browser you will need to install Apache. To access the database using the BETY interface, you will need to have Ruby installed. This document also contains information on how to install the Rstudio server edition as well as any other packages that can be helpful. 24.5.2.1 Install build environment sudo -s # install packages needed for PEcAn yum -y groupinstall 'Development Tools' yum -y install git netcdf-fortran-openmpi-devel R bc curl libxml2-devel openssl-devel ed udunits2 udunits2-devel netcdf netcdf-devel gmp-devel python-devel gdal-devel proj-devel proj-epsg expect # jags yum -y install http://download.opensuse.org/repositories/home:/cornell_vrdc/CentOS_7/x86_64/jags3-3.4.0-54.1.x86_64.rpm yum -y install http://download.opensuse.org/repositories/home:/cornell_vrdc/CentOS_7/x86_64/jags3-devel-3.4.0-54.1.x86_64.rpm # fix include folder for udunits2 ln -s /usr/include/udunits2/* /usr/include/ # install packages needed for ED2 yum -y install environment-modules openmpi-bin libopenmpi-dev # install requirements for DALEC yum -y install gsl-devel # install packages for webserver yum -y install httpd php systemctl enable httpd systemctl start httpd firewall-cmd --zone=public --add-port=80/tcp --permanent firewall-cmd --reload # install packages to compile docs #apt-get -y install texinfo texlive-latex-base texlive-latex-extra texlive-fonts-recommended # install devtools echo 'install.packages("devtools")' | R --vanilla # done as root exit echo "module load mpi" >> ~/.bashrc module load mpi 24.5.2.2 Install and configure PostgreSQL, udunits2, NetCDF sudo -s # point to latest PostgreSQL yum install -y epel-release yum -y install http://yum.postgresql.org/9.4/redhat/rhel-7-x86_64/pgdg-centos94-9.4-1.noarch.rpm # install packages for postgresql (using a newer version than default) yum -y install postgresql94-server postgresql94-contrib postgis2_94 postgresql94-devel udunits2 netcdf # install following if you want to run pecan through the web yum -y install php-pgsql # enable bety user to login with trust by adding the following lines after # the ability of postgres user to login in /var/lib/pgsql/9.4/data/pg_hba.conf local all bety trust host all bety 127.0.0.1/32 trust host all bety ::1/128 trust # Create database /usr/pgsql-9.4/bin/postgresql94-setup initdb # Enable postgres systemctl enable postgresql-9.4 systemctl start postgresql-9.4 exit 24.5.2.3 Apache Configuration PEcAn Install and Start Apache yum -y install httpd systemctl enable httpd systemctl start httpd # become root sudo -s # get index page rm /var/www/html/index.html ln -s /home/carya/pecan/documentation/index_vm.html /var/www/html/index.html # fix selinux context (does this need to be done after PEcAn is installed?) chcon -R -t httpd_sys_content_t /home/carya/pecan /home/carya/output # setup a redirect cat > /etc/httpd/conf.d/pecan.conf << EOF Alias /pecan /home/carya/pecan/web <Directory /home/carya/pecan/web> DirectoryIndex index.php Options +ExecCGI Require all granted </Directory> EOF a2enconf pecan /etc/init.d/apache2 restart # done as root exit 24.5.2.4 Apache Configuration BETY sudo -s # install all ruby related packages sudo curl --fail -sSLo /etc/yum.repos.d/passenger.repo https://oss-binaries.phusionpassenger.com/yum/definitions/el-passenger.repo yum -y install ruby ruby-devel mod_passenger # link static content ln -s /home/carya/bety/public /var/www/html/bety # fix GemFile echo 'gem "test-unit"' >> bety/Gemlile # fix selinux context (does this need to be done after bety is installed?) chcon -R -t httpd_sys_content_t /home/carya/bety # setup a redirect cat > /etc/httpd/conf.d/bety.conf << EOF RailsEnv production RailsBaseURI /bety PassengerRuby /usr/bin/ruby <Directory /var/www/html/bety> Options +FollowSymLinks Require all granted </Directory> EOF systemctl restart httpd 24.5.2.5 Rstudio-server NEED FIXING NOTE This will allow anybody to login to the machine through the rstudio interface and run any arbitrary code. The login used however is the same as the system login/password. wget http://download2.rstudio.org/rstudio-server-0.98.1103-amd64.deb # bceome root sudo -s # install required packages apt-get -y install libapparmor1 apparmor-utils libssl0.9.8 # install rstudio dpkg -i rstudio-server-* rm rstudio-server-* echo "www-address=127.0.0.1" >> /etc/rstudio/rserver.conf echo "r-libs-user=~/R/library" >> /etc/rstudio/rsession.conf rstudio-server restart # setup rstudio forwarding in apache a2enmod proxy_http cat > /etc/apache2/conf-available/rstudio.conf << EOF ProxyPass /rstudio/ http://localhost:8787/ ProxyPassReverse /rstudio/ http://localhost:8787/ RedirectMatch permanent ^/rstudio$ /rstudio/ EOF a2enconf rstudio /etc/init.d/apache2 restart # all done, exit root exit Alternative Rstudio instructions 24.5.2.5.1 Install and configure Rstudio-server Install RStudio Server by following the official documentation for your platform. Then, proceed with the following: add PATH=$PATH:/usr/sbin:/sbin to /etc/profile cat "PATH=$PATH:/usr/sbin:/sbin; export PATH" >> /etc/profile add rstudio.conf to /etc/httpd/conf.d/ wget https://gist.github.com/dlebauer/6921889/raw/d1e0f945228e5519afa6223d6f49d6e0617262bd/rstudio.conf sudo mv rstudio.conf /httpd/conf.d/ restart the Apache server: sudo httpd restart now you should be able to access http://<server>/rstudio 24.5.2.6 Install ruby-netcdf gem cd $RUBY_APPLICATION_HOME export $NETCDF_URL=http://www.gfd-dennou.org/arch/ruby/products/ruby-netcdf/release/ruby-netcdf-0.6.6.tar.gz export $NETCDF_DIR=/usr/local/netcdf gem install narray export NARRAY_DIR="$(ls $GEM_HOME/gems | grep 'narray-')" export NARRAY_PATH="$GEM_HOME/gems/$NARRAY_DIR" cd $MY_RUBY_HOME/bin wget $NETCDF_URL -O ruby-netcdf.tgz tar zxf ruby-netcdf.tgz && cd ruby-netcdf-0.6.6/ ruby -rubygems extconf.rb --with-narray-include=$NARRAY_PATH --with-netcdf-dir=/usr/local/netcdf-4.3.0 sed -i 's|rb/$|rb|' Makefile make make install cd ../ && sudo rm -rf ruby-netcdf* cd $RUBY_APPLICATION bundle install --without development 24.5.2.7 Additional packages NEED FIXING HDF5 Tools, netcdf, GDB and emacs sudo apt-get -y install hdf5-tools cdo nco netcdf-bin ncview gdb emacs ess nedit 24.5.3 Mac OSX These are specific notes for installing PEcAn on Mac OSX and will be referenced from the main installing PEcAn page. You will at least need to install the build environment and Postgres sections. If you want to access the database/PEcAn using a web browser you will need to install Apache. To access the database using the BETY interface, you will need to have Ruby installed. This document also contains information on how to install the Rstudio server edition as well as any other packages that can be helpful. 24.5.3.1 Install build environment # install R # download from http://cran.r-project.org/bin/macosx/ # install gfortran # download from http://cran.r-project.org/bin/macosx/tools/ # install OpenMPI curl -o openmpi-1.6.3.tar.gz http://www.open-mpi.org/software/ompi/v1.6/downloads/openmpi-1.6.3.tar.gz tar zxf openmpi-1.6.3.tar.gz cd openmpi-1.6.3 ./configure --prefix=/usr/local make all sudo make install cd .. # install szip curl -o szip-2.1-MacOSX-intel.tar.gz ftp://ftp.hdfgroup.org/lib-external/szip/2.1/bin/szip-2.1-MacOSX-intel.tar.gz tar zxf szip-2.1-MacOSX-intel.tar.gz sudo mv szip-2.1-MacOSX-intel /usr/local/szip # install HDF5 curl -o hdf5-1.8.11.tar.gz http://www.hdfgroup.org/ftp/HDF5/current/src/hdf5-1.8.11.tar.gz tar zxf hdf5-1.8.11.tar.gz cd hdf5-1.8.11 sed -i -e 's/-O3/-O0/g' config/gnu-flags ./configure --prefix=/usr/local/hdf5 --enable-fortran --enable-cxx --with-szlib=/usr/local/szip make # make check sudo make install # sudo make check-install cd .. 24.5.3.2 Install Postgres For those on a Mac I use the following app for postgresql which has postgis already installed (http://postgresapp.com/) To get postgis run the following commands in psql: ##### Enable PostGIS (includes raster) CREATE EXTENSION postgis; ##### Enable Topology CREATE EXTENSION postgis_topology; ##### fuzzy matching needed for Tiger CREATE EXTENSION fuzzystrmatch; ##### Enable US Tiger Geocoder CREATE EXTENSION postgis_tiger_geocoder; To check your postgis run the following command again in psql: SELECT PostGIS_full_version(); 24.5.3.3 Additional installs 24.5.3.3.1 Install JAGS Download JAGS from http://sourceforge.net/projects/mcmc-jags/files/JAGS/3.x/Mac%20OS%20X/JAGS-Mavericks-3.4.0.dmg/download 24.5.3.3.2 Install udunits Installing udunits-2 on MacOSX is done from source. download most recent version of Udunits here instructions for compiling from source curl -o udunits-2.1.24.tar.gz ftp://ftp.unidata.ucar.edu/pub/udunits/udunits-2.1.24.tar.gz tar zxf udunits-2.1.24.tar.gz cd udunits-2.1.24 ./configure make sudo make install 24.5.3.4 Apache Configuration Mac does not support pdo/postgresql by default. The easiest way to install is use: http://php-osx.liip.ch/ To enable pecan to run from your webserver. cat > /etc/apache2/others/pecan.conf << EOF Alias /pecan ${PWD}/pecan/web <Directory ${PWD}/pecan/web> DirectoryIndex index.php Options +All Require all granted </Directory> EOF 24.5.3.5 Ruby The default version of ruby should work. Or use JewelryBox. 24.5.3.6 Rstudio Server For the mac you can download Rstudio Desktop. 24.5.4 Installing BETY **************THIS PAGE IS DEPRECATED************* Official Instructions for BETY are maintained here: https://pecan.gitbook.io/betydb-documentation If you would like to install the Docker Version of BETY, please consult the PEcAn Docker section. 24.5.4.1 Install Database + Data note To install BETYdb without PEcAn, first download the load.bety.sh script # install database (code assumes password is bety) sudo -u postgres createuser -d -l -P -R -S bety sudo -u postgres createdb -O bety bety sudo -u postgres ./scripts/load.bety.sh -c YES -u YES -r 0 sudo -u postgres ./scripts/load.bety.sh -r 1 sudo -u postgres ./scripts/load.bety.sh -r 2 # configure for PEcAn web app (change password if needed) cp web/config.example.php web/config.php # add models to database (VM only) ./scripts/add.models.sh # add data to database ./scripts/add.data.sh # create outputs folder mkdir ~/output chmod 777 ~/output 24.5.4.2 Installing BETYdb Web Application There are two flavors of BETY, PHP and RUBY. The PHP version allows for a minimal interaction with the database while the RUBY version allows for full interaction with the database. 24.5.4.2.1 PHP version The php version comes with PEcAn and is already configured. 24.5.4.2.2 RUBY version The RUBY version requires a few extra packages to be installed first. Next we install the web app. # install bety cd git clone https://github.com/PecanProject/bety.git # install gems cd bety sudo gem2.0 install bundler bundle install --without development:test:javascript_testing:debug and configure BETY # create folders for upload folders mkdir paperclip/files paperclip/file_names chmod 777 paperclip/files paperclip/file_names # create folder for log files mkdir log touch log/production.log chmod 0666 log/production.log # fix configuration for vm cp config/additional_environment_vm.rb config/additional_environment.rb chmod go+w public/javascripts/cache/ # setup bety database configuration cat > config/database.yml << EOF production: adapter: postgis encoding: utf-8 reconnect: false database: bety pool: 5 username: bety password: bety EOF # setup login tokens cat > config/initializers/site_keys.rb << EOF REST_AUTH_SITE_KEY = 'thisisnotasecret' REST_AUTH_DIGEST_STRETCHES = 10 EOF 24.5.5 Install Models This page contains instructions on how to download and install ecosystem models that have been or are being coupled to PEcAn. These instructions have been tested on the PEcAn unbuntu VM. Commands may vary on other operating systems. Also, some model downloads require permissions before downloading, making them unavailable to the general public. Please contact the PEcAn team if you would like access to a model that is not already installed on the default PEcAn VM. BioCro CLM 4.5 DALEC ED2 FATES GDAY JULES LINKAGES LPJ-GUESS MAESPA SIPNET 24.5.5.1 BioCro # Version 0.951 echo 'devtools::install_github("ebimodeling/biocro@0.951")' | R --vanilla # Version 1.x echo 'devtools::install_github("ebimodeling/biocro-dev@26e0125b")' | R --vanilla BioCro Developers: request access from @dlebauer on GitHub 24.5.5.2 CLM 4.5 The version of CLM installed on PEcAn is the ORNL branch provided by Dan Ricciuto. This version includes Dan’s point-level CLM processing scripts Download the code (~300M compressed), input data (1.7GB compressed and expands to 14 GB), and a few misc inputs. mkdir models cd models wget ftp://nacp.ornl.gov/synthesis/2008/firenze/site/clm4_5_1_r085.tar.gz wget ftp://nacp.ornl.gov/synthesis/2008/firenze/site/clm/ccsm_inputdata.tar.gz tar -xvzf clm4_5* tar -xvzf ccsm_inputdata.tar.gz #Parameter file: mkdir /home/carya/models/ccsm_inputdata/lnd/clm2/paramdata cd /home/carya/models/ccsm_inputdata/lnd/clm2/paramdata wget ftp://nacp.ornl.gov/synthesis/2008/firenze/site/clm_params.c130821.nc wget ftp://nacp.ornl.gov/synthesis/2008/firenze/site/clm_params.c140423.nc #Domain file: cd /home/carya/models/ccsm_inputdata/share/domains/domain.clm/ wget ftp://nacp.ornl.gov/synthesis/2008/firenze/site/domain.lnd.1x1pt_US-UMB_navy.nc #Aggregated met data file: cd /home/carya/models/ccsm_inputdata/atm/datm7/CLM1PT_data/1x1pt_US-UMB wget ftp://nacp.ornl.gov/synthesis/2008/firenze/site/all_hourly.nc ## lightning database cd /home/carya/models/ccsm_inputdata/atm/datm7/NASA_LIS/ wget ftp://nacp.ornl.gov/synthesis/2008/firenze/site/clmforc.Li_2012_climo1995-2011.T62.lnfm_Total_c140423.nc ## surface data cd /home/carya/models/ccsm_inputdata/lnd/clm2/surfdata wget ftp://nacp.ornl.gov/synthesis/2008/firenze/site/clm/surfdata_360x720cru_simyr1850_c130927.nc cd /home/carya/models/ccsm_inputdata/lnd/clm2/surfdata_map wget ftp://nacp.ornl.gov/synthesis/2008/firenze/site/clm/surfdata_1x1pt_US-UMB_I1850CLM45CN_simyr1850.nc_new mv surfdata_1x1pt_US-UMB_I1850CLM45CN_simyr1850.nc_new surfdata_1x1pt_US-UMB_I1850CLM45CN_simyr1850.nc Required libraries sudo apt-get install mercurial csh tcsh subversion cmake sudo ln -s /usr/bin/make /usr/bin/gmake Compile and build default inputs cd ~/carya/models/clm4_5_1_r085/scripts python runCLM.py --site US-UMB ––compset I1850CLM45CN --mach ubuntu --ccsm_input /home/carya/models/ccsm_inputdata --tstep 1 --nopointdata --coldstart --cpl_bypass --clean_build 24.5.5.2.1 CLM Test Run You will see a new directory in scripts: US-UMB_I1850CLM45CN Enter this directory and run (you shouldn’t have to do this normally, but there is a bug with the python script and doing this ensures all files get to the right place): ./US-UMB_I1850CLM45CN.build Next you are ready to go to the run directory: /home/carya/models/clm4_5_1_r085/run/US-UMB_I1850CLM45CN/run Open to edit file: datm.streams.txt.CLM1PT.CLM_USRDAT and check file paths such that all paths start with /home/carya/models/ccsm_inputdata From this directory, launch the executable that resides in the bld directory: /home/carya/clm4_5_1_r085/run/US-UMB_I1850CLM45CN/bld/cesm.exe not sure this was the right location, but wherever the executable is You should begin to see output files that look like this: US-UMB_I1850CLM45CN.clm2.h0.yyyy-mm.nc (yyyy is year, mm is month) These are netcdf files containing monthly averages of lots of variables. The lnd_in file in the run directory can be modified to change the output file frequency and variables. 24.5.5.3 DALEC cd curl -o dalec_EnKF_pub.tgz http://isda.ncsa.illinois.edu/~kooper/EBI/dalec_EnKF_pub.tgz tar zxf dalec_EnKF_pub.tgz rm dalec_EnKF_pub.tgz cd dalec_EnKF_pub make dalec_EnKF make dalec_seqMH sudo cp dalec_EnKF dalec_seqMH /usr/local/bin 24.5.5.4 ED2 24.5.5.4.1 ED2.2 r46 (used in PEcAn manuscript) # ---------------------------------------------------------------------- # Get version r46 with a few patches for ubuntu cd curl -o ED.r46.tgz http://isda.ncsa.illinois.edu/~kooper/EBI/ED.r46.tgz tar zxf ED.r46.tgz rm ED.r46.tgz # ---------------------------------------------------------------------- # configure and compile ed cd ~/ED.r46/ED/build/bin curl -o include.mk.VM http://isda.ncsa.illinois.edu/~kooper/EBI/include.mk.opt.`uname -s` make OPT=VM sudo cp ../ed_2.1-VM /usr/local/bin/ed2.r46 Perform a test run using pre configured ED settings for ED2.2 r46 # ---------------------------------------------------------------------- # Create sample run cd mkdir testrun.ed.r46 cd testrun.ed.r46 curl -o ED2IN http://isda.ncsa.illinois.edu/~kooper/EBI/ED2IN.r46 sed -i -e "s#\\$HOME#$HOME#" ED2IN curl -o config.xml http://isda.ncsa.illinois.edu/~kooper/EBI/config.r46.xml # execute test run time ed2.r46 24.5.5.4.2 ED 2.2 r82 cd curl -o ED.r82.tgz http://isda.ncsa.illinois.edu/~kooper/EBI/ED.r82.tgz tar zxf ED.r82.tgz rm ED.r82.tgz cd ED.r82 curl -o ED.r82.patch http://isda.ncsa.illinois.edu/~kooper/EBI/ED.r82.patch patch -p1 < ED.r82.patch cd ED/build/bin curl -o include.mk.VM http://isda.ncsa.illinois.edu/~kooper/EBI/include.mk.opt.`uname -s` make OPT=VM sudo cp ../ed_2.1-VM /usr/local/bin/ed2.r82 Perform a test run using pre configured ED settings for ED2.2 r82 cd mkdir testrun.ed.r82 cd testrun.ed.r82 curl -o ED2IN http://isda.ncsa.illinois.edu/~kooper/EBI/ED2IN.r82 sed -i -e "s#\\$HOME#$HOME#" ED2IN curl -o config.xml http://isda.ncsa.illinois.edu/~kooper/EBI/config.r82.xml # execute test run time ed2.r82 24.5.5.4.3 ED 2.2 bleeding edge cd git clone https://github.com/EDmodel/ED2.git cd ED2/ED/build/bin curl -o include.mk.VM http://isda.ncsa.illinois.edu/~kooper/EBI/include.mk.opt.`uname -s` ./generate_deps.sh make OPT=VM sudo cp ../ed_2.1-VM /usr/local/bin/ed2.git 24.5.5.5 CLM-FATES Prerequisites sudo apt-get upgrade libnetcdf-dev sudo apt-get install subversion sudo apt-get install csh sudo apt-get install cmake sudo ln -s /usr/bin/make /usr/bin/gmake sudo rm /bin/sh sudo ln -s /bin/bash /bin/sh wget https://github.com/Unidata/netcdf-fortran/archive/v4.4.4.tar.gz cd netcdf-4.4.4 ./configure make sudo make install you might need to mess around with installing netcdf and netcdf-fortran to get a version FATES likes… Get code from Github (currently private) and go to cime/scripts directory git clone git@github.com:NGEET/ed-clm.git cd ed-clm/cime/scripts/ Within CLM-FATES, to be able to build an executable we need to create a reference run. We’ll also use this reference run to grab defaults from, so we’ll be registering the location of both the reference case (location of executable, scripts, etc) and the reference inputs with the PEcAn database. To begin, copy reference run script from pecan cp ~/pecan/models/fates/inst/create_1x1_ref_case.sh . Edit reference case script to set NETCDF_HOME, CROOT (reference run case), DIN_LOC_ROOT (reference run inputs). Also, make sure DIN_LOC_ROOT exists as FATES will not create it itself. Then run the script ./create_1x1_ref_case.sh Be aware that this script WILL ask you for your password on the NCAR server to download the reference case input data (the guest password may work, haven’t tried this). If it gives an error at the pio stage check the log, but the most likely error is it being unable to find a version of netcdf it likes. Once FATES is installed, set the whole reference case directory as the Model path (leave filename blank) and set the whole inputs directory as an Input with format clm_defaults. 24.5.5.6 GDAY Navigate to a directory you would like to store GDAY and run the following: git clone https://github.com/mdekauwe/GDAY.git cd GDAY cd src make gday is your executable. 24.5.5.7 JULES INSTALL STEPS: 1) Download JULES and FCM JULES: Model requires registration to download. Not to be put on PEcAn VM Getting Started documentation: https://jules.jchmr.org/content/getting-started Registration: http://jules-lsm.github.io/access_req/JULES_access.html FCM: https://github.com/metomi/fcm/ wget https://github.com/metomi/fcm/archive/2015.05.0.tar.gz edit makefile open etc/fcm-make/make.cfg set JULES_NETCDF = actual instead of dummy set path (e.g. /usr/) and lib_path /lib64 to netCDF libraries compile JULES cd etc/fcm-make/ {path.to.fcm}/fcm make -f etc/fcm-make/make.cfg --new UBUNTU VERSION: installed without having to add any perl libraries #perl stuff that I had to install on pecan2 not PEcAN VM sudo yum install perl-Digest-SHA sudo yum install perl-Time-modules sudo yum install cpan curl -L http://cpanmin.us | perl - --sudo App::cpanminus sudo cpanm Time/Piece.pm sudo cpanm IO/Uncompress/Gunzip.pm Executable is under build/bin/jules.exe Example rundir: examples/point_loobos 24.5.5.8 LINKAGES 24.5.5.8.1 R Installation # Public echo 'devtools::install_github("araiho/linkages_package")' | R --vanilla 24.5.5.8.2 FORTRAN VERSION #FORTRAN VERSION cd git clone https://github.com/araiho/Linkages.git cd Linkages gfortran -o linkages linkages.f sudo cp linkages /usr/local/bin/linkages.git 24.5.5.9 LPJ-GUESS Instructions to download source code Go to LPJ-GUESS website for instructions to access code. 24.5.5.10 MAESPA Navigate to a directory you would like store MAESPA and run the following: git clone https://bitbucket.org/remkoduursma/maespa.git cd maespa make maespa.out is your executable. Example input files can be found in the inpufiles directory. Executing measpa.out from within one of the example directories will produce output. MAESPA developers have also developed a wrapper package called Maeswrap. The usual R package installation method install.packages may present issues with downloading an unpacking a dependency package called rgl. Here are a couple of solutions: 24.5.5.10.1 Solution 1 ### From the Command Line sudo apt-get install r-cran-rgl then from within R install.packages("Maeswrap") 24.5.5.10.2 Solution 2 ### From the Command line sudo apt-get install libglu1-mesa-dev then from within R install.packages("Maeswrap") 24.5.5.11 SIPNET {inst-sipnet} cd curl -o sipnet_unk.tar.gz http://isda.ncsa.illinois.edu/~kooper/EBI/sipnet_unk.tar.gz tar zxf sipnet_unk.tar.gz rm sipnet_unk.tar.gz cd sipnet_unk make sudo cp sipnet /usr/local/bin/sipnet.runk 24.5.5.11.1 SIPNET testrun cd curl -o testrun.sipnet.tar.gz http://isda.ncsa.illinois.edu/~kooper/EBI/testrun.sipnet.tar.gz tar zxf testrun.sipnet.tar.gz rm testrun.sipnet.tar.gz cd testrun.sipnet sipnet.runk 24.5.6 Installing data for PEcAn PEcAn assumes some of the data to be installed on the machine. This page will describe how to install this data. 24.5.6.1 Site Information These are large-ish files that contain data used with ED2 and SIPNET rm -rf sites curl -o sites.tgz http://isda.ncsa.illinois.edu/~kooper/EBI/sites.tgz tar zxf sites.tgz sed -i -e "s#/home/kooper/Projects/EBI#${PWD}#" sites/*/ED_MET_DRIVER_HEADER rm sites.tgz rm -rf inputs curl -o inputs.tgz http://isda.ncsa.illinois.edu/~kooper/EBI/inputs.tgz tar zxf inputs.tgz rm inputs.tgz 24.5.6.2 FIA database FIA database is large and will add an extra 10GB to the installation. # download and install database curl -o fia5data.psql.gz http://isda.ncsa.illinois.edu/~kooper/EBI/fia5data.psql.gz dropdb --if-exists fia5data createdb -O bety fia5data gunzip fia5data.psql.gz psql -U bety -d fia5data < fia5data.psql rm fia5data.psql 24.5.6.3 Flux Camp Following will install the data for flux camp (as well as the demo script for PEcAn). cd curl -o plot.tgz http://isda.ncsa.illinois.edu/~kooper/EBI/plot.tgz tar zxf plot.tgz rm plot.tgz 24.5.6.4 Harvard for ED tutorial Add datasets and runs curl -o Santarem_Km83.zip http://isda.ncsa.illinois.edu/~kooper/EBI/Santarem_Km83.zip unzip -d sites Santarem_Km83.zip sed -i -e "s#/home/pecan#${HOME}#" sites/Santarem_Km83/ED_MET_DRIVER_HEADER rm Santarem_Km83.zip curl -o testrun.s83.zip http://isda.ncsa.illinois.edu/~kooper/EBI/testrun.s83.zip unzip testrun.s83.zip sed -i -e "s#/home/pecan#${HOME}#" testrun.s83/ED2IN rm testrun.s83.zip curl -o ed2ws.harvard.tgz http://isda.ncsa.illinois.edu/~kooper/EBI/ed2ws.harvard.tgz tar zxf ed2ws.harvard.tgz mkdir ed2ws.harvard/analy ed2ws.harvard/histo sed -i -e "s#/home/pecan#${HOME}#g" ed2ws.harvard/input_harvard/met_driver/HF_MET_HEADER ed2ws.harvard/ED2IN ed2ws.harvard/*.r rm ed2ws.harvard.tgz curl -o testrun.PDG.zip http://isda.ncsa.illinois.edu/~kooper/EBI/testrun.PDG.zip unzip testrun.PDG.zip sed -i -e "s#/home/pecan#${HOME}#" testrun.PDG/Met/PDG_MET_DRIVER testrun.PDG/Template/ED2IN sed -i -e 's#/n/scratch2/moorcroft_lab/kzhang/PDG/WFire_Pecan/##' testrun.PDG/Template/ED2IN rm testrun.PDG.zip curl -o create_met_driver.tar.gz http://isda.ncsa.illinois.edu/~kooper/EBI/create_met_driver.tar.gz tar zxf create_met_driver.tar.gz rm create_met_driver.tar.gz "],["docker-index.html", "25 Docker", " 25 Docker This chapter describes the PEcAn Docker container infrastructure. It contains the following sections: Introduction to Docker – Brief introduction to Docker and docker-compose Docker quickstart – Brief tutorial for setting up a Docker-based PEcAn instance PEcAn Docker Architecture – Detailed description of the containers comprising the PEcAn Docker-based infrastructure Dockerfiles for models – General guide for writing Dockerfiles for new models Building and modifying images Troubleshooting Docker Migrating from VM to Docker – Steps to migrate from running PEcAn on a VM to a docker. "],["docker-intro.html", "25.1 Introduction to Docker?", " 25.1 Introduction to Docker? What is Docker Working with Docker docker-compose 25.1.1 What is Docker? For a quick and accessible introduction to Docker, we suggest this YouTube video: Learn Docker in 12 Minutes. For more comprehensive Docker documentation, we refer you to the Docker documentation website. For a useful analogy for Docker containerization, we refer you to the webcomic xkcd. Docker is a technology for encapsulating software in “containers”, somewhat similarly to virtual machines. Like virtual machines, Docker containers facilitate software distribution by bundling the software with all of its dependencies in a single location. Unlike virtual machines, Docker containers are meant to only run a single service or process and are build on top of existing services provided by the host OS (such as disk access, networking, memory management etc.). In Docker, an image refers to a binary snapshot of a piece of software and all of its dependencies. A container refers to a running instance of a particular image. A good rule of thumb is that each container should be responsible for no more than one running process. A software stack refers to a collection of containers, each responsible for its own process, working together to power a particular application. Docker makes it easy to run multiple software stacks at the same time in parallel on the same machine. Stacks can be given a unique name, which is passed along as a prefix to all their containers. Inside these stacks, containers can communicate using generic names not prefixed with the stack name, making it easy to deploy multiple stacks with the same internal configuration. Containers within the same stack communicate with each other via a common network. Like virtual machines or system processes, Docker stacks can also be instructed to open specific ports to facilitate communication with the host and other machines. The PEcAn database BETY provides an instructive case-study. BETY is comprised of two core processes – a PostgreSQL database, and a web-based front-end to that database (Apache web server with Ruby on Rails). Running BETY as a “Dockerized” application therefore involves two containers – one for the PostgreSQL database, and one for the web server. We could build these containers ourselves by starting from a container with nothing but the essentials of a particular operating system, but we can save some time and effort by starting with an existing image for PostgreSQL from Docker Hub. When starting a Dockerized BETY, we start the PostgreSQL container first, then start the BETY container telling it how to communicate with the PostgreSQL container. To upgrade an existing BETY instance, we stop the BETY container, download the latest version, tell it to upgrade the database, and re-start the BETY container. There is no need to install new dependencies for BETY since they are all shipped as part of the container. The PEcAn Docker architecture is designed to facilitate installation and maintenance on a variety of systems by eliminating the need to install and maintain complex system dependencies (such as PostgreSQL, Apache web server, and Shiny server). Furthermore, using separate Docker containers for each ecosystem model helps avoid clashes between different software version requirements of different models (e.g. some models require GCC <5.0, while others may require GCC >=5.0). The full PEcAn Docker stack is described in more detail in the next section. 25.1.2 Working with Docker To run an image, you can use the Docker command line interface. For example, the following runs a PostgreSQL image based on the pre-existing PostGIS image by mdillon: docker run \\ --detach \\ --rm \\ --name postgresql \\ --network pecan \\ --publish 9876:5432 \\ --volume ${PWD}/postgres:/var/lib/postgresql/data \\ mdillon/postgis:9.6-alpine This will start the PostgreSQL+PostGIS container. The following options were used: --detach makes the container run in the background. --rm removes the container when it is finished (make sure to use the volume below). --name the name of the container, also the hostname of the container which can be used by other docker containers in the same network inside docker. --network pecan the network that the container should be running in, this leverages of network isolation in docker and allows this container to be connected to by others using the postgresql hostname. --publish exposes the port to the outside world, this is like ssh, and maps port 9876 to port 5432 in the docker container --volume maps a folder on your local machine to the machine in the container. This allows you to save data on your local machine. mdillon/postgis:9.6-alpine is the actual image that will be run, in this case it comes from the group/person mdillon, the container is postgis and the version 9.6-alpine (version 9.6 build on alpine linux). Other options that might be used: --tty allocate a pseudo-TTY to send stdout and stderr back to the console. --interactive keeps stdin open so the user can interact with the application running. --env sets environment variables, these are often used to change the behavior of the docker container. To see a list of all running containers you can use the following command: docker ps To see the log files of this container you use the following command (you can either use their name or id as returned by docker ps). The -f flag will follow the stdout/stderr from the container, use Ctrl-C to stop following the stdout/stderr. docker logs -f postgresql To stop a running container use: docker stop postgresql Containers that are running in the foreground (without the --detach) can be stopped by pressing Ctrl-C. Any containers running in the background (with --detach) will continue running until the machine is restarted or the container is stopped using docker stop. 25.1.3 docker-compose For a quick introduction to docker-compose, we recommend the following YouTube video: Docker Compose in 12 Minutes. The complete docker-compose references can be found on the Docker documentation website. docker-compose provides a convenient way to configure and run a multi-container Docker stack. Basically, a docker-compose setup consists of a list of containers and their configuration parameters, which are then internally converted into a bunch of docker commands. To configure BETY as described above, we can use a docker-compose.yml file like the following: version: "3" services: postgres: image: mdillon/postgis:9.5 bety: image: pecan/bety depends_on: - postgres This simple file allows us to bring up a full BETY application with both database and BETY application. The BETY app will not be brought up until the database container has started. You can now start this application by changing into the same directory as the docker-compose.yml file (cd /path/to/file) and then running: docker-compose up This will start the application, and you will see the log files for the 2 different containers. "],["docker-quickstart.html", "25.2 Quick-start docker install", " 25.2 Quick-start docker install git clone git@github.com/pecanproject/pecan cd pecan # start database docker-compose -p pecan up -d postgres # add example data (first time only) docker-compose run --rm bety initialize docker run -ti --rm --network pecan_pecan --volume pecan_pecan:/data --env FQDN=docker pecan/data:develop # start PEcAn docker-compose -p pecan up -d # run a model curl -v -X POST \\ -F 'hostname=docker' \\ -F 'modelid=1000000014' \\ -F 'sitegroupid=1' \\ -F 'siteid=772' \\ -F 'sitename=Niwot Ridge Forest/LTER NWT1 (US-NR1)' \\ -F 'pft[]=temperate.coniferous' \\ -F 'start=2004/01/01' \\ -F 'end=2004/12/31' \\ -F 'input_met=5000000005' \\ -F 'email=' \\ -F 'notes=' \\ 'http://pecan.localhost/pecan/04-runpecan.php' "],["the-pecan-docker-install-process-in-detail.html", "25.3 The PEcAn docker install process in detail", " 25.3 The PEcAn docker install process in detail 25.3.1 Configure docker-compose This section will let you download some configuration files. The documentation provides links to the latest released version (master branch in GitHub) or the develop version that we are working on (develop branch in GitHub) which will become the next release. If you cloned the PEcAn GitHub repository you can use git checkout <branch> to switch branches. The PEcAn Docker stack is configured using a docker-compose.yml file. You can download just this file directly from GitHub latest or develop. You can also find this file in the root of cloned PEcAn GitHub repository. There is no need to edit the docker-compose.yml file. You can use either the .env file to change some of the settings, or the docker-compose.override.yml file to modify the docker-compose.yml file. This makes it easier for you to get an updated version of the docker-compose.yml file and not lose any changes you have made to it. Some of the settings in the docker-compose.yml can be set using a .env file. You can download either the latest or the develop version. If you have cloned the GitHub repository it is also located in the docker folder. This file should be called .env and be placed in the same folder as your docker-compose.yml file. This file will allow you to set which version of PEcAn or BETY to use. See the comments in this file to control the settings. Option you might want to set are: PECAN_VERSION : The docker images to use for PEcAn. The default is latest which is the latest released version of PEcAn. Setting this to develop will result in using the version of PEcAn which will become the next release. PECAN_FQDN : Is the name of the server where PEcAn is running. This is what is used to register all files generated by this version of PEcAn (see also TRAEFIK_HOST). PECAN_NAME : A short name of this PEcAn server that is shown in the pull down menu and might be easier to recognize. BETY_VERSION : This controls the version of BETY. The default is latest which is the latest released version of BETY. Setting this to develop will result in using the version of BETY which will become the next release. TRAEFIK_HOST : Should be the FQDN of the server, this is needed when generating a SSL certificate. For SSL certificates you will need to set TRAEFIK_ACME_ENABLE as well as TRAEFIK_ACME_EMAIL. TRAEFIK_IPFILTER : is used to limit access to certain resources, such as RabbitMQ and the Traefik dashboard. A final file, which is optional, is a docker-compose.override.yml. You can download a version for the latest and develop versions. If you have cloned the GitHub repository it is located in the docker folder. Use this file as an example of what you can do, only copy the pieces over that you really need. This will allow you to make changes to the docker-compose file for your local installation. You can use this to add additional containers to your stack, change the path where docker stores the data for the containers, or you can use this to open up the postgresql port. version: "3" services: # expose database to localhost for ease of access postgres: ports: - 5432:5432 Once you have the docker-compose.yml file as well as the optional .env and docker-compose.override.yml in a folder you can start the PEcAn stack. The following instructions assume you are in the same directory as the file (if not, cd into it). In the rest of this section we will use a few arguments for the docker-compose application. The location of these arguments are important. The general syntax of docker-compose is docker-compose <ARGUMENTS FOR DOCKER COMPOSE> <COMMAND> <ARGUMENTS FOR COMMAND> [SERVICES]. More generally, docker-compose options are very sensitive to their location relative to other commands in the same line – that is, docker-compose -f /my/docker-compose.yml -p pecan up -d postgres is not the same as docker-compose -d postgres -p pecan up -f /my/docker-compose.yml. If expected ever don’t seem to be working, check that the arguments are in the right order.) -f <filename> : ARGUMENTS FOR DOCKER COMPOSE : Allows you to specify a docker-compose.yml file explicitly. You can use this argument multiple times. Default is to use the docker-compose.yml and docker-compose.override.yml in your current folder. -p <projectname> : ARGUMENTS FOR DOCKER COMPOSE : Project name, all volumes, networks, and containers will be prefixed with this argument. The default value is to use the current folder name. -d : ARGUMENTS FOR up COMMAND : Will start all the containers in the background and return back to the command shell. If no services as added to the docker-compose command all services possible will be started. 25.3.2 Initialize PEcAn (first time only) Before you can start to use PEcAn for the first time you will need to initialize the database (and optionally add some data). The following two sections will first initialize the database and secondly add some data to the system. 25.3.2.1 Initialize the PEcAn database The commands described in this section will set up the PEcAn database (BETY) and pre-load it with some common “default” data. docker-compose -p pecan up -d postgres # If you have a custom docker-compose file: # docker-compose -f /path/to/my-docker-compose.yml -p pecan up -d postgres The breakdown of this command is as follows: -p pecan – This tells docker-compose to do all of this as part of a “project” -p we’ll call pecan. By default, the project name is set to the name of the current working directory. The project name will be used as a prefix to all containers started by this docker-compose instance (so, if we have a service called postgres, this will create a container called pecan_postgres). up -d – up is a command that initializes the containers. Initialization involves downloading and building the target containers and any containers they depend on, and then running them. Normally, this happens in the foreground, printing logs directly to stderr/stdout (meaning you would have to interrupt it with Ctrl-C), but the -d flag forces this to happen more quietly and in the background. postgres – This indicates that we only want to initialize the service called postgres (and its dependencies). If we omitted this, docker-compose would initialize all containers in the stack. The end result of this command is to initialize a “blank” PostGIS container that will run in the background. This container is not connected to any data (yet), and is basically analogous to just installing and starting PostgreSQL to your system. As a side effect, the above command will also create blank data “volumes” and a “network” that containers will use to communicate with each other. Because our project is called pecan and docker-compose.yml describes a network called pecan, the resulting network is called pecan_pecan. This is relevant to the following commands, which will actually initialize and populate the BETY database. Assuming the above has run successfully, next run the following: docker run --rm --network pecan_pecan pecan/db The breakdown of this command is as follows: {#docker-run-init} docker run – This says we will be running a container. --rm – This automatically removes the resulting container once the specified command exits, as well as any volumes associated with the container. This is useful as a general “clean-up” flag for one-off commands (like this one) to make sure you don’t leave any “zombie” containers or volumes around at the end. --network pecan_pecan – Thsi will start the container in the same network space as the posgres container, allowing it to push data into the database. pecan/db – This is the name of the container, this holds a copy of the database used to initialize the postgresql database. Note that this command may throw a bunch of errors related to functions and/or operators already existing. This is normal – it just means that the PostGIS extension to PostgreSQL is already installed. The important thing is that you see output near the end like: ---------------------------------------------------------------------- Safety checks ---------------------------------------------------------------------- ---------------------------------------------------------------------- Making sure user 'bety' exists. If you do not see this output, you can look at the troubleshooting section at the end of this section for some troubleshooting tips, as well as some solutions to common problems. Once the command has finished successfully, proceed with the next step which will load some initial data into the database and place the data in the docker volumes. 25.3.2.2 Add first user to PEcAn database You can add an initial user to the BETY database, for example the following commands will add the guestuser account as well as the demo carya account: # guest user docker-compose run --rm bety user guestuser guestuser "Guest User" guestuser@example.com 4 4 # example user docker-compose run --rm bety user carya illinois "Carya Demo User" carya@example.com 1 1 25.3.2.3 Add example data (first time only) The following command will add some initial data to the PEcAn stack and register the data with the database. docker run -ti --rm --network pecan_pecan --volume pecan_pecan:/data --env FQDN=docker pecan/data:develop The breakdown of this command is as follows: docker run – This says we will be running a specific command inside the target Docker container. See docker run --help and the Docker run reference for more information. -ti – This is actually two flags, -t to allocate a pseudo-tty and -i to keep STDIN open even if detached. -t is necessary to ensure lower-level script commands run correctly. -i makes sure that the command output (stdin) is displayed. --rm – This automatically removes the resulting container once the specified command exits, as well as any volumes associated with the container. This is useful as a general “clean-up” flag for one-off commands (like this one) to make sure you don’t leave any “zombie” containers or volumes around at the end. --network pecan_pecan – This indicates that the container will use the existing pecan_pecan network. This network is what ensures communication between the postgres container (which, recall, is just a PostGIS installation with some data) and the “volumes” where the actual data are persistently stored. pecan/data:develop – This is the name of the image in which to run the specified command, in the form repository/image:version. This is interpreted as follows: First, it sees if there are any images called pecan/data:develop available on your local machine. If there are, it uses that one. If that image version is not available locally, it will next try to find the image online. By default, it searches Docker Hub, such that pecan/data gets expanded to the container at https://hub.docker.com/r/pecan/data. For custom repositories, a full name can be given, such as hub.ncsa.illinois.edu/pecan/data:latest. If :version is omitted, Docker assumes :latest. NOTE that while online containers should have a :latest version, not all of them do, and if a :latest version does not exist, Docker will be unable to find the image and will throw an error. Everything after the image name (here, pecan/data:develop) is interpreted as an argument to the image’s specified entrypoint. --volume pecan_pecan:/data – This mounts the data from the subsequent container (pecan/data:develop) onto the current project volume, called pecan_pecan (as with the network, the project name pecan is the prefix, and the volume name also happens to be pecan as specified in the docker-compose.yml file). --env FQDN=docker – the Fully Qualified Domain Name, this is the same value as specified in the .env file (for the web, monitor and executor containers). This will link the data files to the name in the machines table in BETY. pecan/data:develop – As above, this is the target image to run. Since there is no argument after the image name, this command will run the default command (CMD) specified for this docker container. In this case, it is the docker/add_data.sh script from the PEcAn repository. Under the hood, this container runs the docker/add-data.sh script, which copies a bunch of input files and registers them with the PEcAn database. Successful execution of this command should take some time because it involves copying reasonably large amounts of data and performing a number of database operations. 25.3.2.4 Start PEcAn If you already completed the above steps, you can start the full stack by just running the following: docker-compose -p pecan up -d This will build and start all containers required to run PEcAn. With the -d flag, this will run all of these containers quietly in the background, and show a nice architecture diagram with the name and status of each container while they are starting. Once this is done you have a working instance of PEcAn. If all of the containers started successfully, you should be able to access the various components from a browser via the following URLs (if you run these commands on a remote machine replace localhost with the actual hostname). PEcAn web interface (running models) – http://pecan.localhost/pecan/ (NOTE: The trailing backslash is necessary.) PEcAn documentation and home page – http://pecan.localhost/ BETY web interface – http://pecan.localhost/bety/ Monitor, service that monitors models and shows all models that are online as well as how many instances are online and the number of jobs waiting. The output is in JSON – http://pecan.localhost/monitor/ 25.3.2.5 Start model runs using curl To test PEcAn you can use the following curl statement, or use the webpage to submit a request (if you run these commands on a remote machine replace localhost with the actual hostname): curl -v -X POST \\ -F 'hostname=docker' \\ -F 'modelid=5000000002' \\ -F 'sitegroupid=1' \\ -F 'siteid=772' \\ -F 'sitename=Niwot Ridge Forest/LTER NWT1 (US-NR1)' \\ -F 'pft[]=temperate.coniferous' \\ -F 'start=2004/01/01' \\ -F 'end=2004/12/31' \\ -F 'input_met=5000000005' \\ -F 'email=' \\ -F 'notes=' \\ 'http://pecan.localhost/pecan/04-runpecan.php' This should return some text with in there Location: this is shows the workflow id, you can prepend http://pecan.localhost/pecan/ to the front of this, for example: http://pecan.localhost/pecan/05-running.php?workflowid=99000000001. Here you will be able to see the progress of the workflow. To see what is happening behind the scenes you can use look at the log file of the specific docker containers, once of interest are pecan_executor_1 this is the container that will execute a single workflow and pecan_sipnet_1 which executes the sipnet mode. To see the logs you use docker logs pecan_executor_1 Following is an example output: 2018-06-13 15:50:37,903 [MainThread ] INFO : pika.adapters.base_connection - Connecting to 172.18.0.2:5672 2018-06-13 15:50:37,924 [MainThread ] INFO : pika.adapters.blocking_connection - Created channel=1 2018-06-13 15:50:37,941 [MainThread ] INFO : root - [*] Waiting for messages. To exit press CTRL+C 2018-06-13 19:44:49,523 [MainThread ] INFO : root - b'{"folder": "/data/workflows/PEcAn_99000000001", "workflowid": "99000000001"}' 2018-06-13 19:44:49,524 [MainThread ] INFO : root - Starting job in /data/workflows/PEcAn_99000000001. 2018-06-13 19:45:15,555 [MainThread ] INFO : root - Finished running job. This shows that the executor connects to RabbitMQ, waits for messages. Once it picks up a message it will print the message, and execute the workflow in the folder passed in with the message. Once the workflow (including any model executions) is finished it will print Finished. The log file for pecan_sipnet_1 is very similar, in this case it runs the job.sh in the run folder. To run multiple executors in parallel you can duplicate the executor section in the docker-compose file and just rename it from executor to executor1 and executor2 for example. The same can be done for the models. To make this easier it helps to deploy the containers using Kubernetes allowing to easily scale up and down the containers. 25.3.3 Troubleshooting When initializing the database, you will know you have encountered more serious errors if the command exits or hangs with output resembling the following: LINE 1: SELECT count(*) FROM formats WHERE ... ^ Error: Relation `formats` does not exist If the above command fails, you can try to fix things interactively by first opening a shell inside the container… docker run -ti --rm --network pecan_pecan pecan/bety:latest /bin/bash …and then running the following commands, which emulate the functionality of the entrypoint.sh with the initialize argument. # Create the bety role in the postgresql database psql -h postgres -p 5432 -U postgres -c "CREATE ROLE bety WITH LOGIN CREATEDB NOSUPERUSER NOCREATEROLE PASSWORD 'bety'" # Initialize the bety database itself, and set to be owned by role bety psql -h postgres -p 5432 -U postgres -c "CREATE DATABASE bety WITH OWNER bety" # If either of these fail with a "role/database bety already exists", # that's fine. You can safely proceed to the next command. # Load the actual bety database tables and values ./script/load.bety.sh -a "postgres" -d "bety" -p "-h postgres -p 5432" -o bety -c -u -g -m ${LOCAL_SERVER} -r 0 -w https://ebi-forecast.igb.illinois.edu/pecan/dump/all/bety.tar.gz "],["pecan-docker.html", "25.4 PEcAn Docker Architecture", " 25.4 PEcAn Docker Architecture Overview PEcAn’s docker-compose Top-level structure traefik portainer minio thredds postgres rabbitmq bety docs web executor monitor Model-specific containers 25.4.1 Overview The PEcAn docker architecture consists of many containers (see figure below) that will communicate with each other. The goal of this architecture is to easily expand the PEcAn system by deploying new model containers and registering them with PEcAn. Once this is done the user can now use these new models in their work. The PEcAn framework will setup the configurations for the models, and send a message to the model containers to start execution. Once the execution is finished the PEcAn framework will continue. This is exactly as if the model is running on a HPC machine. Models can be executed in parallel by launching multiple model containers. As can be seen in the figure the architecture leverages of two standard containers (in orange). The first container is postgresql with postgis (mdillon/postgis) which is used to store the database used by both BETY and PEcAn. The second containers is a messagebus, more specifically RabbitMQ (rabbitmq). The BETY app container (pecan/bety) is the front end to the BETY database and is connected to the postgresql container. A http server can be put in front of this container for SSL termination as well to allow for load balancing (by using multiple BETY app containers). The PEcAn framework containers consist of multiple unique ways to interact with the PEcAn system (none of these containers will have any models installed): PEcAn shiny hosts the shiny applications developed and will interact with the database to get all information necessary to display PEcAn rstudio is a rstudio environment with the PEcAn libraries preloaded. This allows for prototyping of new algorithms that can be used as part of the PEcAn framework later. PEcAn web allows the user to create a new PEcAn workflow. The workflow is stored in the database, and the models are executed by the model containers. PEcAn cli will allow the user to give a pecan.xml file that will be executed by the PEcAn framework. The workflow created from the XML file is stored in the database, and the models are executed by the model containers. The model containers contain the actual models that are executed as well as small wrappers to make them work in the PEcAn framework. The containers will run the model based on the parameters received from the message bus and convert the outputs back to the standard PEcAn output format. Once the container is finished processing a message it will immediatly get the next message and start processing it. 25.4.2 PEcAn’s docker-compose The PEcAn Docker architecture is described in full by the PEcAn docker-compose.yml file. For full docker-compose syntax, see the official documentation. This section describes the top-level structure and each of the services, which are as follows: traefik portainer minio thredds postgres rabbitmq bety docs web executor monitor Model-specific services For reference, the complete docker-compose file is as follows: version: '3.2' services: traefik: image: traefik:v2.9 command: - --log.level=INFO - --api=true - --api.dashboard=true - --entrypoints.web.address=:80 - --providers.docker=true - --providers.docker.endpoint=unix:///var/run/docker.sock - --providers.docker.exposedbydefault=false - --providers.docker.watch=true restart: unless-stopped networks: pecan security_opt: no-new-privileges:true ports: ${TRAEFIK_HTTP_PORT-80}:80 volumes: - traefik:/config - /var/run/docker.sock:/var/run/docker.sock:ro labels: - traefik.enable=true - traefik.http.routers.traefik.entrypoints=web - traefik.http.routers.traefik.rule=Host(`traefik.pecan.localhost`) - traefik.http.routers.traefik.service=api@internal rabbitmq: image: rabbitmq:3.8-management restart: unless-stopped networks: pecan environment: - RABBITMQ_DEFAULT_USER=${RABBITMQ_DEFAULT_USER:-guest} - RABBITMQ_DEFAULT_PASS=${RABBITMQ_DEFAULT_PASS:-guest} labels: - traefik.enable=true - traefik.http.services.rabbitmq.loadbalancer.server.port=15672 - traefik.http.routers.rabbitmq.entrypoints=web - traefik.http.routers.rabbitmq.rule=Host(`rabbitmq.pecan.localhost`) volumes: rabbitmq:/var/lib/rabbitmq postgres: image: mdillon/postgis:9.5 restart: unless-stopped networks: pecan volumes: postgres:/var/lib/postgresql/data bety: image: pecan/bety:${BETY_VERSION:-latest} restart: unless-stopped networks: pecan environment: - UNICORN_WORKER_PROCESSES=1 - SECRET_KEY_BASE=${BETY_SECRET_KEY:-notasecret} - RAILS_RELATIVE_URL_ROOT=/bety - LOCAL_SERVER=${BETY_LOCAL_SERVER:-99} depends_on: postgres labels: - traefik.enable=true - traefik.http.services.bety.loadbalancer.server.port=8000 - traefik.http.routers.bety.rule=Host(`${TRAEFIK_HOST:-pecan.localhost}`) && PathPrefix(`/bety/`) rstudio: image: pecan/base:${PECAN_VERSION:-latest} command: /work/rstudio.sh restart: unless-stopped networks: pecan depends_on: - rabbitmq - postgres environment: - KEEP_ENV=RABBITMQ_URI RABBITMQ_PREFIX RABBITMQ_PORT FQDN NAME - RABBITMQ_URI=${RABBITMQ_URI:-amqp://guest:guest@rabbitmq/%2F} - RABBITMQ_PREFIX=/ - RABBITMQ_PORT=15672 - FQDN=${PECAN_FQDN:-docker} - NAME=${PECAN_NAME:-docker} - USER=${PECAN_RSTUDIO_USER:-carya} - PASSWORD=${PECAN_RSTUDIO_PASS:-illinois} - USERID=${UID:-1001} - GROUPID=${GID:-1001} volumes: - pecan:/data - rstudio:/home labels: - traefik.enable=true - traefik.http.routers.rstudio.rule=Host(`${TRAEFIK_HOST:-pecan.localhost}`) && PathPrefix(`/rstudio/`) - traefik.http.routers.rstudio.service=rstudio - traefik.http.routers.rstudio.middlewares=rstudio-stripprefix,rstudio-headers - traefik.http.services.rstudio.loadbalancer.server.port=8787 - traefik.http.middlewares.rstudio-headers.headers.customrequestheaders.X-RStudio-Root-Path=/rstudio - traefik.http.middlewares.rstudio-stripprefix.stripprefix.prefixes=/rstudio - traefik.http.routers.rstudio-local.entrypoints=web - traefik.http.routers.rstudio-local.rule=Host(`rstudio.pecan.localhost`) - traefik.http.routers.rstudio-local.service=rstudio-local - traefik.http.services.rstudio-local.loadbalancer.server.port=8787 docs: image: pecan/docs:${PECAN_VERSION:-latest} restart: unless-stopped networks: pecan labels: - traefik.enable=true - traefik.http.services.docs.loadbalancer.server.port=80 - traefik.http.routers.docs.rule=Host(`${TRAEFIK_HOST:-pecan.localhost}`) && PathPrefix(`/`) pecan: user: ${UID:-1001}:${GID:-1001} image: pecan/web:${PECAN_VERSION:-latest} restart: unless-stopped networks: pecan environment: - RABBITMQ_URI=${RABBITMQ_URI:-amqp://guest:guest@rabbitmq/%2F} - FQDN=${PECAN_FQDN:-docker} - NAME=${PECAN_NAME:-docker} - SECRET_KEY_BASE=${BETY_SECRET_KEY:-thisisnotasecret} depends_on: - postgres - rabbitmq labels: - traefik.enable=true - traefik.http.services.pecan.loadbalancer.server.port=8080 - traefik.http.routers.pecan.rule=Host(`${TRAEFIK_HOST:-pecan.localhost}`) && PathPrefix(`/pecan/`) volumes: - pecan:/data - pecan:/var/www/html/pecan/data monitor: user: ${UID:-1001}:${GID:-1001} image: pecan/monitor:${PECAN_VERSION:-latest} restart: unless-stopped networks: pecan environment: - RABBITMQ_URI=${RABBITMQ_URI:-amqp://guest:guest@rabbitmq/%2F} - FQDN=${PECAN_FQDN:-docker} depends_on: rabbitmq labels: - traefik.enable=true - traefik.http.routers.monitor.rule=Host(`${TRAEFIK_HOST:-pecan.localhost}`) && PathPrefix(`/monitor/`) - traefik.http.routers.monitor.middlewares=monitor-stripprefix - traefik.http.middlewares.monitor-stripprefix.stripprefix.prefixes=/monitor volumes: pecan:/data executor: user: ${UID:-1001}:${GID:-1001} image: pecan/executor:${PECAN_VERSION:-latest} restart: unless-stopped networks: pecan environment: - RABBITMQ_URI=${RABBITMQ_URI:-amqp://guest:guest@rabbitmq/%2F} - RABBITMQ_PREFIX=/ - RABBITMQ_PORT=15672 - FQDN=${PECAN_FQDN:-docker} depends_on: - postgres - rabbitmq volumes: pecan:/data basgra: user: ${UID:-1001}:${GID:-1001} image: pecan/model-basgra-basgra_n_v1.0:${PECAN_VERSION:-latest} restart: unless-stopped networks: pecan environment: RABBITMQ_URI=${RABBITMQ_URI:-amqp://guest:guest@rabbitmq/%2F} depends_on: rabbitmq volumes: pecan:/data sipnet: user: ${UID:-1001}:${GID:-1001} image: pecan/model-sipnet-git:${PECAN_VERSION:-latest} restart: unless-stopped networks: pecan environment: RABBITMQ_URI=${RABBITMQ_URI:-amqp://guest:guest@rabbitmq/%2F} depends_on: rabbitmq volumes: pecan:/data ed2: user: ${UID:-1001}:${GID:-1001} image: pecan/model-ed2-2.2.0:${PECAN_VERSION:-latest} restart: unless-stopped networks: pecan environment: RABBITMQ_URI=${RABBITMQ_URI:-amqp://guest:guest@rabbitmq/%2F} depends_on: rabbitmq volumes: pecan:/data maespa: user: ${UID:-1001}:${GID:-1001} image: pecan/model-maespa-git:${PECAN_VERSION:-latest} restart: unless-stopped networks: pecan environment: RABBITMQ_URI=${RABBITMQ_URI:-amqp://guest:guest@rabbitmq/%2F} depends_on: rabbitmq volumes: pecan:/data biocro: user: ${UID:-1001}:${GID:-1001} image: pecan/model-biocro-0.95:${PECAN_VERSION:-latest} restart: unless-stopped networks: pecan environment: RABBITMQ_URI=${RABBITMQ_URI:-amqp://guest:guest@rabbitmq/%2F} depends_on: rabbitmq volumes: pecan:/data dbsync: image: pecan/shiny-dbsync:${PECAN_VERSION:-latest} restart: unless-stopped networks: pecan depends_on: postgres labels: - traefik.enable=true - traefik.http.routers.dbsync.rule=Host(`${TRAEFIK_HOST:-pecan.localhost}`) && PathPrefix(`/dbsync/`) - traefik.http.routers.dbsync.middlewares=dbsync-stripprefix - traefik.http.middlewares.dbsync-stripprefix.stripprefix.prefixes=/monitor api: user: ${UID:-1001}:${GID:-1001} image: pecan/api:${PECAN_VERSION:-latest} restart: unless-stopped networks: pecan environment: - PGHOST=${PGHOST:-postgres} - HOST_ONLY=${HOST_ONLY:-FALSE} - AUTH_REQ=${AUTH_REQ:-FALSE} - RABBITMQ_URI=${RABBITMQ_URI:-amqp://guest:guest@rabbitmq/%2F} - DATA_DIR=${DATA_DIR:-/data/} - DBFILES_DIR=${DBFILES_DIR:-/data/dbfiles/} - SECRET_KEY_BASE=${BETY_SECRET_KEY:-thisisnotasecret} labels: - traefik.enable=true - traefik.http.routers.api.rule=Host(`${TRAEFIK_HOST:-pecan.localhost}`) && PathPrefix(`/api/`) - traefik.http.services.api.loadbalancer.server.port=8000 depends_on: postgres volumes: pecan:/data/ networks: pecan: ~ volumes: traefik: ~ postgres: ~ rabbitmq: ~ pecan: ~ rstudio: ~ There are two ways you can override different values in the docker-compose.yml file. The first method is to create a file called .env that is placed in the same folder as the docker-compose.yml file. This file can override some of configuration variables used by docker-compose. For example the following is an example of the env file # This file will override the configuration options in the docker-compose # file. Copy this file to the same folder as docker-compose as .env # ---------------------------------------------------------------------- # GENERAL CONFIGURATION # ---------------------------------------------------------------------- # project name (-p flag for docker-compose) #COMPOSE_PROJECT_NAME=pecan # ---------------------------------------------------------------------- # TRAEFIK CONFIGURATION # ---------------------------------------------------------------------- # hostname of server #TRAEFIK_HOST=pecan-docker.ncsa.illinois.edu # Run traffik on port 80 (http) and port 443 (https) #TRAEFIK_HTTP_PORT=80 #TRAEFIK_HTTPS_PORT=443 # Use you real email address here to be notified if cert expires #TRAEFIK_ACME_EMAIL=pecanproj@gmail.com # ---------------------------------------------------------------------- # PEcAn CONFIGURATION # ---------------------------------------------------------------------- # what version of pecan to use #PECAN_VERSION=develop # the fully qualified hostname used for this server #PECAN_FQDN=pecan-docker.ncsa.illinois.edu # short name shown in the menu #PECAN_NAME=pecan-docker # ---------------------------------------------------------------------- # BETY CONFIGURATION # ---------------------------------------------------------------------- # what version of BETY to use #BETY_VERSION=develop # what is our server number, 99=vm, 98=docker #BETY_LOCAL_SERVER=98 # secret used to encrypt cookies in BETY #BETY_SECRET_KEY=1208q7493e8wfhdsohfo9ewhrfiouaho908ruq30oiewfdjspadosuf08q345uwrasdy98t7q243 # ---------------------------------------------------------------------- # MINIO CONFIGURATION # ---------------------------------------------------------------------- # minio username and password #MINIO_ACCESS_KEY=carya #MINIO_SECRET_KEY=illinois # ---------------------------------------------------------------------- # PORTAINER CONFIGURATION # ---------------------------------------------------------------------- # password for portainer admin account # use docker run --rm httpd:2.4-alpine htpasswd -nbB admin <password> | cut -d ":" -f 2 #PORTAINER_PASSWORD=$2y$05$5meDPBtS3NNxyGhBpYceVOxmFhiiC3uY5KEy2m0YRbWghhBr2EVn2 # ---------------------------------------------------------------------- # RABBITMQ CONFIGURATION # ---------------------------------------------------------------------- # RabbitMQ username and password #RABBITMQ_DEFAULT_USER=carya #RABBITMQ_DEFAULT_PASS=illinois # create the correct URI with above username and password #RABBITMQ_URI=amqp://carya:illinois@rabbitmq/%2F # ---------------------------------------------------------------------- # RSTUDIO CONFIGURATION # ---------------------------------------------------------------------- # Default RStudio username and password for startup of container #PECAN_RSTUDIO_USER=carya #PECAN_RSTUDIO_PASS=illinois You can also extend the docker-compose.yml file with a docker-compose.override.yml file (in the same directory), allowing you to add more services, or for example to change where the volumes are stored (see official documentation). For example the following will change the volume for postgres to be stored in your home directory: version: "3" volumes: postgres: driver_opts: type: none device: ${HOME}/postgres o: bind 25.4.3 Top-level structure The root of the docker-compose.yml file contains three sections: services – This is a list of services provided by the application, with each service corresponding to a container. When communicating with each other internally, the hostnames of containers correspond to their names in this section. For instance, regardless of the “project” name passed to docker-compose up, the hostname for connecting to the PostgreSQL database of any given container is always going to be postgres (e.g. you should be able to access the PostgreSQL database by calling the following from inside the container: psql -d bety -U bety -h postgres). The services comprising the PEcAn application are described below. networks – This is a list of networks used by the application. Containers can only communicate with each other (via ports and hostnames) if they are on the same Docker network, and containers on different networks can only communicate through ports exposed by the host machine. We just provide the network name (pecan) and resort to Docker’s default network configuration. Note that the services we want connected to this network include a networks: ... - pecan tag. For more details on Docker networks, see the official documentation. volumes – Similarly to networks, this just contains a list of volume names we want. Briefly, in Docker, volumes are directories containing files that are meant to be shared across containers. Each volume corresponds to a directory, which can be mounted at a specific location by different containers. For example, syntax like volumes: ... - pecan:/data in a service definition means to mount the pecan “volume” (including its contents) in the /data directory of that container. Volumes also allow data to persist on containers between restarts, as normally, any data created by a container during its execution is lost when the container is re-launched. For example, using a volume for the database allows data to be saved between different runs of the database container. Without volumes, we would start with a blank database every time we restart the containers. For more details on Docker volumes, see the official documentation. Here, we define three volumes: postgres – This contains the data files underlying the PEcAn PostgreSQL database (BETY). Notice that it is mounted by the postgres container to /var/lib/postgresql/data. This is the data that we pre-populate when we run the Docker commands to initialize the PEcAn database. Note that these are the values stored directly in the PostgreSQL database. The default files to which the database points (i.e. dbfiles) are stored in the pecan volume, described below. rabbitmq – This volume contains persistent data for RabbitMQ. It is only used by the rabbitmq service. pecan – This volume contains PEcAn’s dbfiles, which include downloaded and converted model inputs, processed configuration files, and outputs. It is used by almost all of the services in the PEcAn stack, and is typically mounted to /data. 25.4.4 traefik Traefik manages communication among the different PEcAn services and between PEcAn and the web. Among other things, traefik facilitates the setup of web access to each PEcAn service via common and easy-to-remember URLs. For instance, the following lines in the web service configure access to the PEcAn web interface via the URL http://pecan.localhost/pecan/ : ~ (Further details in the works…) The traefik service configuration looks like this: traefik: image: traefik:v2.9 command: - --log.level=INFO - --api=true - --api.dashboard=true - --entrypoints.web.address=:80 - --providers.docker=true - --providers.docker.endpoint=unix:///var/run/docker.sock - --providers.docker.exposedbydefault=false - --providers.docker.watch=true restart: unless-stopped networks: pecan security_opt: no-new-privileges:true ports: ${TRAEFIK_HTTP_PORT-80}:80 volumes: - traefik:/config - /var/run/docker.sock:/var/run/docker.sock:ro labels: - traefik.enable=true - traefik.http.routers.traefik.entrypoints=web - traefik.http.routers.traefik.rule=Host(`traefik.pecan.localhost`) - traefik.http.routers.traefik.service=api@internal 25.4.5 portainer portainer is lightweight management UI that allows you to manage the docker host (or swarm). You can use this service to monitor the different containers, see the logfiles, and start and stop containers. The portainer service configuration looks like this: NA: ~ Portainer is accessible by browsing to pecan.localhost/portainer/. You can either set the password in the .env file (for an example see env.example) or you can use the web browser and go to the portainer url. If this is the first time it will ask for your password. 25.4.6 minio Minio is a service that provides access to the a folder on disk through a variety of protocols, including S3 buckets and web-based access. We mainly use Minio to facilitate access to PEcAn data using a web browser without the need for CLI tools. Our current configuration is as follows: NA: ~ The Minio interface is accessible by browsing to minio.pecan.localhost. From there, you can browse directories and download files. You can also upload files by clicking the red “+” in the bottom-right corner. Note that it is currently impossible to create or upload directories using the Minio interface (except in the /data root directory – those folders are called “buckets” in Minio). Therefore, the recommended way to perform any file management tasks other than individual file uploads is through the command line, e.g. docker run -it --rm --volumes pecan_pecan:/data --volumes /path/to/local/directory:/localdir ubuntu # Now, you can move files between `/data` and `/localdir`, create new directories, etc. 25.4.7 thredds This service allows PEcAn model outputs to be accessible via the THREDDS data server (TDS). When the PEcAn stack is running, the catalog can be explored in a web browser at http://pecan.localhost/thredds/catalog.html. Specific output files can also be accessed from the command line via commands like the following: Note that everything after outputs/ exactly matches the directory structure of the workflows directory. Which files are served, which subsetting services are available, and other aspects of the data server’s behavior are configured in the docker/thredds_catalog.xml file. Specifically, this XML tells the data server to use the datasetScan tool to serve all files within the /data/workflows directory, with the additional filter that only files ending in .nc are served. For additional information about the syntax of this file, see the extensive THREDDS documentation. Our current configuration is as follows: NA: ~ 25.4.8 postgres This service provides a working PostGIS database. Our configuration is fairly straightforward: postgres: image: mdillon/postgis:9.5 restart: unless-stopped networks: pecan volumes: postgres:/var/lib/postgresql/data Some additional details about our configuration: image – This pulls a container with PostgreSQL + PostGIS pre-installed. Note that by default, we use PostgreSQL version 9.5. To experiment with other versions, you can change 9.5 accordingly. networks – This allows PostgreSQL to communicate with other containers on the pecan network. As mentioned above, the hostname of this service is just its name, i.e. postgres, so to connect to the database from inside a running container, use a command like the following: psql -d bety -U bety -h postgres volumes – Note that the PostgreSQL data files (which store the values in the SQL database) are stored on a volume called postgres (which is not the same as the postgres service, even though they share the same name). 25.4.9 rabbitmq RabbitMQ is a message broker service. In PEcAn, RabbitMQ functions as a task manager and scheduler, coordinating the execution of different tasks (such as running models and analyzing results) associated with the PEcAn workflow. Our configuration is as follows: rabbitmq: image: rabbitmq:3.8-management restart: unless-stopped networks: pecan environment: - RABBITMQ_DEFAULT_USER=${RABBITMQ_DEFAULT_USER:-guest} - RABBITMQ_DEFAULT_PASS=${RABBITMQ_DEFAULT_PASS:-guest} labels: - traefik.enable=true - traefik.http.services.rabbitmq.loadbalancer.server.port=15672 - traefik.http.routers.rabbitmq.entrypoints=web - traefik.http.routers.rabbitmq.rule=Host(`rabbitmq.pecan.localhost`) volumes: rabbitmq:/var/lib/rabbitmq Note that the traefik.http.routers.rabbitmq.rule indicates that browsing to http://rabbitmq.pecan.localhost/ leads to the RabbitMQ management console. By default, the RabbitMQ management console has username/password guest/guest, which is highly insecure. For production instances of PEcAn, we highly recommend changing these credentials to something more secure, and removing access to the RabbitMQ management console via Traefik. 25.4.10 bety This service operates the BETY web interface, which is effectively a web-based front-end to the PostgreSQL database. Unlike the postgres service, which contains all the data needed to run PEcAn models, this service is not essential to the PEcAn workflow. However, note that certain features of the PEcAn web interface do link to the BETY web interface and will not work if this container is not running. Our configuration is as follows: bety: image: pecan/bety:${BETY_VERSION:-latest} restart: unless-stopped networks: pecan environment: - UNICORN_WORKER_PROCESSES=1 - SECRET_KEY_BASE=${BETY_SECRET_KEY:-notasecret} - RAILS_RELATIVE_URL_ROOT=/bety - LOCAL_SERVER=${BETY_LOCAL_SERVER:-99} depends_on: postgres labels: - traefik.enable=true - traefik.http.services.bety.loadbalancer.server.port=8000 - traefik.http.routers.bety.rule=Host(`${TRAEFIK_HOST:-pecan.localhost}`) && PathPrefix(`/bety/`) The BETY container Dockerfile is located in the root directory of the BETY GitHub repository (direct link). 25.4.11 docs This service will show the documentation for the version of PEcAn running as well as a homepage with links to all relevant endpoints. You can access this at http://pecan.localhost/. You can find the documentation for PEcAn at http://pecan.localhost/docs/pecan/. Our current configuration is as follows: docs: image: pecan/docs:${PECAN_VERSION:-latest} restart: unless-stopped networks: pecan labels: - traefik.enable=true - traefik.http.services.docs.loadbalancer.server.port=80 - traefik.http.routers.docs.rule=Host(`${TRAEFIK_HOST:-pecan.localhost}`) && PathPrefix(`/`) 25.4.12 web This service runs the PEcAn web interface. It is effectively a thin wrapper around a standard Apache web server container from Docker Hub that installs some additional dependencies and copies over the necessary files from the PEcAn source code. Our configuration is as follows: NA: ~ Its Dockerfile ships with the PEcAn source code, in docker/web/Dockerfile. In terms of actively developing PEcAn using Docker, this is the service to modify when making changes to the web interface (i.e. PHP, HTML, and JavaScript code located in the PEcAn web directory). 25.4.13 executor This service is in charge of running the R code underlying the core PEcAn workflow. However, it is not in charge of executing the models themselves – model binaries are located on their own dedicated Docker containers, and model execution is coordinated by RabbitMQ. Our configuration is as follows: executor: user: ${UID:-1001}:${GID:-1001} image: pecan/executor:${PECAN_VERSION:-latest} restart: unless-stopped networks: pecan environment: - RABBITMQ_URI=${RABBITMQ_URI:-amqp://guest:guest@rabbitmq/%2F} - RABBITMQ_PREFIX=/ - RABBITMQ_PORT=15672 - FQDN=${PECAN_FQDN:-docker} depends_on: - postgres - rabbitmq volumes: pecan:/data Its Dockerfile is ships with the PEcAn source code, in docker/executor/Dockerfile. Its image is built on top of the pecan/base image (docker/base/Dockerfile), which contains the actual PEcAn source. To facilitate caching, the pecan/base image is itself built on top of the pecan/depends image (docker/depends/Dockerfile), a large image that contains an R installation and PEcAn’s many system and R package dependencies (which usually take ~30 minutes or longer to install from scratch). In terms of actively developing PEcAn using Docker, this is the service to modify when making changes to the PEcAn R source code. Note that, unlike changes to the web image’s PHP code, changes to the R source code do not immediately propagate to the PEcAn container; instead, you have to re-compile the code by running make inside the container. 25.4.14 monitor This service will show all models that are currently running http://pecan.localhost/monitor/. This list returned is JSON and shows all models (grouped by type and version) that are currently running, or where seen in the past. This list will also contain a list of all current active containers, as well as how many jobs are waiting to be processed. This service is also responsible for registering any new models with PEcAn so users can select it and execute the model from the web interface. Our current configuration is as follows: monitor: user: ${UID:-1001}:${GID:-1001} image: pecan/monitor:${PECAN_VERSION:-latest} restart: unless-stopped networks: pecan environment: - RABBITMQ_URI=${RABBITMQ_URI:-amqp://guest:guest@rabbitmq/%2F} - FQDN=${PECAN_FQDN:-docker} depends_on: rabbitmq labels: - traefik.enable=true - traefik.http.routers.monitor.rule=Host(`${TRAEFIK_HOST:-pecan.localhost}`) && PathPrefix(`/monitor/`) - traefik.http.routers.monitor.middlewares=monitor-stripprefix - traefik.http.middlewares.monitor-stripprefix.stripprefix.prefixes=/monitor volumes: pecan:/data 25.4.15 Model-specific containers Additional models are added as additional services. In general, their configuration should be similar to the following configuration for SIPNET, which ships with PEcAn: sipnet: user: ${UID:-1001}:${GID:-1001} image: pecan/model-sipnet-git:${PECAN_VERSION:-latest} restart: unless-stopped networks: pecan environment: RABBITMQ_URI=${RABBITMQ_URI:-amqp://guest:guest@rabbitmq/%2F} depends_on: rabbitmq volumes: pecan:/data The PEcAn source contains Dockerfiles for ED2 (models/ed/Dockerfile) and SIPNET (models/sipnet/Dockerfile) that can serve as references. For additional tips on constructing a Dockerfile for your model, see Dockerfiles for Models. "],["model-docker.html", "25.5 Models using Docker", " 25.5 Models using Docker This section will discuss how to add new models to PEcAn docker. To be able to add a new model to PEcAn when using docker is as simple as starting a new container. The model will come online and let the PEcAn framework know there is a new model available, there is no need to go through the process of registering this model with PEcAn. Users will be able to select this new model from web interface and run with this model selected. For this process to work a docker image of the model will need to be created as well as small json file that is used to announce this new model. A separate service in PEcAn (monitor) will use this json file to keep track of all models available as well as register these models with PEcAn. Model information Model build Common problems 25.5.1 Model information Each model will have a small json file called model_info.json that is used to describe the model and used by the monitor service to register the model with PEcAn. This file will contain information about the model that is send as part of the heartbeat of the container to the monitor service. Below is an example of this file for the ED model. The required fields are name, type, version and binary. The fields type and version are used by PEcAn to send the messages to RabbitMQ. There is no need to specify the queue name explicitly. The queue name will be created by combining these two fields with an underscore. The field binary is used to point to the actual binary in the docker container. There are 2 special values that can be used, @VERSION@ which will be replaced by the version that is passed in when building the container, and @BINARY@ which will be replaced by the binary when building the docker image. { "name": "ED2.2", "type": "ED2", "version": "@VERSION@", "binary": "@BINARY@", "description": "The Ecosystem Demography Biosphere Model (ED2) is an integrated terrestrial biosphere model incorporating hydrology, land-surface biophysics, vegetation dynamics, and soil carbon and nitrogen biogeochemistry", "author": "Mike Dietze", "contributors": ["David LeBauer", "Xiaohui Feng", "Dan Wang", "Carl Davidson", "Rob Kooper", "Shawn Serbin", "Alexey Shiklomanov"], "links": { "source": "https://github.com/EDmodel/ED2", "issues": "https://github.com/EDmodel/ED2/issues" }, "inputs": {}, "citation": ["Medvigy D., Wofsy S. C., Munger J. W., Hollinger D. Y., Moorcroft P. R. 2009. Mechanistic scaling of ecosystem function and dynamics in space and time: Ecosystem Demography model version 2. J. Geophys. Res. 114 (doi:10.1029/2008JG000812)"] } Other fields that are recommended, but currently not used yet, are: description : a longer description of the model. creator : contact person about this docker image. contribuor : other people that have contributed to this docker image. links : addtional links to help people when using this docker image, for example values that can be used are source to link to the source code, issues to link to issue tracking system, and documentation to link to model specific documentation. citation : how the model should be cited in publications. 25.5.2 Model build In general we try to minimize the size of the images. To be able to do this we split the process of creating the building of the model images into two pieces (or leverage of an image that exists from the original model developers). If you look at the example Dockerfile you will see that there are 2 sections, the first section will build the model binary, the second section will build the actual PEcAn model, which copies the binary from the first section. This is an example of how the ED2 model is build. This will install all the packages needed to build ED2 model, gets the latest version from GitHub and builds the model. The second section will create the actual model runner. This will leverage the PEcAn model image that has PEcAn already installed as well as the python code to listen for messages and run the actual model code. This will install some additional packages needed by the model binary (more about that below), copy the model_info.json file and change the @VERSION@ and @BINARY@ placeholders. It is important values for type and version are set correct. The PEcAn code will use these to register the model with the BETY database, which is then used by PEcAn to send out a message to a specfic worker queue, if you do not set these variables correctly your model executor will pick up messages for the wrong model. To build the docker image, we use a Dockerfile (see example below) and run the following command. This command will expect the Dockerfile to live in the model specific folder and the command is executed in the root pecan folder. It will copy the content of the pecan folder and make it available to the build process (in this example we do not need any additional files). Since we can have multiple different versions of a model be available for PEcAn we ar using the following naming schema pecan/model-<modeltype>-<version>:<pecan version. For example the image below will be named pecan/model-ed2-git, since we do not specify the exact version it will be atomically be named pecan/model-ed2-git:latest. docker build \\ --tag pecan/model-ed2-git \\ --file models/ed/Dockerfile \\ . Example of a Dockerfile, in this case to build the ED2 model. ARG IMAGE_VERSION="latest" # ---------------------------------------------------------------------- # BUILD MODEL BINARY # ---------------------------------------------------------------------- FROM pecan/models:${IMAGE_VERSION} as model-binary # Some variables that can be used to set control the docker build ARG MODEL_VERSION=git # install dependencies RUN apt-get update \\ && apt-get install -y --no-install-recommends \\ build-essential \\ curl \\ gfortran \\ git \\ libhdf5-dev \\ libopenmpi-dev \\ && rm -rf /var/lib/apt/lists/* # download, unzip and build ed2 WORKDIR /src RUN git -c http.sslVerify=false clone https://github.com/EDmodel/ED2.git \\ && cd ED2/ED/build \\ && curl -o make/include.mk.VM http://isda.ncsa.illinois.edu/~kooper/EBI/include.mk.opt.Linux \\ && if [ "${MODEL_VERSION}" != "git" ]; then git checkout ${MODEL_VERSION}; fi \\ && ./install.sh -g -p VM ######################################################################## # ---------------------------------------------------------------------- # BUILD PECAN FOR MODEL # ---------------------------------------------------------------------- FROM pecan/models:latest # ---------------------------------------------------------------------- # INSTALL MODEL SPECIFIC PIECES # ---------------------------------------------------------------------- RUN apt-get update \\ && apt-get install -y --no-install-recommends \\ libgfortran3 \\ libopenmpi2 \\ && rm -rf /var/lib/apt/lists/* # ---------------------------------------------------------------------- # SETUP FOR SPECIFIC MODEL # ---------------------------------------------------------------------- # Some variables that can be used to set control the docker build ARG MODEL_VERSION=git # Setup model_info file COPY models/ed/model_info.json /work/model.json RUN sed -i -e "s/@VERSION@/${MODEL_VERSION}/g" \\ -e "s#@BINARY@#/usr/local/bin/ed2.${MODEL_VERSION}#g" /work/model.json # COPY model binary COPY --from=model-binary /src/ED2/ED/build/ed_2.1-opt /usr/local/bin/ed2.${MODEL_VERSION} WARNING: Dockerfile environment variables set via ENV are assigned all at once; they do not evaluate successively, left to right. Consider the following block: # Don't do this! ENV MODEL_TYPE="SIPNET" \\ MODEL_VERSION=136 \\ MODEL_TYPE_VERSION=${MODEL_TYPE}_${MODEL_VERSION} # <- Doesn't know about MODEL_TYPE or MODEL_VERSION! In this block, the expansion for setting MODEL_TYPE_VERSION is not aware of the current values of MODEL_TYPE or MODEL_VERSION, and will therefore be set incorrectly to just _ (unless they have been set previously, in which case it will be aware only of their earlier values). As such, variables depending on other variables must be set in a separate, subsequent ENV statement than the variables they depend on. Once the model has build and is working we can add it to the PEcAn stack and be able to use this model in the web interface. There are two methods to start this new model. First, we can add it to the docker-compose.yml file and start the container using docker-compose -p pecan -d up. sipnet: image: pecan/model-ed2-git networks: - pecan volumes: - pecan:/data depends_on: - rabbitmq restart: unless-stopped Alternatively we can start the container manually using the following command. docker run \\ --detach \\ --rm \\ --name pecan-ed2-git \\ --networks pecan_pecan \\ --volume pecan_pecan:/data pecan/model-ed2-git 25.5.3 Common problems Following are some solutions for common problems that you might encounter when building the docker images for a model. 25.5.4 Debugging missing libraries When building the model binary it might require specific libraries to be installed. In the second stage the model binary is copied into a new image, which could result in the binary missing specific libraries. In the case of the ED2 model the following was used to find the libraries that are needed to be installed (libgfortran5 and libopenmpi3). The first step is to build the model using the Dockerfile (in this case the ap-get install was missing in the second stage). Step 5/9 : RUN git clone https://github.com/EDmodel/ED2.git && cd ED2/ED/build && curl -o make/include.mk.VM http://isda.ncsa.illinois.edu/~kooper/EBI/include.mk.opt.`uname -s` && if [ "${MODEL_VERSION}" != "git" ]; then git checkout ${MODEL_VERSION}; fi && ./install.sh -g -p VM ... LOTS OF OUTPUT ... make[1]: Leaving directory '/src/ED2/ED/build/bin-opt-E' Installation Complete. Removing intermediate container a53eba9a8fc1 ---> 7f23c6302130 Step 6/9 : FROM pecan/executor:latest ---> f19d81b739f5 ... MORE OUTPUT ... Step 9/9 : COPY --from=model-binary /src/ED2/ED/build/ed_2.1-opt /usr/local/bin/ed2.${MODEL_VERSION} ---> 07ac841be457 Successfully built 07ac841be457 Successfully tagged pecan/pecan-ed2:latest At this point we have created a docker image with the binary and all PEcAn code that is needed to run the model. Some models (especially those build as native code) might be missing additional packages that need to be installed in the docker image. To see if all libraries are installed for the binary. > docker run -ti --rm pecan/pecan-ed2 /bin/bash root@8a95ee8b6b47:/work# ldd /usr/local/bin/ed2.git | grep "not found" libmpi_usempif08.so.40 => not found libmpi_usempi_ignore_tkr.so.40 => not found libmpi_mpifh.so.40 => not found libmpi.so.40 => not found libgfortran.so.5 => not found Start the build container again (this is the number before the line FROM pecan/executor:latest, 7f23c6302130 in the example), and find the missing libraries listed above (for example libmpi_usempif08.so.40): > docker run --rm -ti 7f23c6302130 root@e716c63c031f:/src# dpkg -S libmpi_usempif08.so.40 libopenmpi3:amd64: /usr/lib/x86_64-linux-gnu/openmpi/lib/libmpi_usempif08.so.40.10.1 libopenmpi3:amd64: /usr/lib/x86_64-linux-gnu/libmpi_usempif08.so.40.10.1 libopenmpi3:amd64: /usr/lib/x86_64-linux-gnu/libmpi_usempif08.so.40 This shows the pages is libopenmpi3 that needs to be installed, do this for all missing packages, modify the Dockerfile and rebuild. Next time you run the ldd command there should be no more packages being listed. "],["docker-build-images.html", "25.6 Building and modifying images", " 25.6 Building and modifying images The only other section on this page is: Local development and testing with Docker For general use, it is sufficient to use the pre-built PEcAn images hosted on Docker Hub (see Docker quickstart). However, there are cases where it makes sense to re-build the Docker images locally. The following is a list of PEcAn-specific images and reasons why you would want to rebuild them locally: pecan/depends – Rebuild if: You modify the docker/depends/Dockerfile You introduce new system dependencies (i.e. things that need to be installed with apt-get) You introduce new R package dependencies, and you want those R package installations to be cached during future builds. For packages with fast build times, it may be fine to let them be installed as part of PEcAn’s standard build process (i.e. make). pecan/base – Rebuild if: You built a new version of pecan/depends (on which pecan/base depends) You modify the docker/base/Dockerfile You made changes to the PEcAn R package source code, the Makefile, or web/workflow.R. NOTE that changes to the web interface code affect pecan/web, not pecan/base pecan/executor – Rebuild if: You built a new version of pecan/base (on which pecan/executor depends) and/or, pecan/depends (on which pecan/base depends) You modified the docker/executor/Dockerfile You modified the RabbitMQ Python script (e.g. docker/receiver.py) pecan/web – Rebuild if you modified any of the following: docker/web/Dockerfile The PHP/HTML/JavaScript code for the PEcAn web interface in web/ (except web/workflow.R – that goes in pecan/base) docker/config.docker.php (the config.php file for Docker web instances) documentation/index_vm.html (the documentation HTML website) NOTE: Because changes to this code are applied instantly (i.e. do not require compilation or installation), a more effective way to do local development may be to mount the web/ or other relevant folders as a volume onto the pecan/web container. The easiest way to quickly re-build all of the images is using the docker.sh script in the PEcAn source code root directory. This script will build all of the docker images locally on your machine, and tag them as latest. This will not build the pecan/depends image by default because that takes considerably longer. However, you can force the script to build pecan/depends as well by setting the DEPEND environment variable to 1 (i.e. DEPEND=1 ./docker.sh). The following instructions provide details on how to build each image individually. To build an image locally, use the docker build command as described below. For more details, see docker build --help or the online Docker build documentation. First, in a terminal window, navigate (cd) into the PEcAn source code root directory. From there, the general syntax for building an image looks like the following: docker build -t pecan/<image name>:<image version> -f docker/base/Dockerfile.<image name> . For instance, to build a local version of the pecan/depends:latest image, you would run: docker build -t pecan/depends:latest -f docker/depends/Dockerfile . The breakdown of this command is as follows: docker build – This is the core command. The standard syntax is docker build [OPTIONS] <PATH>, where <PATH> refers to the directory to be used as the “build context”. The “build context” is the working directory assumed by the Dockerfiles. In PEcAn, this is always the PEcAn source code root directory, which allows Dockerfiles to use instructions such as COPY web/workflow.R /work/. In this example, the <PATH> is set to the current working directory, i.e. . because we are already in the PEcAn root directory. If you were located in a different directory, you would have to provide a path to the PEcAn source code root directory. Also, by default, docker build will look for a Dockerfile located at <PATH>/Dockerfile, but this is modified by the -f option described below. -t pecan/depends:latest – The -t/--tag option specifies how the image will be labeled. By default, Docker only defines unique image IDs, which are hexidecimal strings that are unintuitive and hard to remember. Tags are useful for referring to specific images in a human-readable way. Note that the same unique image can have multiple tags associated with it, so it is possible for, e.g. pecan/depends:latest, pecan/depends:custom, and even mypecan/somethingelse:20.0 to refer to the same exact image. To see a table of all local images, including their tags and IDs, run docker image ls. NOTE: PEcAn’s docker-compose.yml can be configured via the PECAN environment variable to point at different versions of PEcAn images. By default, it points to the :latest versions of all images. However, if you wanted to, for instance, build :local images corresponding to your local source code and then run that version of PEcAn, you would run: PECAN=local docker-compose -p pecan up -d This is an effective way to do local development and testing of different PEcAn versions, as described below. -f docker/depends/Dockerfile – The -f/--file tag is used to provide an alternative location and file name for the Dockerfile. 25.6.1 Local development and testing with Docker The following is an example of one possible workflow for developing and testing PEcAn using local Docker images. The basic idea is to mount a local version of the PEcAn source code onto a running pecan/executor image, and then send a special “rebuild” RabbitMQ message to the container to trigger the rebuild whenever you make changes. NOTE: All commands assume you are working from the PEcAn source code root directory. In the PEcAn source code directory, create a docker-compose.override.yml file with the following contents.: version: "3" services: executor: volumes: - .:/pecan This will mount the current directory . to the /pecan directory in the executor container. The special docker-compose.override.yml file is read automatically by docker-compose and overrides or extends any instructions set in the original docker-compose.yml file. It provides a convenient way to host server-specific configurations without having to modify the project-wide (and version-controlled) default configuration. For more details, see the Docker Compose documentation. Update your PEcAn Docker stack with docker-compose up -d. If the stack is already running, this should only restart your executor instance while leaving the remaining containers running. To update to the latest local code, run ./scripts/docker_rebuild.sh. Under the hood, this uses curl to post a RabbitMQ message to a running Docker instance. By default, the scripts assumes that username and password are both guest and that the RabbitMQ URL is http://rabbitmq.pecan.localhost/. All of these can be customized by setting the environment variables RABBITMQ_USER, RABBITMQ_PASSWORD, and RABBITMQ_URL, respectively (or running the script prefixed with those variables, e.g. RABBITMQ_USER=carya RABBITMQ_PASSWORD=illinois ./scripts/docker_rebuild.sh). This step can be repeated whenever you want to trigger a rebuild of the local code. NOTE: The updates with this workflow are specific to the running container session; restarting the executor container will revert to the previous versions of the installed packages. To make persistent changes, you should re-build the pecan/base and pecan/executor containers against the current version of the source code. NOTE: The mounted PEcAn source code directory includes everything in your local source directory, including installation artifacts used by make. This can lead to two common issues: - Any previous make cache files (stuff in the .install, .docs, etc. directories) persist across container instances, even though the installed packages may not. To ensure a complete build, it’s a good idea to run make clean on the host machine to remove these artifacts. - Similarly, any installation artifacts from local builds will be carried over to the build. In particular, be wary of packages with compiled code, such as modules/rtm (PEcAnRTM) – the compiled .o, .so, .mod, etc. files from compilation of such packages will carry over into the build, which can cause conflicts if the package was also built locally. The docker-compose.override.yml is useful for some other local modifications. For instance, the following adds a custom ED2 “develop” model container. services: # ... ed2devel: image: pecan/model-ed2-develop:latest build: context: ../ED2 # Or wherever ED2 source code is found networks: - pecan depends_on: - rabbitmq volumes: - pecan:/data restart: unless-stopped Similarly, this snippet modifies the pecan network to use a custom IP subnet mask. This is required on the PNNL cluster because its servers’ IP addresses often clash with Docker’s default IP mask. networks: pecan: ipam: config: - subnet: 10.17.1.0/24 "],["docker-troubleshooting.html", "25.7 Troubleshooting Docker", " 25.7 Troubleshooting Docker 25.7.1 “Package not available” while building images PROBLEM: Packages fail to install while building pecan/depends and/or pecan/base with an error like the following: Installing package into ‘/usr/local/lib/R/site-library’ (as ‘lib’ is unspecified) Warning: unable to access index for repository <URL>: cannot open URL '<URL>' Warning message: package ‘<PACKAGE>’ is not available (for R version 3.5.1) CAUSE: This can sometimes happen if there are problems with the RStudio Package manager, which is the default repository for the rocker/tidyverse containers. See GitHub issues rocker-org/rocker-versioned#102 and #58. WORKAROUND: Add the following line to the depends and/or base Dockerfiles before (i.e. above) any commands that install R packages (e.g. Rscript -e \"install.packages(...)\"): RUN echo "options(repos = c(CRAN = 'https://cran.rstudio.org'))" >> /usr/local/lib/R/etc/Rprofile.site This will set the default repository to the more reliable (albeit, more up-to-date; beware of breaking package changes!) RStudio CRAN mirror. Then, build the image as usual. "],["docker-migrate.html", "25.8 Migrating PEcAn from VM to Docker", " 25.8 Migrating PEcAn from VM to Docker This document assumes you have read through the Introduction to Docker as well as Docker quickstart and have docker running on the VM. This document will slowly replace each of the components with the appropriate docker images. At then end of this document you should be able to use the docker-compose command to bring up the full docker stack as if you had started with this origianally. 25.8.1 Running BETY as a docker container This will replace the BETY application running on the machine with a docker image. This will assume you still have the database running on the local machine and the only thing we replace is the BETY application. If you are running systemd (Ubuntu 16.04 or Centos 7) you can copy the following file to /etc/systemd/system/bety.service (replace LOCAL_SERVER=99 with your actual server). If you have postgres running on another server replace 127.0.0.1 with the actual ip address of the postgres server. [Unit] Description=BETY container After=docker.service [Service] Restart=always ExecStart=/usr/bin/docker run -t --rm --name bety --add-host=postgres:127.0.0.1 --network=host --env RAILS_RELATIVE_URL_ROOT=/bety --env LOCAL_SERVER=99 pecan/bety ExecStop=/usr/bin/docker stop -t 2 bety [Install] WantedBy=local.target At this point we can enable the bety service (this only needs to be done once). First we need to tell systemd a new service is available using systemctl daemon-reload. Next we enable the BETY service so it will restart automatically when the machine reboots, using systemctl enable bety. Finally we can start the BETY service using systemctl start bety. At this point BETY is running as a docker container on port 8000. You can see the log messages using journalctl -u bety. Next we need to modify apache configuration files. The file /etc/apache2/conf-enabled/bety.conf will be replaced with the following content: ProxyPass /bety/ http://pecan.localhost/bety/ ProxyPassReverse /bety/ http://pecan.localhost/bety/ RedirectMatch permanent ^/bety$ /bety/ Once this modified we can restart apache using systemctl restart apache2. At this point BETY is running in a container and is accessable trough the webserver at http://server/bety/. To upgrade to a new version of BETY you can now use the docker commands. You can use the following commands to stop BETY, pull the latest image down, migrate the database (you made a backup correct?) and start BETY again. systemctl stop bety docker pull pecan/bety:latest docker run -ti --rm --add-host=postgres:127.0.0.1 --network=host --env LOCAL_SERVER=99 pecan/bety migrate systemctl start bety Once you are satisfied with the migration of BETY you can remove the bety folder as well as any ruby binaries you have installed. "],["pecan-api.html", "25.9 The PEcAn Docker API", " 25.9 The PEcAn Docker API If you have a running instance of Dockerized PEcAn (or other setup where PEcAn workflows are submitted via RabbitMQ), you have the option of running and managing PEcAn workflows using the pecanapi package. For more details, see the pecanapi package vignette and function-level documentation. What follows is a lightning introduction. 25.9.0.1 Installation The package can be installed directly from GitHub via devtools::install_github: devtools::install_github("pecanproject/pecan/api@develop") 25.9.0.2 Creating and submitting a workflow With pecanapi, creating a workflow, submitting it to RabbitMQ, monitoring its progress, and processing its output can all be accomplished via an R script. Start by loading the package (and the magrittr package, for the %>% pipe operator). library(pecanapi) library(magrittr) Set your PEcAn database user ID, and create a database connection object, which will be used for database operations throughout the workflow. options(pecanapi.user_id = 99000000002) con <- DBI::dbConnect( drv = RPostgres::Postgres(), user = "bety", password = "bety", host = "localhost", port = 5432 ) Find model and site IDs for the site and model you want to run. model_id <- get_model_id(con, "SIPNET", "136") all_umbs <- search_sites(con, "umbs%disturbance") site_id <- subset(all_umbs, !is.na(mat))[["id"]] Insert a new workflow into the PEcAn database, and extract its ID. workflow <- insert_new_workflow(con, site_id, model_id, start_date = "2004-01-01", end_date = "2004-12-31") workflow_id <- workflow[["id"]] Pull all of this information together into a settings list object. settings <- list() %>% add_workflow(workflow) %>% add_database() %>% add_pft("temperate.deciduous") %>% add_rabbitmq(con = con) %>% modifyList(list( meta.analysis = list(iter = 3000, random.effects = list(on = FALSE, use_ghs = TRUE)), run = list(inputs = list(met = list(source = "CRUNCEP", output = "SIPNET", method = "ncss"))), ensemble = list(size = 1, variable = "NPP") )) Submit the workflow via RabbitMQ, and monitor its progress in the R process. submit_workflow(settings) watch_workflow(workflow_id) Use THREDDS to access and analyze the output. sipnet_out <- ncdf4::nc_open(run_dap(workflow_id, "2004.nc")) gpp <- ncdf4::ncvar_get(sipnet_out, "GPP") time <- ncdf4::ncvar_get(sipnet_out, "time") ncdf4::nc_close(sipnet_out) plot(time, gpp, type = "l") "],["rabbitmq.html", "25.10 RabbitMQ", " 25.10 RabbitMQ This section provides additional details about how PEcAn uses RabbitMQ to manage communication between its Docker containers. In PEcAn, we use the Python pika client to retrieve messages from RabbitMQ. The PEcAn.remote library has convenience functions that wrap the API to post and read messages. The executor and models use the python version of the RabbitMQ scripts to retrieve messages, and launch the appropriate code. 25.10.1 Producer – PEcAn.remote::rabbitmq_post_message The PEcAn.remote::rabbitmq_post_message function allows you to post messages to RabbitMQ from R. In the RabbitMQ documentation, it is known as a “producer”. It takes the body of the message to be posted and will return any output generated when the message is posted to the approriate queue. The function has three required arguments and two optional ones: uri – This is the URI used to connect to RabbitMQ, it will have the form amqp://username:password\\@server:5672/vhost. Most containers will have this injected using the environment variable RABBITMQ_URI. queue – The queue to post the message on, this is either pecan for a workflow to be exected, the name of the model and version to be executed, for example SIPNET_r136. message – The actual message to be send, this is of type list and will be converted to a json string representation. prefix – The code will talk to the rest api, this is the prefix of the rest api. In the case of the default docker-compse file, this will be /rabbitmq and will be injected as RABBITMQ_PREFIX. port – The code will talk to the rest api, this is the port of the rest api. In the case of the default docker-compse file, this will be 15672 and will be injected as RABBITMQ_PORT. The PEcAn.remote::start_rabbitmq function is a wrapper for this function that provides an easy way to post a folder message to RabbitMQ. 25.10.2 Consumer – receiver.py The receiver.py script runs like a daemon, constantly listening for messages. In the RabbitMQ documentation, it is known as a “consumer”. In PEcAn, you can tell that it is ready to receive messages if the corresponding logs (e.g. docker-compose logs executor) show the following message: [*] Waiting for messages. To exit press CTRL+C. Our reciever is configured by three environment variables: RABBITMQ_URI – This defines the URI where RabbitMQ is running. See corresponding argument in the producer RABBITMQ_QUEUE – This is the name of the queue on which the consumer will listen for messages, just as in the producer. APPLICATION – This specifies the name (including the path) of the default executable to run when receiving a message. At the moment, it should be an executable that runs in the directory specified by the message’s folder variable. In the case of PEcAn models, this is usually ./job.sh, such that the folder corresponds to the run directory associated with a particular runID (i.e. where the job.sh is located). For the PEcAn workflow itself, this is set to R CMD BATCH workflow.R, such that the folder is the root directory of the workflow (in the executor Docker container, something like /data/workflows/PEcAn_<workflowID>). This default executable is overridden if the message contains a custom_application key. If included, the string specified by the custom_application key will be run as a command exactly as is on the container, from the directory specified by folder. For instance, in the example below, the container will print “Hello there!” instead of running its default application. {"custom_application": "echo 'Hello there!'", "folder": "/path/to/my/dir"} NOTE that in RabbitMQ messages, the folder key is always required. 25.10.3 RabbitMQ and the PEcAn web interface RabbitMQ is configured by the following variables in config.php: $rabbitmq_host – The RabbitMQ server hostname (default: rabbitmq, because that is the name of the rabbitmq service in docker-compose.yml) $rabbitmq_port – The port on which RabbitMQ listens for messages (default: 5672) $rabbitmq_vhost – The path of the RabbitMQ Virtual Host (default: /). $rabbitmq_queue – The name of the RabbitMQ queue associated with the PEcAn workflow (default: pecan) $rabbitmq_username – The RabbitMQ username (default: guest) $rabbitmq_password – The RabbitMQ password (default: guest) In addition, for running models via RabbitMQ, you will also need to add an entry like the following to the config.php $hostlist: $hostlist=array($fqdn => array("rabbitmq" => "amqp://guest:guest@rabbitmq/%2F"), ...) This will set the hostname to the name of the current machine (defined by the $fqdn variable earlier in the config.php file) to an array with one entry, whose key is rabbitmq and whose value is the RabbitMQ URI (amqp://...). These values are converted into the appropriate entries in the pecan.xml in web/04-runpecan.php. 25.10.4 RabbitMQ in the PEcAn XML RabbitMQ is a special case of remote execution, so it is configured by the host node. An example RabbitMQ configuration is as follows: <host> <rabbitmq> <uri>amqp://guest:guest@rabbitmq/%2F</uri> <queue>sipnet_136</queue> </rabbitmq> </host> Here, uri and queue have the same general meanings as described in “producer”. Note that queue here refers to the target model. In PEcAn, RabbitMQ model queues are named as MODELTYPE_REVISION, so the example above refers to the SIPNET model version 136. Another example is ED2_git, referring to the latest git version of the ED2 model. 25.10.5 RabbitMQ configuration in Dockerfiles As described in the “consumer” section, our standard RabbitMQ receiver script is configured using three environment variables: RABBITMQ_URI, RABBITMQ_QUEUE, and APPLICATION. Therefore, configuring a container to work with PEcAn’s RabbitMQ instance requires setting these three variables in the Dockerfile using an ENV statement. For example, this excerpt from docker/base/Dockerfile.executor (for the pecan/executor image responsible for the PEcAn workflow) sets these variables as follows: ENV RABBITMQ_URI="amqp://guest:guest@rabbitmq/%2F" \\ RABBITMQ_QUEUE="pecan" \\ APPLICATION="R CMD BATCH workflow.R" Similarly, this excerpt from docker/models/Dockerfile.sipnet (which builds the SIPNET model image) is a typical example for a model image. Note the use of ARG here to specify a default version model version of 136 while allowing this to be configurable (via --build-arg MODEL_VERSION=X) at build time: ARG MODEL_VERSION=136 ENV APPLICATION="./job.sh" \\ MODEL_TYPE="SIPNET" \\ MODEL_VERSION="${MODEL_VERSION}" ENV RABBITMQ_QUEUE="${MODEL_TYPE}_${MODEL_VERSION}" WARNING: Dockerfile environment variables set via ENV are assigned all at once; they do not evaluate successively, left to right. Consider the following block: # Don't do this! ENV MODEL_TYPE="SIPNET" \\ MODEL_VERSION=136 \\ RABBITMQ_QUEUE=${MODEL_TYPE}_${MODEL_VERSION} # <- Doesn't know about MODEL_TYPE or MODEL_VERSION! In this block, the expansion for setting RABBITMQ_QUEUE is not aware of the current values of MODEL_TYPE or MODEL_VERSION, and will therefore be set incorrectly to just _ (unless they have been set previously, in which case it will be aware only of their earlier values). As such, variables depending on other variables must be set in a separate, subsequent ENV statement than the variables they depend on. 25.10.6 Case study: PEcAn web interface The following describes in general terms what happens during a typical run of the PEcAn web interface with RabbitMQ. The user initializes all containers with docker-compose up. All the services that interact with RabbitMQ (executor and all models) run receiver.py in the foreground, waiting for messages to tell them what to do. The user browses to http://pecan.localhost/pecan/ and steps through the web interface. All the pages up to the 04-runpecan.php run on the web container, and are primarily for setting up the pecan.xml file. Once the user starts the PEcAn workflow at 04-runpecan.php, the underlying PHP code connects to RabbitMQ (based on the URI provided in config.php) and posts the following message to the pecan queue: {"folder": "/workflows/PEcAn_WORKFLOWID", "workflowid": "WORKFLOWID"} The executor service, which is listening on the pecan queue, hears this message and executes its APPLICATION (R CMD BATCH workflow.R) in the working directory specified in the message’s folder. The executor service then performs the pre-execution steps (e.g. trait meta-analysis, conversions) itself. Then, to actually execute the model, executor posts the following message to the target model’s queue: {"folder": "/workflows/PEcAn_WORKFLOWID/run/RUNID"} The target model service, which is listening on its dedicated queue, hears this message and runs its APPLICATION, which is job.sh, in the directory indicated by the message. Upon exiting (normally), the model service writes its status into a file called rabbitmq.out in the same directory. The executor container continuously looks for the rabbitmq.out file as an indication of the model run’s status. Once it sees this file, it reads the status and proceeds with the post-execution parts of the workflow. (NOTE that this isn’t perfect. If the model running process exits abnormally, the rabbitmq.out file may not be created, which can cause the executor container to hang. If this happens, the solution is to restart the executor container with docker-compose restart executor). "],["pecan-remote.html", "26 Remote execution with PEcAn", " 26 Remote execution with PEcAn Remote execution allows the user to leverage the power and storage of high performance computing clusters, AWS instances, or specially configured virtual machines, but without leaving their local working environment. PEcAn uses remote execution primarily to run ecosystem models. The infrastructure for remote execution lives in the PEcAn.remote package (base/remote in the PEcAn repository). This section describes the following: Checking capabilities to connect to the remote machine correctly: Basics of command line SSH SSH authentication with keys and passwords Basics of SSH tunnels, and how they are used in PEcAn Description of PEcAn related tools that control remote execution Basic remote execution R functions in PEcAn.remote SETUP- Configuration Files and settings Remote model execution configuration in the pecan.xml and config.php Additional information about preparing remote servers for execution "],["basics-of-ssh.html", "26.1 Basics of SSH", " 26.1 Basics of SSH All of the PEcAn remote infrastructure depends on the system ssh utility, so it’s important to make sure this works before attempting the advanced remote execution functionality in PEcAn. To connect to a remote server interactively, the command is simply: ssh <username>@<hostname> For instance, my connection to the BU shared computing cluster looks like: ssh ashiklom@geo.bu.edu It will prompt me for my BU password, and, if successful, will drop me into a login shell on the remote machine. Alternatively to the login shell, ssh can be used to execute arbitrary code, whose output will be returned exactly as it would if you ran the command locally. For example, the following: ssh ashiklom@geo.bu.edu pwd will run the pwd command, and return the path to my home directory on the BU SCC. The more advanced example below will run some simple R code on the BU SCC and return the output as if it was run locally. ssh ashiklom@geo.bu.edu Rscript -e "seq(1, 10)" "],["ssh-authentication-password-vs.-ssh-key.html", "26.2 SSH authentication – password vs. SSH key", " 26.2 SSH authentication – password vs. SSH key Because this server uses passwords for authentication, this command will then prompt me for my password. An alternative to password authentication is using SSH keys. Under this system, the host machine (say, your laptop, or the PEcAn VM) has to generate a public and private key pair (using the ssh-keygen command). The private key (by default, a file in ~/.ssh/id_rsa) lives on the host machine, and should never be shared with anyone. The public key will be distributed to any remote machines to which you want the host to be able to connect. On each remote machine, the public key should be added to a list of authorized keys located in the ~/.ssh/authorized_keys file (on the remote machine). The authorized keys list indicates which machines (technically, which keys – a single machine, and even a single user, can have many keys) are allowed to connect to it. This is the system used by all of the PEcAn servers (pecan1, pecan2, test-pecan). "],["ssh-tunneling.html", "26.3 SSH tunneling", " 26.3 SSH tunneling SSH authentication can be more advanced than indicated above, especially on systems that require dual authentication. Even simple password-protection can be tricky in scripts, since (by design) it is fairly difficult to get SSH to accept a password from anything other than the raw keyboard input (i.e. SSH doesn’t let you pass passwords as input or arguments, because this exposes your password as plain text). A convenient and secure way to follow SSH security protocol, but prevent having to go through the full authentication process every time, is to use SSH tunnels (or “sockets”, which are effectively synonymous). Essentially, an SSH socket is a read- and write-protectected file that contains all of the information about an SSH connection. To create an SSH tunnel, use a command like the following: ssh -n -N -f -o ControlMaster=yes -S /path/to/socket/file <username>@<hostname> If appropriate, this will prompt you for your password (if using password authentication), and then will drop you back to the command line (thanks to the -N flag, which runs SSH without executing a command, the -f flag, which pushes SSH into the background, and the -n flag, which prevents ssh from reading any input). It will also create the file /path/to/socket/file. To use this socket with another command, use the -S /path/to/file flag, pointing to the same tunnel file you just created. ssh -S /path/to/socket/file <hostname> <optional command> This will let you access the server without any sort of authentication step. As before, if <optional command> is blank, you will be dropped into an interactive shell on the remote, or if it’s a command, that command will be executed and the output returned. To close a socket, use the following: ssh -S /path/to/socket/file <hostname> -O exit This will delete the socket file and close the connection. Alternatively, a scorched earth approach to closing the SSH tunnel if you don’t remember where you put the socket file is something like the following: pgrep ssh # See which processes will be killed pkill ssh # Kill those processes …which will kill all user processes called ssh. To automatically create tunnels following a specific pattern, you can add the following to your ~/.ssh/config Host <hostname goes here> ControlMaster auto ControlPath /tmp/%r@%h:%p For more information, see man ssh. "],["ssh-tunnels-and-pecan.html", "26.4 SSH tunnels and PEcAn", " 26.4 SSH tunnels and PEcAn Many of the PEcAn.remote functions assume that a tunnel is already open. If working from the web interface, the tunnel will be opened for you by some under-the-hood PHP and Bash code, but if debugging or working locally, you will have to create the tunnel yourself. The best way to do this is to create the tunnel first, outside of R, as described above. (In the following examples, I’ll use my username ashiklom connecting to the test-pecan server with a socket stored in /tmp/testpecan. To follow along, replace these with your own username and designated server, respectively). ssh -nNf -o ControlMaster=yes -S /tmp/testpecan ashiklom@test-pecan.bu.edu Then, in R, create a host object, which is just a list containing the elements name (hostname) and tunnel (path to tunnel file). my_host <- list(name = "test-pecan.bu.edu", tunnel = "/tmp/testpecan") This host object can then be used in any of the remote execution functions. "],["basic-remote-execute-functions.html", "26.5 Basic remote execute functions", " 26.5 Basic remote execute functions The PEcAn.remote::remote.execute.cmd function runs a system command on a remote server (or on the local server, if host$name == \"localhost\"). x <- PEcAn.remote::remote.execute.cmd(host = my_host, cmd = "echo", args = "Hello world") x Note that remote.execute.cmd is similar to base R’s system2, in that the base command (in this case, echo) is passed separately from its arguments (\"Hello world\"). Note also that the output of the remote command is returned as a character. For R code, there is a special wrapper around remote.execute.cmd – PEcAn.remote::remote.execute.R, which runs R code (passed as a string) on a remote and returns the output. code <- " x <- 2:4 y <- 3:1 x ^ y " out <- PEcAn.remote::remote.execute.R(code = code, host = my_host) For additional functions related to remote file operations and other stuff, see the PEcAn.remote package documentation. "],["remote-model-execution-with-pecan.html", "26.6 Remote model execution with PEcAn", " 26.6 Remote model execution with PEcAn The workhorse of remote model execution is the PEcAn.workflow::start_model_runs function, which distributes execution of each run in a list of runs (e.g. multiple runs in an ensemble) to the local machine or a remote based on the configuration in the PEcAn settings. Broadly, there are three major types of model execution: Serialized (PEcAn.remote::start_serial) – This runs models one at a time, directly on the local machine or remote (i.e. same as calling the executables one at a time for each run). Via a queue system, (PEcAn.remote::start_qsub) – This uses a queue management system, such as SGE (e.g. qsub, qstat) found on the BU SCC machines, to submit jobs. For computationally intensive tasks, this is the recommended way to go. Via a model launcher script (PEcAn.remote::setup_modellauncher) – This is a highly customizable approach where task submission is controlled by a user-provided script (launcher.sh). "],["xml-configuration.html", "26.7 XML configuration", " 26.7 XML configuration The relevant section of the PEcAn XML file is the <host> block. Here is a minimal example from one of my recent runs: <host> <name>geo.bu.edu</name> <user>ashiklom</user> <tunnel>/home/carya/output//PEcAn_99000000008/tunnel/tunnel</tunnel> </host> Breaking this down: name – The hostname of the machine where the runs will be performed. Set it to localhost to run on the local machine. user – Your username on the remote machine (note that this may be different from the username on your local machine). tunnel – This is the tunnel file for the connection used by all remote execution files. The tunnel is created automatically by the web interface, but must be created by the user for command line execution. This configuration will run in serialized mode. To use qsub, the configuration is slightly more involved: <host> <name>geo.bu.edu</name> <user>ashiklom</user> <qsub>qsub -V -N @NAME@ -o @STDOUT@ -e @STDERR@ -S /bin/bash</qsub> <qsub.jobid>Your job ([0-9]+) .*</qsub.jobid> <qstat>qstat -j @JOBID@ || echo DONE</qstat> <tunnel>/home/carya/output//PEcAn_99000000008/tunnel/tunnel</tunnel> </host> The additional fields are as follows: qsub – The command used to submit jobs to the queue system. Despite the name, this can be any command used for any queue system. The following variables are available to be set here: @NAME@ – Job name to display @STDOUT@ – File to which stdout will be redirected @STDERR@ – File to which stderr will be redirected qsub.jobid – A regular expression, from which the job ID will be determined. This string will be parsed by R as jobid <- gsub(qsub.jobid, \"\\\\1\", output) – note that the first pattern match is taken as the job ID. qstat – The command used to check the status of a job. Internally, PEcAn will look for the DONE string at the end, so a structure like <some command indicating if any jobs are still running> || echo DONE is required. The @JOBID@ here is the job ID determined from the qsub.jobid parsing. Documentation for using the model launcher is currently unavailable. "],["configuration-for-pecan-web-interface.html", "26.8 Configuration for PEcAn web interface", " 26.8 Configuration for PEcAn web interface The config.php has a few variables that will control where the web interface can run jobs, and how to run those jobs. It is located in the /web directory and if you have not touched it yet it will be named as config.example.php. Rename it to ’config.php` and edit by folowing the following directions. These variables are $hostlist, $qsublist, $qsuboptions, and $SSHtunnel. In the near future $hostlist, $qsublist, $qsuboptions will be combined into a single list. $SSHtunnel : points to the script that creates an SSH tunnel. The script is located in the web folder and the default value of dirname(__FILE__) . DIRECTORY_SEPARATOR . \"sshtunnel.sh\"; most likely will work. $hostlist : is an array with by default a single value, only allowing jobs to run on the local server. Adding any other servers to this list will show them in the pull down menu when selecting machines, and will trigger the web page to be show to ask for a username and password for the remote execution (make sure to use HTTPS setup when asking for password to prevent it from being send in the clear). $qsublist : is an array of hosts that require qsub to be used when running the models. This list can include $fqdn to indicate that jobs on the local machine should use qsub to run the models. $qsuboptions : is an array that lists options for each machine. Currently it support the following options (see also [Run Setup] and look at the tags) array("geo.bu.edu" => array("qsub" => "qsub -V -N @NAME@ -o @STDOUT@ -e @STDERR@ -S /bin/bash", "jobid" => "Your job ([0-9]+) .*", "qstat" => "qstat -j @JOBID@ || echo DONE", "job.sh" => "module load udunits R/R-3.0.0_gnu-4.4.6", "models" => array("ED2" => "module load hdf5")) In this list qsub is the actual command line for qsub, jobid is the text returned from qsub, qstat is the command to check to see if the job is finished. job.sh and the value in models are additional entries to add to the job.sh file generated to run the model. This can be used to make sure modules are loaded on the HPC cluster before running the actual model. "],["running-pecan-code-for-remotely.html", "26.9 Running PEcAn code for remotely", " 26.9 Running PEcAn code for remotely You do not need to download PEcAn fully on your remote machine. You can compile and install the model specific code pieces of PEcAn on the cluster easily without having to install the full code base of PEcAn (and all OS dependencies). Use the git clone command to: devtools::install_github("pecanproject/pecan", subdir = 'base/utils') Next we need to install the model specific pieces, this is done almost the same (example for ED2): devtools::install_github("pecanproject/pecan", subdir = 'models/ed') This should install dependencies required. The following are some notes on how to install the model specifics on different HPC clusters* "],["special-case-geo.bu.html", "26.10 Special case: geo.bu.edu", " 26.10 Special case: geo.bu.edu Following modules need to be loaded: module load hdf5 udunits R/R-3.0.0_gnu-4.4.6 Next the following packages need to be installed, otherwise it will fall back on the older versions install site-library install.packages(c('udunits2', 'lubridate'), configure.args=c(udunits2='--with-udunits2-lib=/project/earth/packages/udunits-2.1.24/lib --with-udunits2-include=/project/earth/packages/udunits-2.1.24/include')) Finally to install support for both ED and SIPNET: devtools::install_github("pecanproject/pecan", subdir = 'base/utils') devtools::install_github("pecanproject/pecan", subdir = 'models/sipnet') devtools::install_github("pecanproject/pecan", subdir = 'models/ed') "],["data-assimilation-with-dart.html", "27 Data assimilation with DART", " 27 Data assimilation with DART In addition to the state assimilation routines found in the assim.sequential module, another approach for state data assimilation in PEcAn is through the DART workflow created by the DARES group in NCAR. This section gives a straight-forward explanation how to implement DART, focused on the technical aspects of the implementation. If there are any questions, feel free to send @Viskari an email (tt.viskari@gmail.com) or contacting DART support as they are quite awesome in helping people with problems. Also, if there are any suggestions on how to improve the wiki, please let me know. Running with current folders in PEcAn Currently the DART folders in PEcAn are that you can simply copy the structure there over a downloaded DART workflow and it should replace/add relevant files and folders. The most important step after that is to check and change the run paths in the following files: Path_name files in the work folders T_ED2IN file, as it indicates where the run results be written. advance_model.csh, as it indicates where to copy files from/to. Second thing is setting the state vector size. This is explained in more detail below, but essentially this is governed by the variable model_size in model_mod.f90. In addition to this, it should be changed in utils/F2R.f90 and R2F.f90 programs, which are responsible for reading and writing state variable information for the different ensembles. This also will be expanded below. Finally, the new state vector size should be updated for any other executable that runs it. Third thing needed are the initial condition and observation sequence files. They will always follow the same format and are explained in more detail below. Finally the ensemble size, which is the easiest to change. In the work subfolder, there is a file named input.nml. Simply changing the ensemble size there will set it for the run itself. Also remember that initial conditions file should have the equal amount of state vectors as there are ensemble members. Adjusting the workflow The central file for the actual workflow is advance_model.csh. It is a script DART calls to determine how the state vector changes between the two observation times and is essentially the only file one needs to change when changing state models or observations operators. The file itself should be commented to give a good idea of the flow, but beneath is a crude order of events. 1. Create a temporary folder to run the model in and copy/link required files in to it. 2. Read in the state vector values and times from DART. Here it is important to note that the values will be in binary format, which need to be read in by a Fortran program. In my system, there is a program called F2R which reads in the binary values and writes out in ascii form the state vector values as well as which ED2 history files it needs to copy based on the time stamps. 3. Run the observation operator, which writes the state vector state in to the history files and adjusts them if necessary. 4. Run the program. 5. Read the new state vector values from output files. 6. Convert the state vector values to the binary. In my system, this is done by the program R2F. Initial conditions file The initial conditions file, commonly named filter_ics although you can set it to something else in input.nml, is relatively simple in structure. It has one sequence repeating over the number of ensemble members. First line contains two times: Seconds and days. Just use one of them in this situation, but it has to match the starting time given in input.nml. After that each line should contain a value from the state vector in the order you want to treat them. R functions filter_ics.R and B_filter_ics.R in the R folder give good examples of how to create these. Observations files The file which contains the observations is commonly known as obs_seq.out, although again the name of the file can be changed in input.nml. The structure of the file is relatively straight-forward and the R function ObsSeq.R in the R subfolder has the write structure for this. Instead of writing it out here, I want to focus on a few really important details in this file. Each observations will have a time, a value, an uncertainty, a location and a kind. The first four are self-explanatory, but the kind is really important, but also unfortunately really easy to misunderstand. In this file, the kind does not refer to a unit or a type of observation, but which member of the state vector is this observation of. So if the kind was, for example, 5, it would mean that it was of the fifth member of the state vector. However, if the kind value is positive, the system assumes that there is some sort of an operator change in comparing the observation and state vector value which is specified in a subprogram in model_mod.f90. So for an direct identity comparison between the observation and the state vector value, the kind needs to be negative number of the state vector component. Thus, again if the observation is of the fifth state vector value, the kind should be set as -5. Thus it is recommendable that the state vector values have already been altered to be comparable with the observations. As for location, there are many ways to set in DART and the method needs to be chosen when compiling the code by giving the program which of the location mods it is to use. In our examples we used a 1-dimensional location vector with scaled values between 0 and 1. For future it makes sense to switch to a 2 dimensional long- and lat-scale, but for the time being the location does not impact the system a lot. The main impact will be if the covariances will be localized, as that will be decided on their locations. State variable vector in DART Creating/adjusting a state variable vector in DART is relatively straight-forward. Below are listed the steps to specify a state variable vector in DART. I. For each specific model, there should be an own folder within the DART root models folder. In this folder there is a model_mod.f90, which contains the model specific subroutines necessary for a DART run. At the beginning of this file there should be the following line: integer, parameter :: model_size = [number] The number here should be the number of variables in the vector. So for example if there were three state variables, then the line should look like this: integer, parameter :: model_size = 3 This number should also be changed to match with any of the other executables called during the run as indicated by the list above. In the DART root, there should be a folder named obs_kind, which contains a file called DEFAULT_obs_kind_mod.F90. It is important to note that all changes should be done to this file instead of obs_kind_mod.f90, as during compilation DART creates obs_kind_mod.f90 from DEFAULT_obs_kind_mod.F90. This program file contains all the defined observation types used by DART and numbers them for easier reference later. Different types are classified according to observation instrument or relevant observation phenomenon. Adding a new type only requires finding an unused number and starting a new identifying line with the following: integer, parameter, public :: & KIND_… Note that the observation kind should always be easy to understand, so avoid using unnecessary acronyms. For example, when adding an observation type for Leaf Area Index, it would look like below: integer, parameter, public :: & KIND_LEAF_AREA_INDEX = [number] In the DART root, there should be a folder named obs_def, which contains several files starting with obs_def_. There files contain the different available observation kinds classified either according to observation instrument or observable system. Each file starts with the line ! BEGIN DART PREPROCESS KIND LIST And end with line ! END DART PREPROCESS KIND LIST The lines between these two should contain ! The desired observation reference, the observation type, COMMON_CODE. For example, for observations relating to phenology, I have created a file called obs_def_phen_mod.f90. In this file I define the Leaf Area Index observations in the following way. ! BEGIN DART PREPROCESS KIND LIST ! LAI, TYPE_LEAF_AREA_INDEX, COMMON_CODE ! END DART PREPROCESS KIND LIST Note that the exclamation marks are necessary for the file. In the model specific folder, in the work subfolder there is a namelist file input.nml. This contains all the run specific information for DART. In it, there is a subtitle &preprocess, under which there is a line input_files = ‘….’ This input_files sections must be set to refer to the obs_def file created in step III. The input files can contain references to multiple obs_def files if necessary. As an example, the reference to the obs_def_phen_mod.f90 would look like input_files = ‘../../../obs_def/obs_def_phen_mod.f90’ V. Finally, as an optional step, the different values in state vector can be typed. In model_mod, referred to in step I, there is a subroutine get_state_meta_data. In it, there is an input variable index_in, which refers to the vector component. So for instance for the second component of the vector index_in would be 2. If this is done, the variable kind has to be also included at the beginning of the model_mod.f90 file, at the section which begins use obs_kind_mod, only :: The location of the variable can be set, but for a 0-dimensional model we are discussing here, this is not necessary. Here, though, it is possible to set the variable types by including the following line if(index_in .eq. [number]) var_type = [One of the variable kinds set in step II] If the length of the state vector is changed, it is important that the script ran with DART produces a vector of that length. Change appropriately if necessary. After these steps, DART should be able to run with the state vector of interest. "],["miscellaneous.html", "28 Miscellaneous ", " 28 Miscellaneous "],["todo.html", "28.1 TODO", " 28.1 TODO Add list of developers "],["using-the-pecan-download_file-function.html", "28.2 Using the PEcAn download_file() function", " 28.2 Using the PEcAn download_file() function download_file(url, destination_file, method) This custom PEcAn function works together with the base R function download.file (https://stat.ethz.ch/R-manual/R-devel/library/utils/html/download.file.html). However, it provides expanded functionality to generalize the use for a broad range of environments. This is because some computing environments are behind a firewall or proxy, including FTP firewalls. This may require the use of a custom FTP program and/or initial proxy server authentication to retrieve the files needed by PEcAn (e.g. meteorology drivers, other inputs) to run certain model simulations or tools. For example, the Brookhaven National Laboratory (BNL) requires an initial connection to a FTP proxy before downloading files via FTP protocol. As a result, the computers running PEcAn behind the BNL firewall (e.g. https://modex.bnl.gov) use the ncftp cleint (http://www.ncftp.com/) to download files for PEcAn because the base options with R::base download.file() such as curl, libcurl which don’t have the functionality to provide credentials for a proxy or even those such as wget which do but don’t easily allow for connecting through a proxy server before downloading files. The current option for use in these instances is ncftp, specifically ncftpget Examples: HTTP download_file("http://lib.stat.cmu.edu/datasets/csb/ch11b.txt","~/test.download.txt") FTP download_file("ftp://ftp.cdc.noaa.gov/Datasets/NARR/monolevel/pres.sfc.2000.nc", "~/pres.sfc.2000.nc") customizing to use ncftp when running behind an FTP firewall (requires ncftp to be installed and availible) download_file("ftp://ftp.cdc.noaa.gov/Datasets/NARR/monolevel/pres.sfc.2000.nc", "~/pres.sfc.2000.nc", method=""ncftpget") On modex.bnl.gov, the ncftp firewall configuration file (e.g. ~/.ncftp/firewall) is configured as: firewall-type=1 firewall-host=ftpgateway.sec.bnl.local firewall-port=21 which then allows for direct connection through the firewall using a command like: ncftpget ftp://ftp.unidata.ucar.edu/pub/netcdf/netcdf-fortran-4.4.4.tar.gz To allow the use of ncftpget from within the download.file() function you need to set your R profile download.ftp.method option in your options list. To see your current R options run options() from R cmd, which should look something like this: > options() $add.smooth [1] TRUE $bitmapType [1] "cairo" $browser [1] "/usr/bin/xdg-open" $browserNLdisabled [1] FALSE $CBoundsCheck [1] FALSE $check.bounds [1] FALSE $citation.bibtex.max [1] 1 $continue [1] "+ " $contrasts unordered ordered "contr.treatment" "contr.poly" In order to set your download.ftp.method option you need to add a line such as # set default FTP options(download.ftp.method = "ncftpget") In your ~/.Rprofile. On modex at BNL we have set the global option in /usr/lib64/R/etc/Rprofile.site. Once this is done you should be able to see the option set using this command in R: > options("download.ftp.method") $download.ftp.method [1] "ncftpget" "],["faq.html", "29 FAQ", " 29 FAQ "],["pecan-project-used-in-courses.html", "30 PEcAn Project Used in Courses ", " 30 PEcAn Project Used in Courses "],["university-classes.html", "30.1 University classes", " 30.1 University classes 30.1.1 GE 375 - Environmental Modeling - Spring 2013, 2014 (Mike Dietze, Boston University) The final “Case Study: Terrestrial Ecosystem Models” is a PEcAn-based hands-on activity. Each class has been 25 students. GE 585 - Ecological forecasting Fall 2013 (Mike Dietze, Boston University) "],["summer-courses-workshops.html", "30.2 Summer Courses / Workshops", " 30.2 Summer Courses / Workshops 30.2.1 Annual summer course in flux measurement and advanced modeling (Mike Dietze, Ankur Desai) Niwot Ridge, CO About 1/3 lecture, 2/3 hands-on (the syllabus is actually wrong as it list the other way around). Each class has 24 students. 2013 Syllabus see Tuesday Week 2 Data Assimilation lectures and PEcAn demo and the Class projects and presentations on Thursday and Friday. (Most students use PEcAn for their group projects. 2014 will be the third year that PEcAn has been used for this course. 30.2.2 Assimilating Long-Term Data into Ecosystem Models: Paleo-Ecological Observatory Network (PalEON) Project Here is a link to the course: https://www3.nd.edu/~paleolab/paleonproject/summer-course/ This course uses the same demo as above, including collecting data in the field and assimilating it (part 3) 30.2.3 Integrating Evidence on Forest Response to Climate Change: Physiology to Regional Abundance http://blue.for.msu.edu/macrosystems/workshop May 13-14, 2013 Session 4: Integrating Forest Data Into Ecosystem Models 30.2.4 Ecological Society of America meetings Workshop: Combining Field Measurements and Ecosystem Models "],["selected-publications.html", "30.3 Selected Publications", " 30.3 Selected Publications Dietze, M.C., D.S LeBauer, R. Kooper (2013) On improving the communication between models and data. Plant, Cell, & Environment doi:10.1111/pce.12043 LeBauer, D.S., D. Wang, K. Richter, C. Davidson, & M.C. Dietze. (2013). Facilitating feedbacks between field measurements and ecosystem models. Ecological Monographs. doi:10.1890/12-0137.1 "],["package-dependencies.html", "31 Package Dependencies ", " 31 Package Dependencies "],["executive-summary-what-to-usually-do.html", "31.1 Executive Summary: What to usually do", " 31.1 Executive Summary: What to usually do When you’re editing one PEcAn package and want to use a function from any other R package (including other PEcAn packages), the standard method is to add the other package to the Imports: field of your DESCRIPTION file, spell the function in fully namespaced form (pkg::function()) everywhere you call it, and be done. There are a few cases where this isn’t enough, but they’re rarer than you think. The rest of this section mostly deals with the exceptions to this rule and why not to use them when they can be avoided. "],["big-picture-whats-possible-to-do.html", "31.2 Big Picture: What’s possible to do", " 31.2 Big Picture: What’s possible to do To make one PEcAn package use functionality from another R package (including other PEcAn packages), you must do at least one and up to four things in your own package. Always, declare which packages your package depends on, so that R can install them as needed when someone installs your package and so that human readers can understand what additional functionality it uses. Declare dependencies by manually adding them to your package’s DESCRIPTION file. Sometimes, import functions from the dependency package into your package’s namespace, so that your functions know where to find them. This is only sometimes necessary, because you can usually use :: to call functions without importing them. Import functions by writing Roxygen @importFrom statements and do not edit the NAMESPACE file by hand. Rarely, load dependency code into the R environment, so that the person using your package can use it without loading it separately. This is usually a bad idea, has caused many subtle bugs, and in PEcAn it should only be used when unavoidable. When unavoidable, prefer requireNamespace(... quietly = TRUE) over Depends: or require() or library(). Only if your dependency relies on non-R tools, install any components that R won’t know how to find for itself. These components are often but not always identifiable from a SystemRequirements field in the dependency’s DESCRIPTION file. The exact installation procedure will vary case by case and from one operating system to another, and for PEcAn the key point is that you should skip this step until it proves necessary. When it does prove necessary, edit the documentation for your package to include advice on installing the dependency components, then edit the PEcAn build and testing scripts as needed so that they follow your advice. The advice below about each step is written specifically for PEcAn, although much of it holds for R packages in general. For more details about working with dependencies, start with Hadley Wickham’s R packages and treat the CRAN team’s Writing R Extensions as the final authority. "],["declaring-dependencies-depends-suggests-imports.html", "31.3 Declaring Dependencies: Depends, Suggests, Imports", " 31.3 Declaring Dependencies: Depends, Suggests, Imports List all dependencies in the DESCRIPTION file. Every package that is used by your package’s code must appear in exactly one of the sections Depends, Imports, or Suggests. Please list packages in alphabetical order within each section. R doesn’t care about the order, but you will later when you’re trying to check whether this package uses a particular dependency. Imports is the correct place to declare most PEcAn dependencies. This ensures that they get installed, but does not automatically import any of their functions – Since PEcAn style prefers to mostly use :: instead of importing, this is what we want. Depends is, despite the name, usually the wrong place to declare PEcAn dependencies. The only difference between Depends and Imports is that when the user attaches your packages to their own R workspace (e.g. using library(\"PEcAn.yourpkg\")), the packages in Depends are attached as well. Notice that a call like PEcAn.yourpkg::yourfun() will not attach your package or its dependencies, so your code still needs to import or ::-qualify all functions from packages listed in Depends. In short, Depends is not a shortcut, is for user convenience not developer convenience, and makes it easy to create subtle bugs that appear to work during interactive test sessions but fail when run from scripts. As the R extensions manual puts it (emphasis added): This [Imports and Depends] scheme was developed before all packages had namespaces (R 2.14.0 in October 2011), and good practice changed once that was in place. Field ‘Depends’ should nowadays be used rarely, only for packages which are intended to be put on the search path to make their facilities available to the end user (and not to the package itself).” The Suggests field can be used to declare dependencies on packages that make your package more useful but are not completely essential. Again from the R extensions manual: The Suggests field uses the same syntax as Depends and lists packages that are not necessarily needed. This includes packages used only in examples, tests or vignettes (see Writing package vignettes), and packages loaded in the body of functions. E.g., suppose an example from package foo uses a dataset from package bar. Then it is not necessary to have bar use foo unless one wants to execute all the examples/tests/vignettes: it is useful to have bar, but not necessary. Some of the PEcAn model interface packages push this definition of “not necessarily needed” by declaring their coupled model package in Suggests rather than Imports. For example, the PEcAn.BIOCRO package cannot do anything useful when the BioCro model is not installed, but it lists BioCro in Suggests because PEcAn as a whole can work without it. This is a compromise to simplify installation of PEcAn for users who only plan to use a few models, so that they can avoid the bother of installing BioCro if they only plan to run, say, SIPNET. Since the point of Suggests is that they are allowed to be missing, all code that uses a suggested package must behave reasonably when the package is not found. Depending on the situation, “reasonably” could mean checking whether the package is available and throwing an error as needed (PEcAn.BIOCRO uses its .onLoad function to check at load time whether BioCro is installed and will refuse to load if it is not), or providing an alternative behavior (PEcAn.data.atmosphere::get_NARR_thredds checks at call time for either parallel or doParallel and uses whichever one it finds first), or something else, but your code should never just assume that the suggested package is available. You are not allowed to import functions from Suggests into your package’s namespace, so always call them in ::-qualified form. By default R will not install suggested packages when your package is installed, but users can change this using the dependencies argument of install.packages. Note that for testing on Travis CI, PEcAn does install all Suggests (because they are required for full package checks), so any of your code that runs when a suggested package is not available will never be exercised by Travis checks. It is often tempting to move a dependency from Imports to Suggests because it is a hassle to install (large, hard to compile, no longer available from CRAN, currently broken on GitHub, etc), in the hopes that this will isolate the rest of PEcAn from the troublesome dependency. This helps for some cases, but fails for two very common ones: It does not reduce install time for CI builds, because all suggested packages need to be present when running full package checks (R CMD check or devtools::check or make check). It also does not prevent breakage when updating PEcAn via make install, because devtools::install_deps does not install suggested packages that are missing but does try to upgrade any that are already installed to the newest available version – even if the installed version took ages to compile and would have worked just fine! "],["importing-functions-use-roxygen.html", "31.4 Importing Functions: Use Roxygen", " 31.4 Importing Functions: Use Roxygen PEcAn style is to import very few functions and instead use fully namespaced function calls (pkg::fn()) everywhere it’s practical to do so. In cases where double-colon notation would be especially burdensome, such as when importing custom binary operators like %>%, it’s acceptable to import specific functions into the package namespace. Do this by using Roxygen comments of the form #' @importFrom pkg function, not by hand-editing the NAMESPACE file. If the import is only used in one or a few functions, use an @importFrom in the documentation for each function that uses it. If it is used all over the package, use a single @importFrom in the Roxygen documentation block for the whole package, which probably lives in a file called either zzz.R or <your_package_name>-package.R: #' What your package does #' #' Longer description of the package goes here. #' Probably with links to other resources about it, citations, etc. #' #' @docType package #' @name PEcAn.yourpkg #' @importFrom magrittr %>% NULL Roxygen will make sure there’s only one NAMESPACE entry per imported function no matter how many importFrom statements there are, but please pick a scheme (either import on every usage or once for the whole package), stick with it, and do not make function x() rely on an importFrom in the comments above function y(). Please do not import entire package namespaces (#' @import pkg); it increases the chance of function name collisions and makes it much harder to understand which package a given function was called from. A special note about importing functions from the tidyverse: Be sure to import from the package(s) that actually contain the functions you want to use, e.g. Imports: dplyr, magrittr, purrr / @importFrom magrittr %>% / purrr::map(...), not Imports: tidyverse / @importFrom tidyverse %>% / tidyverse::map(...). The package named tidyverse is just a interactive shortcut that loads the whole collection of constituent packages; it doesn’t export any functions in its own namespace and therefore importing it into your package doesn’t make them available. "],["loading-code-dont-but-use-requirenamespace-when-you-do.html", "31.5 Loading Code: Don’t… But Use requireNamespace When You Do", " 31.5 Loading Code: Don’t… But Use requireNamespace When You Do The very short version of this section: We want to maintain clear separation between the package’s namespace (which we control and want to keep predictable) and the global namespace (which the user controls, might change in ways we have no control over, and will be justifiably angry if we change it in ways they were not expecting). Therefore, avoid attaching packages to the search path (so no Depends and no library() or require() inside functions), and do not explicitly load other namespaces if you can help it. The longer version requires that we make a distinction often glossed over: Loading a package makes it possible for R to find things in the package namespace and does any actions needed to make it ready for use (e.g. running its .onLoad method, loading DLLs if the package contains compiled code, etc). Attaching a package (usually by calling library(\"somePackage\")) loads it if it wasn’t already loaded, and then adds it to the search path so that the user can find things in its namespace. As discussed in the “Declaring Dependancies” section above, dependencies listed in Depends will be attached when your package is attached, but they will be neither attached nor loaded when your package is loaded without being attached. Loading a dependency into the package namespace is undesirable because it makes it hard to understand our own code – if we need to use something from elsewhere, we’d prefer call it from its own namespace using :: (which implicitly loads the dependency!) or explicitly import it with a Roxygen @import directive. But in a few cases this isn’t enough. The most common reason to need to explicitly load a dependency is that some packages define new S3 methods for generic functions defined in other packages, but do not export these methods directly. We would prefer that these packages did not do this, but sometimes we have to use them anyway. An example from PEcAn is that PEcAn.MA needs to call as.matrix on objects of class mcmc.list. When the coda namespace is loaded, as.matrix(some_mcmc.list) can be correctly dispatched by base::as.matrix to the unexported method coda:::as.matrix.mcmc.list, but when coda is not loaded this dispatch will fail. Unfortunately coda does not export as.matrix.mcmc.list so we cannot call it directly or import it into the PEcAn.MA namespace, so instead we load the coda namespace whenever PEcAn.MA is loaded. Attaching packages to the user’s search path is even more problematic because it makes it hard for the user to understand how your package will affect their own code. Packages attached by a function stay attached after the function exits, so they can cause name collisions far downstream of the function call, potentially in code that has nothing to do with your package. And worse, since names are looked up in reverse order of package loading, it can cause behavior that differs in strange ways depending on the order of lines that look independent of each other: library(Hmisc) x = ... y = 3 summarize(x) # calls Hmisc::summarize y2 <- some_package_that_attaches_dplyr::innocent.looking.function(y) # Loading required package: dplyr summarize(x) # Looks identical to previous summarize, but calls dplyr::summarize! This is not to say that users will never want your package to attach another one for them, just that it’s rare and that attaching dependencies is much more likely to cause bugs than to fix them and additionally doesn’t usually save the package author any work. One possible exception to the do-not-attach-packages rule is a case where your dependency ignores all good practice and wrongly assumes, without checking, that all of its own dependencies are attached; if its DESCRIPTION uses only Depends instead of Imports, this is often a warning sign. For example, a small-but-surprising number of packages depend on the methods package without proper checks (this is probably because most but not all R interpreters attach methods by default and therefore it’s easy for an author to forget it might ever be otherwise unless they happen to test with a but-not-all interpreter). If you find yourself with a dependency that does this, accept first that you are relying on a package that is broken, and you should either convince its maintainer to fix it or find a way to remove the dependency from PEcAn. But as a short-term workaround, it is sometimes possible for your code to attach the direct dependency so that it will behave right with regard to its secondary dependencies. If so, make sure the attachment happens every time your package is loaded (e.g. by calling library(depname) inside your package’s .onLoad method) and not just when your package is attached (e.g. by putting it in Depends). When you do need to load or attach a dependency, it is probably better to do it inside your package’s .onLoad method rather than in individual functions, but this isn’t ironclad. To only load, use requireNamespace(pkgname, quietly=TRUE) – this will make it available inside your package’s namespace while avoiding (most) annoying loadtime messages and not disturbing the user’s search path. To attach when you really can’t avoid it, declare the dependency in Depends and also attach it using library(pkgname) in your .onLoad method. Note that scripts in inst/ are considered to be sample code rather than part of the package namespace, so it is acceptable for them to explicitly attach packages using library(). You may also see code that uses require(pkgname); this is just like library, but returns FALSE instead of erroring if package load fails. It is OK for scripts in inst/ that can do and do do something useful when a dependency is missing, but if it is used as if(!require(pkg)){ stop(...)} then replace it with library(pkg). If you think your package needs to load or attach code for any reason, please note why in your pull request description and be prepared for questions about it during code review. If your reviewers can think of an alternate approach that avoids loading or attaching, they will likely ask you to use it even if it creates extra work for you. "],["installing-dependencies-let-the-machines-do-it.html", "31.6 Installing dependencies: Let the machines do it", " 31.6 Installing dependencies: Let the machines do it In most cases you won’t need to think about how dependencies get installed – just declare them in your package’s DESCRIPTION and the installation will be handled automatically by R and devtools during the build process. The main exception is when a dependency relies on non-R software that R does not know how to install automatically. For example, rjags relies on JAGS, which might be installed in a different place on every machine. If your dependency falls in this category, you will know (because your CI builds will keep failing until you figure out how to fix it), but the exact details of the fix will differ for every case. "],["appendix-testthat.html", "32 Testing with the testthat package", " 32 Testing with the testthat package Tests are found in <package>/tests/testthat/ (for example, base/utils/inst/tests/) See attached file and http://r-pkgs.had.co.nz/tests.html for details on how to use the testthat package. "],["list-of-expectations.html", "32.1 List of Expectations", " 32.1 List of Expectations Full Abbreviation expect_that(x, is_true()) expect_true(x) expect_that(x, is_false()) expect_false(x) expect_that(x, is_a(y)) expect_is(x, y) expect_that(x, equals(y)) expect_equal(x, y) expect_that(x, is_equivalent_to(y)) expect_equivalent(x, y) expect_that(x, is_identical_to(y)) expect_identical(x, y) expect_that(x, matches(y)) expect_matches(x, y) expect_that(x, prints_text(y)) expect_output(x, y) expect_that(x, shows_message(y)) expect_message(x, y) expect_that(x, gives_warning(y)) expect_warning(x, y) expect_that(x, throws_error(y)) expect_error(x, y) "],["basic-use-of-the-testthat-package.html", "32.2 Basic use of the testthat package", " 32.2 Basic use of the testthat package Create a file called <packagename>/tests/testthat.R with the following contents: library(testthat) library(mypackage) test_check("mypackage") Tests should be placed in <packagename>/tests/testthat/test-<sourcefilename>.R, and look like the following: test_that("mathematical operators plus and minus work as expected",{ expect_equal(sum(1,1), 2) expect_equal(sum(-1,-1), -2) expect_equal(sum(1,NA), NA) expect_error(sum("cat")) set.seed(0) expect_equal(sum(matrix(1:100)), sum(data.frame(1:100))) }) test_that("different testing functions work, giving excuse to demonstrate",{ expect_identical(1, 1) expect_identical(numeric(1), integer(1)) expect_equivalent(numeric(1), integer(1)) expect_warning(mean('1')) expect_that(mean('1'), gives_warning("argument is not numeric or logical: returning NA")) expect_warning(mean('1'), "argument is not numeric or logical: returning NA") expect_message(message("a"), "a") }) "],["data-for-tests.html", "32.3 Data for tests", " 32.3 Data for tests Many of PEcAn’s functions require inputs that are provided as data. These can be in the data or the inst/extdata folders of a package. Data that are not package specific should be placed in the PEcAn.all (base/all) or PEcAn.utils (base/utils) packages. Some useful conventions: "],["settings-1.html", "32.4 Settings", " 32.4 Settings A generic settings can be found in the PEcAn.all package settings.xml <- system.file("pecan.biocro.xml", package = "PEcAn.BIOCRO") settings <- read.settings(settings.xml) database settings can be specified, and tests run only if a connection is available We currently use the following database to run tests against; tests that require access to a database should check db.exists() and be skipped if it returns FALSE to avoid failed tests on systems that do not have the database installed. settings$database <- list(userid = "bety", passwd = "bety", name = "bety", # database name host = "localhost" # server name) test_that(..., { skip_if_not(db.exists(settings$database)) ## write tests here }) instructions for installing this are available on the VM creation wiki examples can be found in the PEcAn.DB package (base/db/tests/testthat/). Model specific settings can go in the model-specific module, for example: settings.xml <- system.file("extdata/pecan.biocro.xml", package = "PEcAn.BIOCRO") settings <- read.settings(settings.xml) test-specific settings: settings text can be specified inline: settings.text <- " <pecan> <nocheck>nope</nocheck> ## allows bypass of checks in the read.settings functions <pfts> <pft> <name>ebifarm.pavi</name> <outdir>test/</outdir> </pft> </pfts> <outdir>test/</outdir> <database> <userid>bety</userid> <passwd>bety</passwd> <location>localhost</location> <name>bety</name> </database> </pecan>" settings <- read.settings(settings.text) values in settings can be updated: settings <- read.settings(settings.text) settings$outdir <- "/tmp" ## or any other settings "],["helper-functions-for-unit-tests.html", "32.5 Helper functions for unit tests", " 32.5 Helper functions for unit tests PEcAn.utils::tryl returns FALSE if function gives error PEcAn.utils::temp.settings creates temporary settings file PEcAn.DB::db.exists returns TRUE if connection to database is available "],["developer-devtools.html", "33 devtools package", " 33 devtools package Provides functions to simplify development Documentation: The R devtools package load_all("pkg") document("pkg") test("pkg") install("pkg") build("pkg") other tips for devtools (from the documentation): Adding the following to your ~/.Rprofile will load devtools when running R in interactive mode: # load devtools by default if (interactive()) { suppressMessages(require(devtools)) } Adding the following to your .Rpackages will allow devtools to recognize package by folder name, rather than directory path # in this example, devhome is the pecan trunk directory devhome <- "/home/dlebauer/R-dev/pecandev/" list( default = function(x) { file.path(devhome, x, x) }, "utils" = paste(devhome, "pecandev/utils", sep = "") "common" = paste(devhome, "pecandev/common", sep = "") "all" = paste(devhome, "pecandev/all", sep = "") "ed" = paste(devhome, "pecandev/models/ed", sep = "") "uncertainty" = paste(devhome, "modules/uncertainty", sep = "") "meta.analysis" = paste(devhome, "modules/meta.analysis", sep = "") "db" = paste(devhome, "db", sep = "") ) Now, devtools can take pkg as an argument instead of /path/to/pkg/, e.g. so you can use build(\"pkg\") instead of build(\"/path/to/pkg/\") "],["models_singularity.html", "34 singularity", " 34 singularity Running a model using singularity. This is work in progress. This assumes you have singulariy already installed. This will work on a Linux machine (x86_64). First make sure you have all the data files: bash script to install required files (click to expand) #!/bin/bash if [ ! -e sites ]; then curl -s -o sites.tgz http://isda.ncsa.illinois.edu/~kooper/EBI/sites.tgz tar zxf sites.tgz sed -i -e "s#/home/kooper/Projects/EBI#/data/sites#" sites/*/ED_MET_DRIVER_HEADER rm sites.tgz fi if [ ! -e inputs ]; then curl -s -o inputs.tgz http://isda.ncsa.illinois.edu/~kooper/EBI/inputs.tgz tar zxf inputs.tgz rm inputs.tgz fi if [ ! -e testrun.s83 ]; then curl -s -o testrun.s83.zip http://isda.ncsa.illinois.edu/~kooper/EBI/testrun.s83.zip unzip -q testrun.s83.zip sed -i -e "s#/home/pecan#/data#" testrun.s83/ED2IN rm testrun.s83.zip fi if [ ! -e ${HOME}/sites/Santarem_Km83 ]; then curl -s -o Santarem_Km83.zip http://isda.ncsa.illinois.edu/~kooper/EBI/Santarem_Km83.zip unzip -q -d sites Santarem_Km83.zip sed -i -e "s#/home/pecan#/data#" sites/Santarem_Km83/ED_MET_DRIVER_HEADER rm Santarem_Km83.zip fi Next edit the ED2IN file in testrun.s83 ED2IN file (click to expand) !==========================================================================================! !==========================================================================================! ! ED2IN . ! ! ! ! This is the file that contains the variables that define how ED is to be run. There ! ! is some brief information about the variables here. ! !------------------------------------------------------------------------------------------! $ED_NL !----- Simulation title (64 characters). -----------------------------------------------! NL%EXPNME = 'ED version 2.1 test' !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! Type of run: ! ! INITIAL -- Starts a new run, that can be based on a previous run (restart/history), ! ! but then it will use only the biomass and soil carbon information. ! ! HISTORY -- Resumes a simulation from the last history. This is different from ! ! initial in the sense that exactly the same information written in the ! ! history will be used here. ! !---------------------------------------------------------------------------------------! NL%RUNTYPE = 'INITIAL' !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! Start of simulation. Information must be given in UTC time. ! !---------------------------------------------------------------------------------------! NL%IMONTHA = 01 NL%IDATEA = 01 NL%IYEARA = 2001 NL%ITIMEA = 0000 !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! End of simulation. Information must be given in UTC time. ! !---------------------------------------------------------------------------------------! NL%IMONTHZ = 01 NL%IDATEZ = 01 NL%IYEARZ = 2002 NL%ITIMEZ = 0000 !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! DTLSM -- Time step to integrate photosynthesis, and the maximum time step for ! ! integration of energy and water budgets (units: seconds). Notice that the ! ! model will take steps shorter than this if this is too coarse and could ! ! lead to loss of accuracy or unrealistic results in the biophysics. ! ! Recommended values are < 60 seconds if INTEGRATION_SCHEME is 0, and 240-900 ! ! seconds otherwise. ! ! RADFRQ -- Time step to integrate radiation, in seconds. This must be an integer ! ! multiple of DTLSM, and we recommend it to be exactly the same as DTLSM. ! !---------------------------------------------------------------------------------------! NL%DTLSM = 600. NL%RADFRQ = 600. !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! The following variables are used in case the user wants to run a regional run. ! ! ! ! N_ED_REGION -- number of regions for which you want to run ED. This can be set to ! ! zero provided that N_POI is not... ! ! GRID_TYPE -- which kind of grid to run: ! ! 0. Longitude/latitude grid ! ! 1. Polar-stereographic ! !---------------------------------------------------------------------------------------! NL%N_ED_REGION = 0 NL%GRID_TYPE = 1 !------------------------------------------------------------------------------------! ! The following variables are used only when GRID_TYPE is set to 0. You must ! ! provide one value for each grid, except otherwise noted. ! ! ! ! GRID_RES -- Grid resolution, in degrees (first grid only, the other grids ! ! resolution will be defined by NSTRATX/NSTRATY). ! ! ED_REG_LATMIN -- Southernmost point of each region. ! ! ED_REG_LATMAX -- Northernmost point of each region. ! ! ED_REG_LONMIN -- Westernmost point of each region. ! ! ED_REG_LONMAX -- Easternmost point of each region. ! !------------------------------------------------------------------------------------! NL%GRID_RES = 1.0 NL%ED_REG_LATMIN = -12.0, -7.5, 10.0, -6.0 NL%ED_REG_LATMAX = 1.0, -3.5, 15.0, -1.0 NL%ED_REG_LONMIN = -66.0,-58.5, 70.0, -63.0 NL%ED_REG_LONMAX = -49.0,-54.5, 35.0, -53.0 !------------------------------------------------------------------------------------! !------------------------------------------------------------------------------------! ! The following variables are used only when GRID_TYPE is set to 1. ! ! ! ! NNXP -- number of points in the X direction. One value for each grid. ! ! NNYP -- number of points in the Y direction. One value for each grid. ! ! DELTAX -- grid resolution in the X direction, near the grid pole. Units: [ m]. ! ! this value is used to define the first grid only, other grids are ! ! defined using NNSTRATX. ! ! DELTAY -- grid resolution in the Y direction, near the grid pole. Units: [ m]. ! ! this value is used to define the first grid only, other grids are ! ! defined using NNSTRATX. Unless you are running some specific tests, ! ! both DELTAX and DELTAY should be the same. ! ! POLELAT -- Latitude of the pole point. Set this close to CENTLAT for a more ! ! traditional "square" domain. One value for all grids. ! ! POLELON -- Longitude of the pole point. Set this close to CENTLON for a more ! ! traditional "square" domain. One value for all grids. ! ! CENTLAT -- Latitude of the central point. One value for each grid. ! ! CENTLON -- Longitude of the central point. One value for each grid. ! !------------------------------------------------------------------------------------! NL%NNXP = 110 NL%NNYP = 70 NL%DELTAX = 60000. NL%DELTAY = 60000. NL%POLELAT = -2.609075 NL%POLELON = -60.2093 NL%CENTLAT = -2.609075 NL%CENTLON = -60.2093 !------------------------------------------------------------------------------------! !------------------------------------------------------------------------------------! ! Nest ratios. These values are used by both GRID_TYPE=0 and GRID_TYPE=1. ! ! NSTRATX -- this is will divide the values given by DELTAX or GRID_RES for the ! ! nested grids. The first value should be always one. ! ! NSTRATY -- this is will divide the values given by DELTAY or GRID_RES for the ! ! nested grids. The first value should be always one, and this must ! ! be always the same as NSTRATX when GRID_TYPE = 0, and this is also ! ! strongly recommended for when GRID_TYPE = 1. ! !------------------------------------------------------------------------------------! NL%NSTRATX = 1,4 NL%NSTRATY = 1,4 !------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! The following variables are used to define single polygon of interest runs, and ! ! they are ignored when N_ED_REGION = 0. ! ! ! ! N_POI -- number of polygons of interest (POIs). This can be zero as long as ! ! N_ED_REGION is not. ! ! POI_LAT -- list of latitudes of each POI. ! ! POI_LON -- list of longitudes of each POI. ! ! POI_RES -- grid resolution of each POI (degrees). This is used only to define the ! ! soil types ! !---------------------------------------------------------------------------------------! NL%N_POI = 1 NL%POI_LAT = -3.018 NL%POI_LON = -54.971 NL%POI_RES = 1.00 !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! LOADMETH -- Load balancing method. This is used only in regional runs run in ! ! parallel. ! ! 0. Let ED decide the best way of splitting the polygons. Commonest ! ! option and default. ! ! 1. One of the methods to split polygons based on their previous ! ! work load. Developpers only. ! ! 2. Try to load an equal number of SITES per node. Useful for when ! ! total number of polygon is the same as the total number of cores. ! ! 3. Another method to split polygons based on their previous work load. ! ! Developpers only. ! !---------------------------------------------------------------------------------------! NL%LOADMETH = 0 !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! ED2 File output. For all the variables 0 means no output and 3 means HDF5 output. ! ! ! ! IFOUTPUT -- Fast analysis. These are mostly polygon-level averages, and the time ! ! interval between files is determined by FRQANL ! ! IDOUTPUT -- Daily means (one file per day) ! ! IMOUTPUT -- Monthly means (one file per month) ! ! IQOUTPUT -- Monthly means of the diurnal cycle (one file per month). The number ! ! of points for the diurnal cycle is 86400 / FRQANL ! ! IYOUTPUT -- Annual output. ! ! ITOUTPUT -- Instantaneous fluxes, mostly polygon-level variables, one file per year. ! ! ISOUTPUT -- restart file, for HISTORY runs. The time interval between files is ! ! determined by FRQHIS ! !---------------------------------------------------------------------------------------! NL%IFOUTPUT = 0 NL%IDOUTPUT = 0 NL%IMOUTPUT = 0 NL%IQOUTPUT = 3 NL%IYOUTPUT = 0 NL%ITOUTPUT = 0 NL%ISOUTPUT = 3 !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! ATTACH_METADATA -- Flag for attaching metadata to HDF datasets. Attaching metadata ! ! will aid new users in quickly identifying dataset descriptions but ! ! will compromise I/O performance significantly. ! ! 0 = no metadata, 1 = attach metadata ! !---------------------------------------------------------------------------------------! NL%ATTACH_METADATA = 0 !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! UNITFAST -- The following variables control the units for FRQFAST/OUTFAST, and ! ! UNITSTATE FRQSTATE/OUTSTATE, respectively. Possible values are: ! ! 0. Seconds; ! ! 1. Days; ! ! 2. Calendar months (variable) ! ! 3. Calendar years (variable) ! ! ! ! N.B.: 1. In case OUTFAST/OUTSTATE are set to special flags (-1 or -2) ! ! UNITFAST/UNITSTATE will be ignored for them. ! ! 2. In case IQOUTPUT is set to 3, then UNITFAST has to be 0. ! ! ! !---------------------------------------------------------------------------------------! NL%UNITFAST = 0 NL%UNITSTATE = 3 !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! OUTFAST/OUTSTATE -- these control the number of times per file. ! ! 0. Each time gets its own file ! ! -1. One file per day ! ! -2. One file per month ! ! > 0. Multiple timepoints can be recorded to a single file reducing ! ! the number of files and i/o time in post-processing. ! ! Multiple timepoints should not be used in the history files ! ! if you intend to use these for HISTORY runs. ! !---------------------------------------------------------------------------------------! NL%OUTFAST = 1. NL%OUTSTATE = 1. !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! ICLOBBER -- What to do in case the model finds a file that it was supposed the ! ! written? 0 = stop the run, 1 = overwrite without warning. ! ! FRQFAST -- time interval between analysis files, units defined by UNITFAST. ! ! FRQSTATE -- time interval between history files, units defined by UNITSTATE. ! !---------------------------------------------------------------------------------------! NL%ICLOBBER = 1 NL%FRQFAST = 3600. NL%FRQSTATE = 1. !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! FFILOUT -- Path and prefix for analysis files (all but history/restart). ! ! SFILOUT -- Path and prefix for history files. ! !---------------------------------------------------------------------------------------! NL%FFILOUT = '/data/testrun.s83/analy/ts83' NL%SFILOUT = '/data/testrun.s83/histo/ts83' !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! IED_INIT_MODE -- This controls how the plant community and soil carbon pools are ! ! initialised. ! ! ! ! -1. Start from a true bare ground run, or an absolute desert run. This will ! ! never grow any plant. ! ! 0. Start from near-bare ground (only a few seedlings from each PFT to be included ! ! in this run). ! ! 1. This will use history files written by ED-1.0. It will grab the ecosystem ! ! state (like biomass, LAI, plant density, etc.), but it will start the ! ! thermodynamic state as a new simulation. ! ! 2. Same as 1, but it uses history files from ED-2.0 without multiple sites, and ! ! with the old PFT numbers. ! ! 3. Same as 1, but using history files from ED-2.0 with multiple sites and ! ! TOPMODEL hydrology. ! ! 4. Same as 1, but using ED2.1 H5 history/state files that take the form: ! ! 'dir/prefix-gxx.h5' ! ! Initialization files MUST end with -gxx.h5 where xx is a two digit integer ! ! grid number. Each grid has its own initialization file. As an example, if a ! ! user has two files to initialize their grids with: ! ! example_file_init-g01.h5 and example_file_init-g02.h5 ! ! NL%SFILIN = 'example_file_init' ! ! ! ! 5. This is similar to option 4, except that you may provide several files ! ! (including a mix of regional and POI runs, each file ending at a different ! ! date). This will not check date nor grid structure, it will simply read all ! ! polygons and match the nearest neighbour to each polygon of your run. SFILIN ! ! must have the directory common to all history files that are sought to be used,! ! up to the last character the files have in common. For example if your files ! ! are ! ! /mypath/P0001-S-2000-01-01-000000-g01.h5, ! ! /mypath/P0002-S-1966-01-01-000000-g02.h5, ! ! ... ! ! /mypath/P1000-S-1687-01-01-000000-g01.h5: ! ! NL%SFILIN = '/mypath/P' ! ! ! ! 6 - Initialize with ED-2 style files without multiple sites, exactly like option ! ! 2, except that the PFT types are preserved. ! !---------------------------------------------------------------------------------------! NL%IED_INIT_MODE = 6 !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! EDRES -- Expected input resolution for ED2.0 files. This is not used unless ! ! IED_INIT_MODE = 3. ! !---------------------------------------------------------------------------------------! NL%EDRES = 1.0 !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! SFILIN -- The meaning and the size of this variable depends on the type of run, set ! ! at variable NL%RUNTYPE. ! ! ! ! 1. INITIAL. Then this is the path+prefix of the previous ecosystem state. This has ! ! dimension of the number of grids so you can initialize each grid with a ! ! different dataset. In case only one path+prefix is given, the same will ! ! be used for every grid. Only some ecosystem variables will be set up ! ! here, and the initial condition will be in thermodynamic equilibrium. ! ! ! ! 2. HISTORY. This is the path+prefix of the history file that will be used. Only the ! ! path+prefix will be used, as the history for every grid must have come ! ! from the same simulation. ! !---------------------------------------------------------------------------------------! NL%SFILIN = '/data/sites/Santarem_Km83/s83_default.' !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! History file information. These variables are used to continue a simulation from ! ! a point other than the beginning. Time must be in UTC. ! ! ! ! IMONTHH -- the time of the history file. This is the only place you need to change ! ! IDATEH dates for a HISTORY run. You may change IMONTHZ and related in case you ! ! IYEARH want to extend the run, but yo should NOT change IMONTHA and related. ! ! ITIMEH ! !---------------------------------------------------------------------------------------! NL%ITIMEH = 0000 NL%IDATEH = 01 NL%IMONTHH = 05 NL%IYEARH = 2001 !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! NZG - number of soil layers. One value for all grids. ! ! NZS - maximum number of snow/water pounding layers. This is used only for ! ! snow, if only liquid water is standing, the water will be all collapsed ! ! into a single layer, so if you are running for places where it doesn't snow ! ! a lot, leave this set to 1. One value for all grids. ! !---------------------------------------------------------------------------------------! NL%NZG = 16 NL%NZS = 4 !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! ISOILFLG -- this controls which soil type input you want to use. ! ! 1. Read in from a dataset I will provide in the SOIL_DATABASE variable a ! ! few lines below. ! ! below. ! ! 2. No data available, I will use constant values I will provide in ! ! NSLCON or by prescribing the fraction of sand and clay (see SLXSAND ! ! and SLXCLAY). ! !---------------------------------------------------------------------------------------! NL%ISOILFLG = 2 !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! NSLCON -- ED-2 Soil classes that the model will use when ISOILFLG is set to 2. ! ! Possible values are: ! !---------------------------------------------------------------------------------------! ! 1 -- sand | 7 -- silty clay loam | 13 -- bedrock ! ! 2 -- loamy sand | 8 -- clayey loam | 14 -- silt ! ! 3 -- sandy loam | 9 -- sandy clay | 15 -- heavy clay ! ! 4 -- silt loam | 10 -- silty clay | 16 -- clayey sand ! ! 5 -- loam | 11 -- clay | 17 -- clayey silt ! ! 6 -- sandy clay loam | 12 -- peat ! !---------------------------------------------------------------------------------------! NL%NSLCON = 11 !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! ISOILCOL -- LEAF-3 and ED-2 soil colour classes that the model will use when ISOILFLG ! ! is set to 2. Soil classes are from 1 to 20 (1 = lightest; 20 = darkest). ! ! The values are the same as CLM-4.0. The table is the albedo for visible ! ! and near infra-red. ! !---------------------------------------------------------------------------------------! ! ! ! |-----------------------------------------------------------------------| ! ! | | Dry soil | Saturated | | Dry soil | Saturated | ! ! | Class |-------------+-------------| Class +-------------+-------------| ! ! | | VIS | NIR | VIS | NIR | | VIS | NIR | VIS | NIR | ! ! |-------+------+------+------+------+-------+------+------+------+------| ! ! | 1 | 0.36 | 0.61 | 0.25 | 0.50 | 11 | 0.24 | 0.37 | 0.13 | 0.26 | ! ! | 2 | 0.34 | 0.57 | 0.23 | 0.46 | 12 | 0.23 | 0.35 | 0.12 | 0.24 | ! ! | 3 | 0.32 | 0.53 | 0.21 | 0.42 | 13 | 0.22 | 0.33 | 0.11 | 0.22 | ! ! | 4 | 0.31 | 0.51 | 0.20 | 0.40 | 14 | 0.20 | 0.31 | 0.10 | 0.20 | ! ! | 5 | 0.30 | 0.49 | 0.19 | 0.38 | 15 | 0.18 | 0.29 | 0.09 | 0.18 | ! ! | 6 | 0.29 | 0.48 | 0.18 | 0.36 | 16 | 0.16 | 0.27 | 0.08 | 0.16 | ! ! | 7 | 0.28 | 0.45 | 0.17 | 0.34 | 17 | 0.14 | 0.25 | 0.07 | 0.14 | ! ! | 8 | 0.27 | 0.43 | 0.16 | 0.32 | 18 | 0.12 | 0.23 | 0.06 | 0.12 | ! ! | 9 | 0.26 | 0.41 | 0.15 | 0.30 | 19 | 0.10 | 0.21 | 0.05 | 0.10 | ! ! | 10 | 0.25 | 0.39 | 0.14 | 0.28 | 20 | 0.08 | 0.16 | 0.04 | 0.08 | ! ! |-----------------------------------------------------------------------| ! ! ! ! Soil type 21 is a special case in which we use the albedo method that used to be ! ! the default in ED-2.1. ! !---------------------------------------------------------------------------------------! NL%ISOILCOL = 21 !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! These variables are used to define the soil properties when you don't want to use ! ! the standard soil classes. ! ! ! ! SLXCLAY -- Prescribed fraction of clay [0-1] ! ! SLXSAND -- Prescribed fraction of sand [0-1]. ! ! ! ! They are used only when ISOILFLG is 2, both values are between 0. and 1., and ! ! theira sum doesn't exceed 1. Otherwise standard ED values will be used instead. ! !---------------------------------------------------------------------------------------! NL%SLXCLAY = 0.59 NL%SLXSAND = 0.39 !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! Soil grid and initial conditions if no file is provided: ! ! ! ! SLZ - soil depth in m. Values must be negative and go from the deepest layer to ! ! the top. ! ! SLMSTR - this is the initial soil moisture, now given as the soil moisture index. ! ! Values can be fraction, in which case they will be linearly interpolated ! ! between the special points (e.g. 0.5 will put soil moisture half way ! ! between the wilting point and field capacity). ! ! -1 = dry air soil moisture ! ! 0 = wilting point ! ! 1 = field capacity ! ! 2 = porosity (saturation) ! ! STGOFF - initial temperature offset (soil temperature = air temperature + offset) ! !---------------------------------------------------------------------------------------! NL%SLZ = -8.000, -6.959, -5.995, -5.108, -4.296, -3.560, -2.897, -2.307, -1.789, -1.340, -0.961, -0.648, -0.400, -0.215, -0.089, -0.020 NL%SLMSTR = 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00 NL%STGOFF = 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00 !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! Input databases ! ! VEG_DATABASE -- vegetation database, used only to determine the land/water mask. ! ! Fill with the path and the prefix. ! ! SOIL_DATABASE -- soil database, used to determine the soil type. Fill with the ! ! path and the prefix. ! ! LU_DATABASE -- land-use change disturbance rates database, used only when ! ! IANTH_DISTURB is set to 1. Fill with the path and the prefix. ! ! PLANTATION_FILE -- plantation fraction file. In case you don't have such a file or ! ! you do not want to use it, you must leave this variable empty: ! ! (NL%PLANTATION_FILE = '' ! ! THSUMS_DATABASE -- input directory with dataset to initialise chilling degrees and ! ! growing degree days, which is used to drive the cold-deciduous ! ! phenology (you must always provide this, even when your PFTs are ! ! not cold deciduous). ! ! ED_MET_DRIVER_DB -- File containing information for meteorological driver ! ! instructions (the "header" file). ! ! SOILSTATE_DB -- Dataset in case you want to provide the initial conditions of ! ! soil temperature and moisture. ! ! SOILDEPTH_DB -- Dataset in case you want to read in soil depth information. ! !---------------------------------------------------------------------------------------! NL%VEG_DATABASE = '/data/oge2OLD/OGE2_' NL%SOIL_DATABASE = '/data/faoOLD/FAO_' NL%LU_DATABASE = '/data/ed_inputs/glu/' NL%PLANTATION_FILE = '' NL%THSUMS_DATABASE = '/data/ed_inputs/' NL%ED_MET_DRIVER_DB = '/data/sites/Santarem_Km83/ED_MET_DRIVER_HEADER' NL%SOILSTATE_DB = '' NL%SOILDEPTH_DB = '' !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! ISOILSTATEINIT -- Variable controlling how to initialise the soil temperature and ! ! moisture ! ! 0. Use SLMSTR and STGOFF. ! ! 1. Read from SOILSTATE_DB. ! ! ISOILDEPTHFLG -- Variable controlling how to initialise soil depth ! ! 0. Constant, always defined by the first SLZ layer. ! ! 1. Read from SOILDEPTH_DB. ! !---------------------------------------------------------------------------------------! NL%ISOILSTATEINIT = 0 NL%ISOILDEPTHFLG = 0 !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! ISOILBC -- This controls the soil moisture boundary condition at the bottom. If ! ! unsure, use 0 for short-term simulations (couple of days), and 1 for long- ! ! -term simulations (months to years). ! ! 0. Bedrock. Flux from the bottom of the bottommost layer is set to 0. ! ! 1. Gravitational flow. The flux from the bottom of the bottommost layer ! ! is due to gradient of height only. ! ! 2. Super drainage. Soil moisture of the ficticious layer beneath the ! ! bottom is always at dry air soil moisture. ! ! 3. Half-way. Assume that the fictious layer beneath the bottom is always ! ! at field capacity. ! ! 4. Aquifer. Soil moisture of the ficticious layer beneath the bottom is ! ! always at saturation. ! !---------------------------------------------------------------------------------------! NL%ISOILBC = 1 !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! IVEGT_DYNAMICS -- The vegetation dynamics scheme. ! ! 0. No vegetation dynamics, the initial state will be preserved, ! ! even though the model will compute the potential values. This ! ! option is useful for theoretical simulations only. ! ! 1. Normal ED vegetation dynamics (Moorcroft et al 2001). ! ! The normal option for almost any simulation. ! !---------------------------------------------------------------------------------------! NL%IVEGT_DYNAMICS = 1 !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! IBIGLEAF -- Do you want to run ED as a 'big leaf' model? ! ! 0. No, use the standard size- and age-structure (Moorcroft et al. 2001) ! ! This is the recommended method for most applications. ! ! 1. 'big leaf' ED: this will have no horizontal or vertical hetero- ! ! geneities; 1 patch per PFT and 1 cohort per patch; no vertical ! ! growth, recruits will 'appear' instantaneously at maximum height. ! ! ! ! N.B. if you set IBIGLEAF to 1, you MUST turn off the crown model (CROWN_MOD = 0) ! !---------------------------------------------------------------------------------------! NL%IBIGLEAF = 0 !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! INTEGRATION_SCHEME -- The biophysics integration scheme. ! ! 0. Euler step. The fastest, but it doesn't estimate ! ! errors. ! ! 1. Fourth-order Runge-Kutta method. ED-2.1 default method ! ! 2. Heun's method (a second-order Runge-Kutta). ! ! 3. Hybrid Stepping (BDF2 implicit step for the canopy air and ! ! leaf temp, forward Euler for else, under development). ! !---------------------------------------------------------------------------------------! NL%INTEGRATION_SCHEME = 1 !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! RK4_TOLERANCE -- This is the relative tolerance for Runge-Kutta or Heun's ! ! integration. Larger numbers will make runs go faster, at the ! ! expense of being less accurate. Currently the valid range is ! ! between 1.e-7 and 1.e-1, but recommended values are between 1.e-4 ! ! and 1.e-2. ! !---------------------------------------------------------------------------------------! NL%RK4_TOLERANCE = 0.01 !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! IBRANCH_THERMO -- This determines whether branches should be included in the ! ! vegetation thermodynamics and radiation or not. ! ! 0. No branches in energy/radiation (ED-2.1 default); ! ! 1. Branches are accounted in the energy and radiation. Branchwood ! ! and leaf are treated separately in the canopy radiation scheme, ! ! but solved as a single pool in the biophysics integration. ! ! 2. Similar to 1, but branches are treated as separate pools in the ! ! biophysics (thus doubling the number of prognostic variables). ! !---------------------------------------------------------------------------------------! NL%IBRANCH_THERMO = 1 !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! IPHYSIOL -- This variable will determine the functional form that will control how ! ! the various parameters will vary with temperature, and how the CO2 ! ! compensation point for gross photosynthesis (Gamma*) will be found. ! ! Options are: ! ! ! ! 0 -- Original ED-2.1, we use the "Arrhenius" function as in Foley et al. (1996) and ! ! Moorcroft et al. (2001). Gamma* is found using the parameters for tau as in ! ! Foley et al. (1996). ! ! 1 -- Modified ED-2.1. In this case Gamma* is found using the Michaelis-Mentel ! ! coefficients for CO2 and O2, as in Farquhar et al. (1980) and in CLM. ! ! 2 -- Collatz et al. (1991). We use the power (Q10) equations, with Collatz et al. ! ! parameters for compensation point, and the Michaelis-Mentel coefficients. The ! ! correction for high and low temperatures are the same as in Moorcroft et al. ! ! (2001). ! ! 3 -- Same as 2, except that we find Gamma* as in Farquhar et al. (1980) and in CLM. ! !---------------------------------------------------------------------------------------! NL%IPHYSIOL = 2 !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! IALLOM -- Which allometry to use (this mostly affects tropical PFTs. Temperate PFTs ! ! will use the new root allometry and the maximum crown area if IALLOM is set ! ! to 1 or 2). ! ! 0. Original ED-2.1 ! ! 1. a. The coefficients for structural biomass are set so the total AGB ! ! is similar to Baker et al. (2004), equation 2. Balive is the ! ! default ED-2.1; ! ! b. Experimental root depth that makes canopy trees to have root depths ! ! of 5m and grasses/seedlings at 0.5 to have root depth of 0.5 m. ! ! c. Crown area defined as in Poorter et al. (2006), imposing maximum ! ! crown area ! ! 2. Similar to 1, but with a few extra changes. ! ! a. Height -> DBH allometry as in Poorter et al. (2006) ! ! b. Balive is retuned, using a few leaf biomass allometric equations for ! ! a few genuses in Costa Rica. References: ! ! Cole and Ewel (2006), and Calvo Alvarado et al. (2008). ! !---------------------------------------------------------------------------------------! NL%IALLOM = 2 !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! IGRASS -- This controls the dynamics and growth calculation for grasses. A new ! ! grass scheme is now available where bdead = 0, height is a function of bleaf! ! and growth happens daily. ALS (3/3/12) ! ! 0: grasses behave like trees as in ED2.1 (old scheme) ! ! ! ! 1: new grass scheme as described above ! !---------------------------------------------------------------------------------------! NL%IGRASS = 0 !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! IPHEN_SCHEME -- It controls the phenology scheme. Even within each scheme, the ! ! actual phenology will be different depending on the PFT. ! ! ! ! -1: grasses - evergreen; ! ! tropical - evergreen; ! ! conifers - evergreen; ! ! hardwoods - cold-deciduous (Botta et al.); ! ! ! ! 0: grasses - drought-deciduous (old scheme); ! ! tropical - drought-deciduous (old scheme); ! ! conifers - evergreen; ! ! hardwoods - cold-deciduous; ! ! ! ! 1: prescribed phenology ! ! ! ! 2: grasses - drought-deciduous (new scheme); ! ! tropical - drought-deciduous (new scheme); ! ! conifers - evergreen; ! ! hardwoods - cold-deciduous; ! ! ! ! 3: grasses - drought-deciduous (new scheme); ! ! tropical - drought-deciduous (light phenology); ! ! conifers - evergreen; ! ! hardwoods - cold-deciduous; ! ! ! ! Old scheme: plants shed their leaves once instantaneous amount of available water ! ! becomes less than a critical value. ! ! New scheme: plants shed their leaves once a 10-day running average of available ! ! water becomes less than a critical value. ! !---------------------------------------------------------------------------------------! NL%IPHEN_SCHEME = 2 !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! Parameters that control the phenology response to radiation, used only when ! ! IPHEN_SCHEME = 3. ! ! ! ! RADINT -- Intercept ! ! RADSLP -- Slope. ! !---------------------------------------------------------------------------------------! NL%RADINT = -11.3868 NL%RADSLP = 0.0824 !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! REPRO_SCHEME -- This controls plant reproduction and dispersal. ! ! 0. Reproduction off. Useful for very short runs only. ! ! 1. Original reproduction scheme. Seeds are exchanged between ! ! patches belonging to the same site, but they can't go outside ! ! their original site. ! ! 2. Similar to 1, but seeds are exchanged between patches belonging ! ! to the same polygon, even if they are in different sites. They ! ! can't go outside their original polygon, though. This is the ! ! same as option 1 if there is only one site per polygon. ! ! 3. Similar to 2, but recruits will only be formed if their phenology ! ! status would be "leaves fully flushed". This only matters for ! ! drought deciduous plants. This option is for testing purposes ! ! only, think 50 times before using it... ! !---------------------------------------------------------------------------------------! NL%REPRO_SCHEME = 2 !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! LAPSE_SCHEME -- This specifies the met lapse rate scheme: ! ! 0. No lapse rates ! ! 1. phenomenological, global ! ! 2. phenomenological, local (not yet implemented) ! ! 3. mechanistic(not yet implemented) ! !---------------------------------------------------------------------------------------! NL%LAPSE_SCHEME = 0 !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! CROWN_MOD -- Specifies how tree crowns are represent in the canopy radiation model, ! ! and in the turbulence scheme depending on ICANTURB. ! ! 0. ED1 default, crowns are evenly spread throughout the patch area, and ! ! cohorts are stacked on the top of each other. ! ! 1. Dietze (2008) model. Cohorts have a finite radius, and cohorts are ! ! stacked on the top of each other. ! !---------------------------------------------------------------------------------------! NL%CROWN_MOD = 0 !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! The following variables control the canopy radiation solver. ! ! ! ! ICANRAD -- Specifies how canopy radiation is solved. This variable sets both ! ! shortwave and longwave. ! ! 0. Two-stream model (Medvigy 2006), with the possibility to apply ! ! finite crown area to direct shortwave radiation. ! ! 1. Multiple-scattering model (Zhao and Qualls 2005,2006), with the ! ! possibility to apply finite crown area to all radiation fluxes. ! ! LTRANS_VIS -- Leaf transmittance for tropical plants - Visible/PAR ! ! LTRANS_NIR -- Leaf transmittance for tropical plants - Near Infrared ! ! LREFLECT_VIS -- Leaf reflectance for tropical plants - Visible/PAR ! ! LREFLECT_NIR -- Leaf reflectance for tropical plants - Near Infrared ! ! ORIENT_TREE -- Leaf orientation factor for tropical trees. Extremes are: ! ! -1. All leaves are oriented in the vertical ! ! 0. Leaf orientation is perfectly random ! ! 1. All leaves are oriented in the horizontal ! ! In practice, acceptable values range from -0.4 and 0.6 ! ! ORIENT_GRASS -- Leaf orientation factor for tropical grasses. Extremes are: ! ! -1. All leaves are oriented in the vertical ! ! 0. Leaf orientation is perfectly random ! ! 1. All leaves are oriented in the horizontal ! ! In practice, acceptable values range from -0.4 and 0.6 ! ! CLUMP_TREE -- Clumping factor for tropical trees. Extremes are: ! ! lim -> 0. Black hole (0 itself is unacceptable) ! ! 1. Homogeneously spread over the layer (i.e., no clumping) ! ! CLUMP_GRASS -- Clumping factor for tropical grasses. Extremes are: ! ! lim -> 0. Black hole (0 itself is unacceptable) ! ! 1. Homogeneously spread over the layer (i.e., no clumping) ! !---------------------------------------------------------------------------------------! NL%ICANRAD = 0 NL%LTRANS_VIS = 0.050 NL%LTRANS_NIR = 0.230 NL%LREFLECT_VIS = 0.100 NL%LREFLECT_NIR = 0.460 NL%ORIENT_TREE = 0.100 NL%ORIENT_GRASS = 0.000 NL%CLUMP_TREE = 0.800 NL%CLUMP_GRASS = 1.000 !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! DECOMP_SCHEME -- This specifies the dependence of soil decomposition on temperature. ! ! 0. ED-2.0 default, the original exponential ! ! 1. Lloyd and Taylor (1994) model ! ! [[option 1 requires parameters to be set in xml]] ! !---------------------------------------------------------------------------------------! NL%DECOMP_SCHEME = 0 !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! H2O_PLANT_LIM -- this determines whether plant photosynthesis can be limited by ! ! soil moisture, the FSW, defined as FSW = Supply / (Demand + Supply). ! ! ! ! Demand is always the transpiration rates in case soil moisture is ! ! not limiting (the psi_0 term times LAI). The supply is determined ! ! by Kw * nplant * Broot * Available_Water, and the definition of ! ! available water changes depending on H2O_PLANT_LIM: ! ! 0. Force FSW = 1 (effectively available water is infinity). ! ! 1. Available water is the total soil water above wilting point, ! ! integrated across all layers within the rooting zone. ! ! 2. Available water is the soil water at field capacity minus ! ! wilting point, scaled by the so-called wilting factor: ! ! (psi(k) - (H - z(k)) - psi_wp) / (psi_fc - psi_wp) ! ! where psi is the matric potentital at layer k, z is the layer ! ! depth, H it the crown height and psi_fc and psi_wp are the ! ! matric potentials at wilting point and field capacity. ! !---------------------------------------------------------------------------------------! NL%H2O_PLANT_LIM = 2 !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! The following variables are factors that control photosynthesis and respiration. ! ! Notice that some of them are relative values whereas others are absolute. ! ! ! ! VMFACT_C3 -- Factor multiplying the default Vm0 for C3 plants (1.0 = default). ! ! VMFACT_C4 -- Factor multiplying the default Vm0 for C4 plants (1.0 = default). ! ! MPHOTO_TRC3 -- Stomatal slope (M) for tropical C3 plants ! ! MPHOTO_TEC3 -- Stomatal slope (M) for conifers and temperate C3 plants ! ! MPHOTO_C4 -- Stomatal slope (M) for C4 plants. ! ! BPHOTO_BLC3 -- cuticular conductance for broadleaf C3 plants [umol/m2/s] ! ! BPHOTO_NLC3 -- cuticular conductance for needleleaf C3 plants [umol/m2/s] ! ! BPHOTO_C4 -- cuticular conductance for C4 plants [umol/m2/s] ! ! KW_GRASS -- Water conductance for trees, in m2/yr/kgC_root. This is used only ! ! when H2O_PLANT_LIM is not 0. ! ! KW_TREE -- Water conductance for grasses, in m2/yr/kgC_root. This is used only ! ! when H2O_PLANT_LIM is not 0. ! ! GAMMA_C3 -- The dark respiration factor (gamma) for C3 plants. Subtropical ! ! conifers will be scaled by GAMMA_C3 * 0.028 / 0.02 ! ! GAMMA_C4 -- The dark respiration factor (gamma) for C4 plants. ! ! D0_GRASS -- The transpiration control in gsw (D0) for ALL grasses. ! ! D0_TREE -- The transpiration control in gsw (D0) for ALL trees. ! ! ALPHA_C3 -- Quantum yield of ALL C3 plants. This is only applied when ! ! QUANTUM_EFFICIENCY_T = 0. ! ! ALPHA_C4 -- Quantum yield of C4 plants. This is always applied. ! ! KLOWCO2IN -- The coefficient that controls the PEP carboxylase limited rate of ! ! carboxylation for C4 plants. ! ! RRFFACT -- Factor multiplying the root respiration factor for ALL PFTs. ! ! (1.0 = default). ! ! GROWTHRESP -- The actual growth respiration factor (C3/C4 tropical PFTs only). ! ! (1.0 = default). ! ! LWIDTH_GRASS -- Leaf width for grasses, in metres. This controls the leaf boundary ! ! layer conductance (gbh and gbw). ! ! LWIDTH_BLTREE -- Leaf width for trees, in metres. This controls the leaf boundary ! ! layer conductance (gbh and gbw). This is applied to broadleaf trees ! ! only. ! ! LWIDTH_NLTREE -- Leaf width for trees, in metres. This controls the leaf boundary ! ! layer conductance (gbh and gbw). This is applied to conifer trees ! ! only. ! ! Q10_C3 -- Q10 factor for C3 plants (used only if IPHYSIOL is set to 2 or 3). ! ! Q10_C4 -- Q10 factor for C4 plants (used only if IPHYSIOL is set to 2 or 3). ! !---------------------------------------------------------------------------------------! NL%VMFACT_C3 = 1 NL%VMFACT_C4 = 1 NL%MPHOTO_TRC3 = 9 NL%MPHOTO_TEC3 = 7.2 NL%MPHOTO_C4 = 5.2 NL%BPHOTO_BLC3 = 10000 NL%BPHOTO_NLC3 = 1000 NL%BPHOTO_C4 = 10000 NL%KW_GRASS = 900 NL%KW_TREE = 600 NL%GAMMA_C3 = 0.0145 NL%GAMMA_C4 = 0.035 NL%D0_GRASS = 0.016 NL%D0_TREE = 0.016 NL%ALPHA_C3 = 0.08 NL%ALPHA_C4 = 0.055 NL%KLOWCO2IN = 4000 NL%RRFFACT = 1 NL%GROWTHRESP = 0.333 NL%LWIDTH_GRASS = 0.05 NL%LWIDTH_BLTREE = 0.1 NL%LWIDTH_NLTREE = 0.05 NL%Q10_C3 = 2.4 NL%Q10_C4 = 2.4 !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! THETACRIT -- Leaf drought phenology threshold. The sign matters here: ! ! >= 0. -- This is the relative soil moisture above the wilting point ! ! below which the drought-deciduous plants will start shedding ! ! their leaves ! ! < 0. -- This is the soil potential in MPa below which the drought- ! ! -deciduous plants will start shedding their leaves. The wilt- ! ! ing point is by definition -1.5MPa, so make sure that the value ! ! is above -1.5. ! !---------------------------------------------------------------------------------------! NL%THETACRIT = -1.20 !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! QUANTUM_EFFICIENCY_T -- Which quantum yield model should to use for C3 plants ! ! 0. Original ED-2.1, quantum efficiency is constant. ! ! 1. Quantum efficiency varies with temperature following ! ! Ehleringer (1978) polynomial fit. ! !---------------------------------------------------------------------------------------! NL%QUANTUM_EFFICIENCY_T = 0 !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! N_PLANT_LIM -- This controls whether plant photosynthesis can be limited by nitrogen. ! ! 0. No limitation ! ! 1. ED-2.1 nitrogen limitation model. ! !---------------------------------------------------------------------------------------! NL%N_PLANT_LIM = 0 !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! N_DECOMP_LIM -- This controls whether decomposition can be limited by nitrogen. ! ! 0. No limitation ! ! 1. ED-2.1 nitrogen limitation model. ! !---------------------------------------------------------------------------------------! NL%N_DECOMP_LIM = 0 !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! The following parameters adjust the fire disturbance in the model. ! ! INCLUDE_FIRE -- Which threshold to use for fires. ! ! 0. No fires; ! ! 1. (deprecated) Fire will be triggered with enough biomass and ! ! integrated ground water depth less than a threshold. Based on ! ! ED-1, the threshold assumes that the soil is 1 m, so deeper ! ! soils will need to be much drier to allow fires to happen and ! ! often will never allow fires. ! ! 2. Fire will be triggered with enough biomass and the total soil ! ! water at the top 75 cm falls below a threshold. ! ! FIRE_PARAMETER -- If fire happens, this will control the intensity of the disturbance ! ! given the amount of fuel (currently the total above-ground ! ! biomass). ! ! SM_FIRE -- This is used only when INCLUDE_FIRE = 2. The sign here matters. ! ! >= 0. - Minimum relative soil moisture above dry air of the top 1m ! ! that will prevent fires to happen. ! ! < 0. - Minimum mean soil moisture potential in MPa of the top 1m ! ! that will prevent fires to happen. The dry air soil ! ! potential is defined as -3.1 MPa, so make sure SM_FIRE is ! ! greater than this value. ! !---------------------------------------------------------------------------------------! NL%INCLUDE_FIRE = 0 NL%FIRE_PARAMETER = 0.5 NL%SM_FIRE = -1.40 !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! IANTH_DISTURB -- This flag controls whether to include anthropogenic disturbances ! ! such as land clearing, abandonment, and logging. ! ! 0. no anthropogenic disturbance. ! ! 1. use anthropogenic disturbance dataset. ! !---------------------------------------------------------------------------------------! NL%IANTH_DISTURB = 0 !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! ICANTURB -- This flag controls the canopy roughness. ! ! 0. Based on Leuning et al. (1995), wind is computed using the similarity ! ! theory for the top cohort, and they are extinguished with cumulative ! ! LAI. If using CROWN_MOD 1 or 2, this will use local LAI and average ! ! by crown area. ! ! 1. The default ED-2.1 scheme, except that it uses the zero-plane ! ! displacement height. ! ! 2. This uses the method of Massman (1997) using constant drag and no ! ! sheltering factor. ! ! 3. This is also based on Massman (1997), but with the option of varying ! ! the drag and sheltering within the canopy. ! ! 4. Same as 0, but if finds the ground conductance following CLM ! ! technical note (equations 5.98-5.100). ! !---------------------------------------------------------------------------------------! NL%ICANTURB = 2 !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! ISFCLYRM -- Similarity theory model. The model that computes u*, T*, etc... ! ! 1. BRAMS default, based on Louis (1979). It uses empirical relations to ! ! estimate the flux based on the bulk Richardson number ! ! ! ! All models below use an interative method to find z/L, and the only change ! ! is the functional form of the psi functions. ! ! ! ! 2. Oncley and Dudhia (1995) model, based on MM5. ! ! 3. Beljaars and Holtslag (1991) model. Similar to 2, but it uses an alternative ! ! method for the stable case that mixes more than the OD95. ! ! 4. CLM (2004). Similar to 2 and 3, but they have special functions to deal with ! ! very stable and very stable cases. ! !---------------------------------------------------------------------------------------! NL%ISFCLYRM = 3 !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! IED_GRNDVAP -- Methods to find the ground -> canopy conductance. ! ! 0. Modified Lee Pielke (1992), adding field capacity, but using beta factor ! ! without the square, like in Noilhan and Planton (1989). This is the closest ! ! to the original ED-2.0 and LEAF-3, and it is also the recommended one. ! ! 1. Test # 1 of Mahfouf and Noilhan (1991) ! ! 2. Test # 2 of Mahfouf and Noilhan (1991) ! ! 3. Test # 3 of Mahfouf and Noilhan (1991) ! ! 4. Test # 4 of Mahfouf and Noilhan (1991) ! ! 5. Combination of test #1 (alpha) and test #2 (soil resistance). ! ! In all cases the beta term is modified so it approaches zero as soil moisture goes ! ! to dry air soil. ! !---------------------------------------------------------------------------------------! NL%IED_GRNDVAP = 0 !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! The following variables are used to control the similarity theory model. For the ! ! meaning of these parameters, check Beljaars and Holtslag (1991). ! ! GAMM -- gamma coefficient for momentum, unstable case (dimensionless) ! ! Ignored when ISTAR = 1 ! ! GAMH -- gamma coefficient for heat, unstable case (dimensionless) ! ! Ignored when ISTAR = 1 ! ! TPRANDTL -- Turbulent Prandtl number ! ! Ignored when ISTAR = 1 ! ! RIBMAX -- maximum bulk Richardson number. ! ! LEAF_MAXWHC -- Maximum water that can be intercepted by leaves, in kg/m2leaf. ! !---------------------------------------------------------------------------------------! NL%GAMM = 13.0 NL%GAMH = 13.0 NL%TPRANDTL = 0.74 NL%RIBMAX = 0.50 NL%LEAF_MAXWHC = 0.11 !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! IPERCOL -- This controls percolation and infiltration. ! ! 0. Default method. Assumes soil conductivity constant and for the ! ! temporary surface water, it sheds liquid in excess of a 1:9 liquid- ! ! -to-ice ratio through percolation. Temporary surface water exists ! ! only if the top soil layer is at saturation. ! ! 1. Constant soil conductivity, and it uses the percolation model as in ! ! Anderson (1976) NOAA technical report NWS 19. Temporary surface ! ! water may exist after a heavy rain event, even if the soil doesn't ! ! saturate. Recommended value. ! ! 2. Soil conductivity decreases with depth even for constant soil moisture ! ! , otherwise it is the same as 1. ! !---------------------------------------------------------------------------------------! NL%IPERCOL = 1 !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! The following variables control the plant functional types (PFTs) that will be ! ! used in this simulation. ! ! ! ! INCLUDE_THESE_PFT -- a list containing all the PFTs you want to include in this run ! ! AGRI_STOCK -- which PFT should be used for agriculture ! ! (used only when IANTH_DISTURB = 1) ! ! PLANTATION_STOCK -- which PFT should be used for plantation ! ! (used only when IANTH_DISTURB = 1) ! ! ! ! PFT table ! !---------------------------------------------------------------------------------------! ! 1 - C4 grass | 9 - early temperate deciduous ! ! 2 - early tropical | 10 - mid temperate deciduous ! ! 3 - mid tropical | 11 - late temperate deciduous ! ! 4 - late tropical | 12:15 - agricultural PFTs ! ! 5 - temperate C3 grass | 16 - Subtropical C3 grass ! ! 6 - northern pines | (C4 grass with C3 photo). ! ! 7 - southern pines | 17 - "Araucaria" (non-optimised ! ! 8 - late conifers | Southern Pines). ! !---------------------------------------------------------------------------------------! NL%INCLUDE_THESE_PFT = 1,2,3,4,16 NL%AGRI_STOCK = 1 NL%PLANTATION_STOCK = 3 !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! PFT_1ST_CHECK -- What to do if the initialisation file has a PFT that is not listed ! ! in INCLUDE_THESE_PFT (ignored if IED_INIT_MODE is -1 or 0) ! ! 0. Stop the run ! ! 1. Add the PFT in the INCLUDE_THESE_PFT list ! ! 2. Ignore the cohort ! !---------------------------------------------------------------------------------------! NL%PFT_1ST_CHECK = 0 !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! The following variables control the size of sub-polygon structures in ED-2. ! ! MAXSITE -- This is the strict maximum number of sites that each polygon can ! ! contain. Currently this is used only when the user wants to run ! ! the same polygon with multiple soil types. If there aren't that ! ! many different soil types with a minimum area (check MIN_SITE_AREA ! ! below), then the model will allocate just the amount needed. ! ! MAXPATCH -- If number of patches in a given site exceeds MAXPATCH, force patch ! ! fusion. If MAXPATCH is 0, then fusion will never happen. If ! ! MAXPATCH is negative, then the absolute value is used only during ! ! the initialization, and fusion will never happen again. Notice ! ! that if the patches are too different, then the actual number of ! ! patches in a site may exceed MAXPATCH. ! ! MAXCOHORT -- If number of cohorts in a given patch exceeds MAXCOHORT, force ! ! cohort fusion. If MAXCOHORT is 0, then fusion will never happen. ! ! If MAXCOHORT is negative, then the absolute value is used only ! ! during the initialization, and fusion will never happen again. ! ! Notice that if the cohorts are too different, then the actual ! ! number of cohorts in a patch may exceed MAXCOHORT. ! ! MIN_SITE_AREA -- This is the minimum fraction area of a given soil type that allows ! ! a site to be created (ignored if IED_INIT_MODE is set to 3). ! ! MIN_PATCH_AREA -- This is the minimum fraction area of a given soil type that allows ! ! a site to be created (ignored if IED_INIT_MODE is set to 3). ! !---------------------------------------------------------------------------------------! NL%MAXSITE = 1 NL%MAXPATCH = 10 NL%MAXCOHORT = 40 NL%MIN_SITE_AREA = 0.005 NL%MIN_PATCH_AREA = 0.005 !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! ZROUGH -- constant roughness, in metres, if for all domain ! !---------------------------------------------------------------------------------------! NL%ZROUGH = 0.1 !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! Treefall disturbance parameters. ! ! TREEFALL_DISTURBANCE_RATE -- Sign-dependent treefall disturbance rate: ! ! > 0. usual disturbance rate, in 1/years; ! ! = 0. No treefall disturbance; ! ! < 0. Treefall will be added as a mortality rate (it ! ! will kill plants, but it won't create a new patch). ! ! TIME2CANOPY -- Minimum patch age for treefall disturbance to happen. ! ! If TREEFALL_DISTURBANCE_RATE = 0., this value will be ! ! ignored. If this value is different than zero, then ! ! TREEFALL_DISTURBANCE_RATE is internally adjusted so the ! ! average patch age is still 1/TREEFALL_DISTURBANCE_RATE ! !---------------------------------------------------------------------------------------! NL%TREEFALL_DISTURBANCE_RATE = 0.014 NL%TIME2CANOPY = 0.0 !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! RUNOFF_TIME -- In case a temporary surface water (TSW) is created, this is the "e- ! ! -folding lifetime" of the TSW in seconds due to runoff. If you don't ! ! want runoff to happen, set this to 0. ! !---------------------------------------------------------------------------------------! NL%RUNOFF_TIME = 3600.0 !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! The following variables control the minimum values of various velocities in the ! ! canopy. This is needed to avoid the air to be extremely still, or to avoid singular- ! ! ities. When defining the values, keep in mind that UBMIN >= UGBMIN >= USTMIN. ! ! ! ! UBMIN -- minimum wind speed at the top of the canopy air space [ m/s] ! ! UGBMIN -- minimum wind speed at the leaf level [ m/s] ! ! USTMIN -- minimum friction velocity, u*, in m/s. [ m/s] ! !---------------------------------------------------------------------------------------! NL%UBMIN = 0.65 NL%UGBMIN = 0.25 NL%USTMIN = 0.05 !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! Control parameters for printing to standard output. Any variable can be printed ! ! to standard output as long as it is one dimensional. Polygon variables have been ! ! tested, no gaurtantees for other hierarchical levels. Choose any variables that are ! ! defined in the variable table fill routine in ed_state_vars.f90. Choose the start ! ! and end index of the polygon,site,patch or cohort. It should work in parallel. The ! ! indices are global indices of the entire domain. The are printed out in rows of 10 ! ! columns each. ! ! ! ! IPRINTPOLYS -- 0. Do not print information to screen ! ! 1. Print polygon arrays to screen, use variables described below to ! ! determine which ones and how ! ! NPVARS -- Number of variables to be printed ! ! PRINTVARS -- List of variables to be printed ! ! PFMTSTR -- The standard fortran format for the prints. One format per variable ! ! IPMIN -- First polygon (absolute index) to be print ! ! IPMAX -- Last polygon (absolute index) to print ! !---------------------------------------------------------------------------------------! NL%IPRINTPOLYS = 0 NL%NPVARS = 1 NL%PRINTVARS = 'AVG_PCPG','AVG_CAN_TEMP','AVG_VAPOR_AC','AVG_CAN_SHV' NL%PFMTSTR = 'f10.8','f5.1','f7.2','f9.5' NL%IPMIN = 1 NL%IPMAX = 60 !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! Variables that control the meteorological forcing. ! ! ! ! IMETTYPE -- Format of the meteorological dataset ! ! 0. ASCII (deprecated) ! ! 1. HDF5 ! ! ISHUFFLE -- How to choose an year outside the meterorological data range (see ! ! METCYC1 and METCYCF). ! ! 0. Sequentially cycle over years ! ! 1. Randomly pick the years, using the same sequence. This has worked ! ! with gfortran running in Mac OS X system, but it acts like option 2 ! ! when running ifort. ! ! 2. Randomly pick the years, choosing a different sequence each time ! ! the model is run. ! ! IMETCYC1 -- First year with meteorological information ! ! IMETCYCF -- Last year with meteorological information ! ! IMETAVG -- How the input radiation was originally averaged. You must tell this ! ! because ED-2.1 can make a interpolation accounting for the cosine of ! ! zenith angle. ! ! -1. I don't know, use linear interpolation. ! ! 0. No average, the values are instantaneous ! ! 1. Averages ending at the reference time ! ! 2. Averages beginning at the reference time ! ! 3. Averages centred at the reference time ! ! IMETRAD -- What should the model do with the input short wave radiation? ! ! 0. Nothing, use it as is. ! ! 1. Add them together, then use the SiB method to break radiation down ! ! into the four components (PAR direct, PAR diffuse, NIR direct, ! ! NIR diffuse). ! ! 2. Add then together, then use the method by Weiss and Norman (1985) ! ! to break radiation down to the four components. ! ! 3. Gloomy -- All radiation goes to diffuse. ! ! 4. Sesame street -- all radiation goes to direct, except at night. ! ! INITIAL_CO2 -- Initial value for CO2 in case no CO2 is provided at the meteorological ! ! driver dataset [Units: µmol/mol] ! !---------------------------------------------------------------------------------------! NL%IMETTYPE = 1 NL%ISHUFFLE = 0 NL%METCYC1 = 2000 NL%METCYCF = 2003 NL%IMETAVG = 1 NL%IMETRAD = 2 NL%INITIAL_CO2 = 378.0 !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! The following variables control the phenology prescribed from observations: ! ! ! ! IPHENYS1 -- First year for spring phenology ! ! IPHENYSF -- Final year for spring phenology ! ! IPHENYF1 -- First year for fall/autumn phenology ! ! IPHENYFF -- Final year for fall/autumn phenology ! ! PHENPATH -- path and prefix of the prescribed phenology data. ! ! ! ! If the years don't cover the entire simulation period, they will be recycled. ! !---------------------------------------------------------------------------------------! NL%IPHENYS1 = 1992 NL%IPHENYSF = 2003 NL%IPHENYF1 = 1992 NL%IPHENYFF = 2003 NL%PHENPATH = '/n/moorcroft_data/data/ed2_data/phenology/phenology' !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! These are some additional configuration files. ! ! IEDCNFGF -- XML file containing additional parameter settings. If you don't have ! ! one, leave it empty ! ! EVENT_FILE -- file containing specific events that must be incorporated into the ! ! simulation. ! ! PHENPATH -- path and prefix of the prescribed phenology data. ! !---------------------------------------------------------------------------------------! NL%IEDCNFGF = 'config.xml' NL%EVENT_FILE = 'myevents.xml' !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! The following variables are used to control the detailed output for debugging ! ! purposes. ! ! ! ! IDETAILED -- This flag controls the possible detailed outputs, mostly used for ! ! debugging purposes. Notice that this doesn't replace the normal debug- ! ! ger options, the idea is to provide detailed output to check bad ! ! assumptions. The options are additive, and the indices below represent ! ! the different types of output: ! ! ! ! 1 -- Detailed budget (every DTLSM) ! ! 2 -- Detailed photosynthesis (every DTLSM) ! ! 4 -- Detailed output from the integrator (every HDID) ! ! 8 -- Thermodynamic bounds for sanity check (every DTLSM) ! ! 16 -- Daily error stats (which variable caused the time step to shrink) ! ! 32 -- Allometry parameters, and minimum and maximum sizes ! ! (two files, only at the beginning) ! ! ! ! In case you don't want any detailed output (likely for most runs), set ! ! IDETAILED to zero. In case you want to generate multiple outputs, add ! ! the number of the sought options: for example, if you want detailed ! ! photosynthesis and detailed output from the integrator, set IDETAILED ! ! to 6 (2 + 4). Any combination of the above outputs is acceptable, al- ! ! though all but the last produce a sheer amount of txt files, in which ! ! case you may want to look at variable PATCH_KEEP. It is also a good ! ! idea to set IVEGT_DYNAMICS to 0 when using the first five outputs. ! ! ! ! ! ! PATCH_KEEP -- This option will eliminate all patches except one from the initial- ! ! isation. This is only used when one of the first five types of ! ! detailed output is active, otherwise it will be ignored. Options are: ! ! -2. Keep only the patch with the lowest potential LAI ! ! -1. Keep only the patch with the highest potential LAI ! ! 0. Keep all patches. ! ! > 0. Keep the patch with the provided index. In case the index is ! ! not valid, the model will crash. ! !---------------------------------------------------------------------------------------! NL%IDETAILED = 0 NL%PATCH_KEEP = 0 !---------------------------------------------------------------------------------------! !---------------------------------------------------------------------------------------! ! IOPTINPT -- Optimization configuration. (Currently not used) ! !---------------------------------------------------------------------------------------! !NL%IOPTINPT = '' !---------------------------------------------------------------------------------------! NL%IOOUTPUT = 3 NL%IADD_SITE_MEANS = 0 NL%IADD_PATCH_MEANS = 0 NL%IADD_COHORT_MEANS = 0 NL%GROWTH_RESP_SCHEME = 0 NL%STORAGE_RESP_SCHEME = 0 NL%PLANT_HYDRO_SCHEME = 0 NL%ISTOMATA_SCHEME = 0 NL%ISTRUCT_GROWTH_SCHEME = 0 NL%TRAIT_PLASTICITY_SCHEME = 0 NL%IDDMORT_SCHEME = 0 NL%CBR_SCHEME = 0 NL%DDMORT_CONST = 0 NL%ICANRAD = 1 NL%DT_CENSUS = 60 NL%YR1ST_CENSUS = 2000 NL%MON1ST_CENSUS = 6 NL%MIN_RECRUIT_DBH = 50 $END !==========================================================================================! !==========================================================================================! Convert the docker image to singularity singularity pull docker://pecan/model-ed2-git Finally you can run the singularity image singularity exec -B ed_inputs:/data/ed_inputs -B faoOLD:/data/faoOLD -B oge2OLD:/data/oge2OLD -B sites:/data/sites -B testrun.s83:/data/testrun.s83 --pwd /data/testrun.s83 ./model-ed2-git.simg ed2.git -s Note that the -B option will mount the folder into the singularity image as the second argument (afther the :) The ed2.git command is started with the -s which will run it in single mode, and not initialize and use MPI. Once the model is finished the outputs should be available under testrun.s83. The example ED2IN file is not 100% correct and will result in the following error: output of (failed) run (click to expand) +---------------- MPI parallel info: --------------------+ + - Machnum = 0 + - Machsize = 1 +---------------- OMP parallel info: --------------------+ + - thread use: 1 + - threads max: 1 + - cpu use: 1 + - cpus max: 1 + Note: Max vals are for node, not sockets. +--------------------------------------------------------+ Reading namelist information Copying namelist !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!! WARNING! WARNING! WARNING! WARNING! WARNING! !!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -> Outfast cannot be less than frqfast. Oufast was redefined to 3600. seconds. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!! WARNING! WARNING! WARNING! WARNING! WARNING! !!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -> Outstate cannot be different than frqstate when unitstate is set to 3 (years). Oustate was set to 1. years. Oustate was redefined to 1. years. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +------------------------------------------------------------+ | Ecosystem Demography Model, version 2.2 +------------------------------------------------------------+ | Input namelist filename is ED2IN | | Single process execution on INITIAL run. +------------------------------------------------------------+ => Generating the land/sea mask. /data/oge2OLD/OGE2_HEADER -> Getting file: /data/oge2OLD/OGE2_30S060W.h5... + Work allocation, node 1; + Polygon array allocation, node 1; + Memory successfully allocated on none 1; [+] Load_Ed_Ecosystem_Params... ---------------------------------------- Treefall disturbance parameters: - LAMBDA_REF = 1.40000E-02 - LAMBDA_EFF = 1.40000E-02 - TIME2CANOPY = 0.00000E+00 ---------------------------------------- [+] Checking for XML config... ********************************************* ** WARNING! ** ** ** ** XML file wasn't found. Using default ** ** parameters in ED. ** ** (You provided config.xml). ** ** ********************************************* [+] Alloc_Soilgrid... [+] Set_Polygon_Coordinates... [+] Sfcdata_ED... [+] Load_Ecosystem_State... + Doing sequential initialization over nodes. + Initializing from ED restart file. Node: 001 [-] filelist_f: Checking prefix: /data/sites/Santarem_Km83/s83_default. + Showing first 10 files: [-] File #: 1 /data/sites/Santarem_Km83/s83_default.lat-3.018lon-54.971.css [-] File #: 2 /data/sites/Santarem_Km83/s83_default.lat-3.018lon-54.971.pss Using patch file: /data/sites/Santarem_Km83/s83_default.lat-3.018lon-54.971.pss Using cohort file: /data/sites/Santarem_Km83/s83_default.lat-3.018lon-54.971.css + Initializing phenology. Node: 001 - Reading thermal sums. + Initializing anthropogenic disturbance forcing. Node: 001 -------------------------------------------------------- Soil information: Polygon name : ts83 Longitude : -54.971 Latitude : -3.018 Prescribed sand and clay : T # of sites : 1 Site : 1 - Type : 16 - Clay fraction = 5.90000E-01 - Sand fraction = 3.90000E-01 - Silt fraction = 2.00000E-02 - SLBS = 1.22460E+01 - SLPOTS = -1.52090E-01 - SLCONS = 2.30320E-06 - Dry air soil = 2.29248E-01 - Wilting point = 2.43249E-01 - Field capacity = 3.24517E-01 - Saturation = 4.27790E-01 - Heat capacity = 1.30601E+06 -------------------------------------------------------- [+] Init_Met_Drivers... [+] Read_Met_Drivers_Init... ------------------------------ - METCYC1 = 2000 - METCYCF = 2003 - NYEARS = 2 ------------------------------ IYEAR YEAR_USE 1 2001 2 2002 ------------------------------ [+] Update_met_drivers... [+] Ed_Init_Atm... Total count in node 1 for grid 1 : POLYGONS= 1 SITES= 1 PATCHES= 18 COHORTS= 1753 Grid: 1 Poly: 1 Lon: -54.9710 Lat: -3.0180 Nplants: 0.73 Avg. LAI: 4.45 NPatches: 18 NCohorts: 660 [+] initHydrology... initHydrology | mynum= 1 ngrids= 1 mpolys= 1 msites= 1 Allocated | mynum= 1 ngrids= 1 mpolys= 1 msites= 1 Updated | mynum= 1 ngrids= 1 mpolys= 1 msites= 1 Deallocated | mynum= 1 ngrids= 1 mpolys= 1 msites= 1 [+] Filltab_Alltypes... [+] Finding frqsum... [+] Loading obstime_list File /nowhere not found! Specify OBSTIME_DB properly in ED namelist. :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: -------------------------------------------------------------- !!! FATAL ERROR !!! -------------------------------------------------------------- ---> File: ed_init.F90 ---> Subroutine: read_obstime ---> Reason: OBSTIME_DB not found! -------------------------------------------------------------- ED execution halts (see previous error message)... -------------------------------------------------------------- STOP fatal_error "],["sibcasa.html", "35 SiBCASA", " 35 SiBCASA Model Information Home Page Source Code Contact Kevin Schaefer at (kevin.schaefer[at]nsidc.org License Authors Kevin Shaefer PEcAn Integration Tony Gardella, Yasin Elshorbany Introduction SiBCASA was created from the combination of the Carnegie-Ames_Stanford Approach (CASA) and the Simple Biosphere(SiB) model.They have added other features, including dynamic allocation of GPP for the growth and maintance of leaves, roots, and wood andd explicit calculation of autotrophic respiration. Schaefer, Kevin, et al. “The combined Simple Biosphere/Carnegie-Ames-Stanford Approach (SiBCASA) Model.” J. Geophys. Res 113: G03034. PEcAn configuration file additions Model specific input files Software libraries- PGI 16.5 or later https://www.pgroup.com/products/community.htm NETCDF 3.6.0 Input - Driver data: Made to use CRUNCEP data by default. Param File Initial Condition File Model configuration files The namel_sibdrv is the namelist file that controls input and output file locations. Installation notes Update $PATH to the netcdf library version 3.6 (compiled with the same PGI Fortran compiler) in: PEcAn/sim_setup/Makefile & PEcAn/SiB/sibcasa_arctic4/Makefile Change paths in: Line 379: /SiB/sibcasa_ arctic4/read_ti.F90 Line 260, 273, 286: /SiB/sibcasa_ arctic4/sibdrv_read_ncep2.F90 Update $PATH variables in: /SiB/sibcasa_arctic4/sibmerg.in IMPORTANT: update “fmt_type=‘sing_proc’” even if running on parallel computing system, since the file names will otherwise be incompatible with the outputted data..check Compile code: in ~/SiB/sibcasa_arctic4/ Make clean Make VM Currently Not Avialable on the VM "],["404.html", "Page not found", " Page not found The page you requested cannot be found (perhaps it was moved or renamed). You may want to try searching to find the page's new location, or use the table of contents to find the page you are looking for. "]] diff --git a/master/selected-publications.html b/master/selected-publications.html deleted file mode 100644 index 0c2eb5ce4..000000000 --- a/master/selected-publications.html +++ /dev/null @@ -1,867 +0,0 @@ - - - - - - - 30.3 Selected Publications | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

30.3 Selected Publications

-
    -
  1. Dietze, M.C., D.S LeBauer, R. Kooper (2013) On improving the communication between models and data. Plant, Cell, & Environment doi:10.1111/pce.12043
  2. -
  3. LeBauer, D.S., D. Wang, K. Richter, C. Davidson, & M.C. Dietze. (2013). Facilitating feedbacks between field measurements and ecosystem models. Ecological Monographs. doi:10.1890/12-0137.1
  4. -
- -
- -
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/selecting-plant-functional-types-pfts-and-other-parameter-groupings..html b/master/selecting-plant-functional-types-pfts-and-other-parameter-groupings..html deleted file mode 100644 index cf90e17b1..000000000 --- a/master/selecting-plant-functional-types-pfts-and-other-parameter-groupings..html +++ /dev/null @@ -1,941 +0,0 @@ - - - - - - - 6.3 Selecting Plant Functional Types (PFTs) and other parameter groupings. | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

6.3 Selecting Plant Functional Types (PFTs) and other parameter groupings.

-
-

6.3.1 Using existing PFTs

-

PEcAn does not automatically know what vegetation types are present at your study site so you need to select the PFT.

-

Some models, such as ED2 and LINKAGES, support competition among multiple PFTs and thus you are encouraged to highlight multiple choices. Other models, such as SIPNET and DALEC, only support one PFT at a site.

-

Many models also have parameters that control non-vegetation processes (e.g. soil biogeochemistry and hydrology). PEcAn allows users to assign these parameters to functional groups as well (e.g. a soils PFT)

-
-
-

6.3.2 Creating new PFTs

-

To modify or add a new Plant Functional Type (PFT), or to change a PFT’s priors, navigate -on the grey menu bar to Data > PFTs

-
    -
  1. To add a new pft, click “new PFT” at the top and enter a name and description. (hint: -we’re trying to name PFTs based on model.biome.pft, ED2 is the default model if one -isn’t specified)

  2. -
  3. To add new species to a PFT click on [+] View Related Species and type the species, -genus, or family you are looking for into the Search box. Click on the + to add.

  4. -
  5. To remove a species from a PFT, click on [+] View Related Species and click on the X -of the species you want to remove from the PFT.

  6. -
  7. To remove a prior, click [-] View Related Prior and click on the X of the variable who’s -prior you want to remove. This will cause the parameter to be excluded from all -analyses (meta-analysis, sensitivity analysis, etc) and revert to its default value.

  8. -
  9. To add a prior, choose one from the white box of priors on the right to choose.

  10. -
  11. To view the specification of a prior, or to add a new prior, click BETY-DB > Priors and -enter the information on the variable, distribution name, distribution parameters, etc. N -is the sample size underlying the prior specification (0 is ok for uninformative priors).

  12. -
  13. You can also got to Data > Variables in order to use the search function to find an -existing variable (or create a new one). Please try not to create new variables -unnecessarily (e.g. changes of variable name or units to what your model uses is handled -internally, so you want to find the trait with the correct MEANING).

  14. -
-

Additional information on adding PFTs, Species, and Priors can be found in Adding An [Ecosystem Model].

-
-
-

6.3.3 Choosing initial vegetation

-

On the Input Selection webpage, in addition to selecting PFTs, start & end dates, and meteorology, many models also require some way of specifying the initial conditions for the vegetation, which may range from setting the aboveground biomass and LAI up to detailed inventory-like data on species composition and stand structure.

-

At the moment, PEcAn has three cases for initial conditions:

-
    -
  1. If files already exist in the database, they can simply be selected from the menu. For ED2, there are 3 different veg files (site, pss, css) and it is important that you select a complete set, not mix and match.

  2. -
  3. If files don’t exist they can be uploaded following the instructions in Create a database file record for the input data.

  4. -
  5. Automated vegetation initial condition workflow

  6. -
-

As with meteorology, PEcAn is working to develop a model-agnostic workflow for converting various sources of vegetation data to common standards, developing common processing tools, and then writing out to model-specific formats. This process is in a much early stage than the meteorology workflow, as we are still researching what the options are for standard formats, but ultimately aims to be much more broad in scope, considering not just plot inventory data but also historical documentation, paleoecological proxies, satellite remote sensing (e.g. LANDSAT), airborne hyperspectral imagery, and active remote sensing (Lidar, Radar).

-

At the moment, what is functional is a prototype workflow that works for inventory-based vegetation data. This data can come from either files that have been registered with the BETY Inputs and Formats tables or can be queried from the USFS Forest Inventory and Analysis (FIA). For more information visit Section 13.1.2.2 Vegetation Data

-
-
-

6.3.4 US FIA

-

This tool works with an internal copy of the FIA that is uploaded to a postGRES database along side BETY, however for space reasons this database does not ship with the PEcAn VM. To turn this feature on:

-
    -
  1. Download and Install the FIA database. Instructions in Installing data for PEcAn
  2. -
  3. For web-base runs, specify the database settings in the config.php
  4. -
  5. For R-based runs, specify the database settings in the THE PEcAn XML
  6. -
-

More detailed information on how PEcAn processes inputs can be found on our [Input Conversion]page.

-
-
-

6.3.5 Spin up

-

A number of ecosystem models are typically initialized by spinning up to steady state. At the moment PEcAn doesn’t handle spin up automatically (e.g. looping met, checking for stability), but there are various ways to achieve a spin-up within the system.

-

Option 1: If there are model-specific settings in a model’s settings/config file, then that file can be accessed by clicking on the Edit model config check box. If this box is selected then PEcAn will pause the site run workflow after it has generated your model config file, but before it runs the model, and give you an opportunity to edit the file by hand, allowing you to change any model-specific spin up settings (e.g met recycling, spin up length)

-

Option 2: Set start_year very early and set the met drivers to be a long time series (e.g. PalEON, something custom uploaded to Inputs)

-

Option 3: In the MODEL_TYPE table, add your model’s restart format as an optional input, modify the model specific write.config function to use that restart, and then load a previous spin-up to the Inputs table

-

Beyond these options, we hope to eventually develop more general, model-agnostic tools for spin up. In particular, we have started to explore the accelerated spin-up and semi-analytical techniques being developed by Yiqi Luo’s lab

-
-
-

6.3.6 Selecting a soils product

-

Many models have requirements for soils information, which may include: site-specific soil texture and depth information; soil biogeochemical initial conditions (e.g. soil carbon and nitrogen pools); soil moisture initial conditions; and soil thermal initial conditions.

-

As with Choosing initial vegetation, we eventually hope to develop data standards, soils workflows, and spin-up tools, but at the moment this workflow is in the early stages of development. Model requirements need to be met byCreating a new Input record in BETY into the database or using files that have already been uploaded. Similar to met, we recommend that this file be in the PEcAn-standard netCDF described below, but model-specific files can also be registered.

-
-
-

6.3.7 Soil texture, depth, and physical parameters

-

A PEcAn-standard netCDF file format exists for soil texture, depth, and physical parameters, using PEcAn standard names that are largely a direct extention of the CF standard.

-

The easiest way to create this file is with the PEcAn R function soil2netcdf as described in the Soil Data section of the Advanced Users Guide.

-

A table of standard names and units can be listed using PEcAn.data.land::soil.units() with no arguments.

-

More detailed information on how PEcAn processes inputs can be found on our [Input Conversion] page.

-
-
-

6.3.8 Other model inputs

-

Finally, any other model-specific inputs (e.g. N deposition, land use history, etc), should be met by Creating a new Input record in BETY or using files that have already been uploaded.

- -
-
- -
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/sensitivity-analysis-variance-decomposition.html b/master/sensitivity-analysis-variance-decomposition.html deleted file mode 100644 index 38d82d3e8..000000000 --- a/master/sensitivity-analysis-variance-decomposition.html +++ /dev/null @@ -1,867 +0,0 @@ - - - - - - - 23.9 Sensitivity Analysis, Variance Decomposition | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

23.9 Sensitivity Analysis, Variance Decomposition

-
-

23.9.1 run.sensitivity.analysis()

-

This function processes the output of the previous module into sensitivity analysis plots, sensitivityanalysis.pdf, and a variance decomposition plot, variancedecomposition.pdf . In the sensitivity plots you will see the parameter values on the x-axis, the model output on the Y, with the dots being the model evaluations and the line being the spline fit.

-

The variance decomposition plot is discussed more below. For your reference, the R list object, sensitivity.results, stored in sensitivity.results.Rdata, contains all the components of the variance decomposition table, as well as the the input parameter space and splines from the sensitivity analysis (reminder: the output parameter space from the sensitivity analysis was in outputs.R).

-

The variance decomposition plot contains three columns, the coefficient of variation (normalized posterior variance), the elasticity (normalized sensitivity), and the partial standard deviation of each model parameter. This graph is sorted by the variable explaining the largest amount of variability in the model output (right hand column). From this graph identify the top-tier parameters that you would target for future constraint.

-
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/set-up.html b/master/set-up.html deleted file mode 100644 index c2e6864c3..000000000 --- a/master/set-up.html +++ /dev/null @@ -1,865 +0,0 @@ - - - - - - - 17.2 Set up | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

17.2 Set up

-

Requests for new machine ID’s is currently handled manually. To request a machine ID contact Rob Kooper . In the examples below this ID is referred to as ‘my siteid’.

-

To setup the database to use this ID you need to call load.bety in ‘CREATE’ mode (replacing with the ID if your site)

-
sudo -u postgres {$PECAN}/scripts/load.bety.sh -c -u -m <my siteid> 
-

WARNING: At the moment running CREATE deletes all current records in the database. If you are running from the VM this includes both all runs you have done and all information that the database is prepopulated with (e.g. input and model records). Remote records can be fetched (see below), but local records will be lost (we’re working on improving this!)

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/settings-1.html b/master/settings-1.html deleted file mode 100644 index 62f99fb51..000000000 --- a/master/settings-1.html +++ /dev/null @@ -1,914 +0,0 @@ - - - - - - - 32.4 Settings | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

32.4 Settings

-
    -
  • A generic settings can be found in the PEcAn.all package
  • -
-
settings.xml <- system.file("pecan.biocro.xml", package = "PEcAn.BIOCRO")
-settings <- read.settings(settings.xml)
-
    -
  • database settings can be specified, and tests run only if a connection is available
  • -
-

We currently use the following database to run tests against; tests that require access to a database should check db.exists() and be skipped if it returns FALSE to avoid failed tests on systems that do not have the database installed.

-
settings$database <- list(userid = "bety", 
-                          passwd = "bety", 
-                          name = "bety",     # database name 
-                          host = "localhost" # server name)
-test_that(..., {
-  skip_if_not(db.exists(settings$database))
-  ## write tests here
-})
-
    -
  • instructions for installing this are available on the VM creation -wiki

  • -
  • examples can be found in the PEcAn.DB package (base/db/tests/testthat/).

  • -
  • Model specific settings can go in the model-specific module, for -example:

  • -
-
settings.xml <- system.file("extdata/pecan.biocro.xml", package = "PEcAn.BIOCRO")
-settings <- read.settings(settings.xml)
-
    -
  • test-specific settings: -
      -
    • settings text can be specified inline:

      -
      settings.text <- "
      -  <pecan>
      -    <nocheck>nope</nocheck> ## allows bypass of checks in the read.settings functions
      -    <pfts>
      -      <pft>
      -        <name>ebifarm.pavi</name>
      -        <outdir>test/</outdir>
      -      </pft>
      -    </pfts>
      -    <outdir>test/</outdir>
      -    <database>
      -      <userid>bety</userid>
      -      <passwd>bety</passwd>
      -      <location>localhost</location>
      -      <name>bety</name>
      -    </database>
      -  </pecan>"
      -settings <- read.settings(settings.text)
    • -
    • values in settings can be updated:

      -
      settings <- read.settings(settings.text)
      -settings$outdir <- "/tmp" ## or any other settings
    • -
  • -
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/settings-configured-analyses.html b/master/settings-configured-analyses.html deleted file mode 100644 index 5e7272490..000000000 --- a/master/settings-configured-analyses.html +++ /dev/null @@ -1,1732 +0,0 @@ - - - - - - - 7.2 Settings-configured analyses | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

7.2 Settings-configured analyses

-

These analyses can be run through the web interface, but lack graphical interfaces and currently can only be configured throughthe XML settings. To run these analyses use the Edit pecan.xml checkbox on the Input configuration page. Eventually, these modules will be integrated into the web user interface.

- -

(TODO: Add links)

-
-

7.2.1 Parameter data assimilation (PDA)

-

All functions pertaining to Parameter Data Assimilation are housed within: pecan/modules/assim.batch.

-

For a detailed usage of the module, please see the vignette under pecan/modules/assim.batch/vignettes.

-

Hierarchical version of the PDA is also implemented, for more details, see the MultiSitePDAVignette package vignette and function-level documentation.

-
-

7.2.1.1 pda.mcmc.R

-

This is the main PDA code. It performs Bayesian MCMC on model parameters by proposing parameter values, running the model, calculating a likelihood (between model output and supplied observations), and accepting or rejecting the proposed parameters (Metropolis algorithm). Additional notes:

-
    -
  • The first argument is settings, followed by others that all default to NULL.settings is a list used throughout Pecan, which contains all the user options for whatever analyses are being done. The easiest thing to do is just pass that whole object all around the Pecan code and let different functions access whichever settings they need. That’s what a lot of the rest of the Pecan code does. But the flexibility to override most of the relevant settings in settings is there by providing them directly as arguments to the function.

  • -
  • The if(FALSE)… : If you’re trying to step through the function you probably will have the settings object around, but those other variables will be undefined. If you set them all to NULL then they’ll be ignored without causing errors. It is there for debugging purposes.

  • -
  • The next step calls pda.settings(), which is in the file pda.utils.R (see below). It checks whether any settings are being overridden by arguments, and in most cases supplies default values if it can’t find either.

  • -
  • In the MCMC setup section

    -
      -
    • The code is set up to allow you to start a new MCMC chain, or to continue a previous chain as specified in settings.
    • -
    • The code writes a simple text file of parameter samples at every iteration, which lets you get some results and even re-start an MCMC that fails for some reason.
    • -
    • The code has adaptive jump distributions. So you can see some initialization of the jump distributions and associated variables here.
    • -
    • Finally, note that after all this setup a new XML settings file is saved. The idea is that the original pecan.xml you create is preserved for provenance, and then periodically throughout the workflow the settings (likely containing new information) are re-saved with descriptive filenames.
    • -
  • -
  • MCMC loop

    -
      -
    • Periodically adjust jump distribution to make acceptance rate closer to target
    • -
    • Propose new parameters one at a time. For each: -
        -
      • First, note that Pecan may be handling many more parameters than are actually being targeted by PDA. Pecan puts priors on any variables it has information for (in the BETY database), and then these get passed around throughout the analysis and every step (meta-, sensitivity, ensemble analyses, etc.). But for PDA, you specify a separate list of probably far fewer parameters to constrain with data. These are the ones that get looped over and varied here. The distinction between all parameters and only those dealt with in PDA is dealt with in the setup code above.
      • -
      • First a new value is proposed for the parameter of interest.
      • -
      • Then, a new model run is set up, identical to the previous except with the new proposed value for the one parameter being updated on this run.
      • -
      • The model run is started, and outputs collected after waiting for it to finish.
      • -
      • A new likelihood is calculated based on the model outputs and the observed dataset provided.
      • -
      • Standard Metropolis acceptance criteria is used to decide whether to keep the proposed parameter.
      • -
      • Periodically (at interval specified in settings), a diagnostic figure is saved to disk so you can check on progress.
      • -
    • -
    • This works only for NEE currently
    • -
  • -
-
-
-

7.2.1.2 pda.mcmc.bs.R

-

This file is basically identical to pda.mcm.R, but rather than propose parameters one at a time, it proposes new values for all parameters at once (“bs” stands for “block sampling”). You choose which option to use by specifying settings\(assim.batch\)method: -* “bruteforce” means sample parameters one at a time -* “bruteforce.bs” means use this version, sampling all parameters at once -* “emulator” means use the emulated-likelihood version

-
-
-

7.2.1.3 pda.emulator

-

This version of the PDA code again looks quite similar to the basic “bruteforce” one, but its mechanics are very different. The basic idea is, rather than running thousands of model iterations to explore parameter space via MCMC, run a relatively smaller number of runs that have been carefully chosen to give good coverage of parameter space. Then, basically interpolate the likelihood calculated for each of those runs (actually, fit a Gaussian process to it), to get a surface that “emulates” the true likelihood. Now, perform regular MCMC (just like the “bruteforce” approach), except instead of actually running the model on every iteration to get a likelihood, just get an approximation from the likelihood emulator. Since the latter step takes virtually no time, you can run as long of an MCMC as you need at little computational cost, once you have done the initial model runs to create the likelihood emulator.

-
-
-

7.2.1.4 pda.mcmc.recover.R

-

This function is for recovering a failed PDA MCMC run.

-
-
-

7.2.1.5 pda.utils.R

-

This file contains most of the individual functions used by the main PDA functions (pda.mcmc.*.R).

-
    -
  • assim.batch is the main function Pecan calls to do PDA. It checks which method is requested (bruteforce, bruteforce.bs, or emulator) and call the appropriate function described above.
  • -
  • pda.setting handles settings. If a setting isn’t found, the code can usually supply a reasonable default.
  • -
  • pda.load.priors is fairly self explanatory, except that it handles a lot of cases and gives different options priority over others. Basically, the priors to use for PDA parameters can come from either a Pecan prior.distns or post.distns object (the latter would be, e.g., the posteriors of a meta-analysis or previous PDA), or specified either by file path or BETY ID. If not told otherwise, the code tries to just find the most recent posterior in BETY, and use that as prior for PDA.
  • -
  • pda.create.ensemble gets an ensemble ID for the PDA. All model runs associated with an individual PDA (any of the three methods) are considered part of a single ensemble. This function does is register a new ensemble in BETY, and return the ID that BETY gives it.
  • -
  • pda.define.prior.fn creates R functions for all of the priors the PDA will use.
  • -
  • pda.init.params sets up the parameter matrix for the run, which has one row per iteration, and one column per parameter. Columns include all Pecan parameters, not just the (probably small) subset that are being updated by PDA. This is for compatibility with other Pecan components. If starting a fresh run, the returned matrix is just a big empty matrix to fill in as the PDA runs. If continuing an existing MCMC, then it will be the previous params matrix, with a bunch of blank rows added on for filling in during this round of PDA.
  • -
  • pda.init.run This is basically a big wrapper for Pecan’s write.config function (actually functions [plural], since every model in Pecan has its own version). For the bruteforce and bruteforce.bs methods this will be run once per iteration, whereas the emulator method knows about all its runs ahead of time and this will be a big batch of all runs at once.
  • -
  • pda.adjust.jumps tweaks the jump distributions for the standard MCMC method, and pda.adjust.jumps.bs does the same for the block-sampled version.
  • -
  • pda.calc.llik calculates the log-likelihood of the model given all datasets provided to compare it to.
  • -
  • pda.generate.knots is for the emulator version of PDA. It uses a Latin hypercube design to sample a specified number of locations in parameter space. These locations are where the model will actually be run, and then the GP interpolates the likelihood surface in between.
  • -
  • pda.plot.params provides basic MCMC diagnostics (trace and density) for parameters being sampled.
  • -
  • pda.postprocess prepares the posteriors of the PDA, stores them to files and the database, and performs some other cleanup functions.
  • -
  • pda.load.data.r This is the function that loads in data that will be used to constrain the PDA. It’s supposed to be eventually more integrated with Pecan, which will know how to load all kinds of data from all kinds of sources. For now, it can do NEE from Ameriflux.
  • -
  • pda.define.llik.r A simple helper function that defines likelihood functions for different datasets. Probably in the future this should be queried from the database or something. For now, it is extremely limited. The original test case of NEE assimilation uses a heteroskedastic Laplacian distribution.
  • -
  • pda.get.model.output.R Another function that will eventually grow to handle many more cases, or perhaps be replaced by a better system altogether. For now though, it again just handles Ameriflux NEE.
  • -
-
-
-

7.2.1.6 get.da.data.*.R, plot.da.R

-

Old codes written by Carl Davidson. Defunct now, but may contain good ideas so currently left in.

-
-
-
-

7.2.2 State data assimilation (SDA)

-

sda.enkf.R is housed within: /pecan/modules/assim.sequential/R

-

The tree ring tutorial is housed within: /pecan/documentation/tutorials/StateAssimilation

-

More descriptive SDA methods can be found at: /pecan/book_source/adve_user_guide_web/SDA_Methods.Rmd

-
-

7.2.2.1 sda.enkf.R Description

-

This is the main ensemble Kalman filter and generalized filter code. Originally, this was just ensemble Kalman filter code. Mike Dietze and Ann Raiho added a generalized ensemble filter to avoid filter divergence. The output of this function will be all the of run outputs, a PDF of diagnostics, and an Rdata object that includes three lists:

-
    -
  • FORECAST will be the ensemble forecasts for each year
  • -
  • ANALYSIS will be the updated ensemble sample given the NPP observations
  • -
  • enkf.params contains the prior and posterior mean vector and covariance matrix for each time step.
  • -
-
-
-

7.2.2.2 sda.enkf.R Arguments

-
    -
  • settings - (required) State Data Assimilation Tags Example settings object

  • -
  • obs.mean - (required) a list of observation means named with dates in YYYY/MM/DD format

  • -
  • obs.cov - (required) a list of observation covariances names with dates in YYYY/MM/DD format

  • -
  • IC - (optional) initial condition matrix (dimensions: ensemble memeber # by state variables). Default is NULL.

  • -
  • Q - (optional) process covariance matrix (dimensions: state variable by state variables). Default is NULL.

  • -
-
-
-

7.2.2.3 State Data Assimilation Workflow

-

Before running sda.enkf, these tasks must be completed (in no particular order),

-
    -
  • Read in a State Data Assimilation Tags Example settings file with tags listed below. i.e. read.settings(‘pecan.SDA.xml’)

  • -
  • Load data means (obs.mean) and covariances (obs.cov) as lists with PEcAn naming and unit conventions. Each observation must have a date in YYYY/MM/DD format (optional time) associated with it. If there are missing data, the date must still be represented in the list with an NA as the list object.

  • -
  • Create initial conditions matrix (IC) that is state variables columns by ensemble members rows in dimension. sample.IC.MODEL can be used to create the IC matrix, but it is not required. This IC matrix is fed into write.configs for the initial model runs.

  • -
-

The main parts of the SDA function are:

-

Setting up for initial runs:

-
    -
  • Set parameters

  • -
  • Load initial run inputs via split.inputs.MODEL

  • -
  • Open database connection

  • -
  • Get new workflow ids

  • -
  • Create ensemble ids

  • -
-

Performing the initial set of runs

-

Set up for data assimilation

-

Loop over time

-
    -
  • read.restart.MODEL - read model restart files corresponding to start.time and stop.time that you want to assimilate data into

  • -
  • Analysis - There are four choices based on if process variance is TRUE or FALSE and if there is data or not. See explaination below.

  • -
  • write.restart.MODEL - This function has two jobs. First, to insert adjusted state back into model restart file. Second, to update start.time, stop.time, and job.sh.

  • -
  • run model

  • -
-

Save outputs

-

Create diagnostics

-
-
-

7.2.2.4 State Data Assimilation Tags Example

-
<state.data.assimilation>
-  <adjustment>TRUE</adjustment>
-  <process.variance>FALSE</process.variance>
-  <sample.parameters>FALSE</sample.parameters>
-  <q.type>Single</q.type>
-   <state.variables>
-    <variable>
-      <variable.name>AGB.pft</variable.name>
-      <unit>MgC/ha/yr</unit>
-      <min_value>0</min_value>
-      <max_value>100000000</max_value>
-    </variable>
-    <variable>
-      <variable.name>TotSoilCarb</variable.name>
-      <unit>KgC/m^2</unit>
-      <min_value>0</min_value>
-      <max_value>100000000</max_value>
-    </variable>
-  </state.variables>
-  <spin.up>
-    <start.date>1950/01/01</start.date>
-    <end.date>1960/12/31</end.date>
-  </spin.up>
-  <forecast.time.step>1</forecast.time.step>
-  <start.date>1961/01/01</start.date>
-  <end.date>2010/12/31</end.date>
- </state.data.assimilation>
-
-
-

7.2.2.5 State Data Assimilation Tags Descriptions

-
    -
  • adjustment : [optional] TRUE/FLASE flag for if ensembles needs to be adjusted based on weights estimated given their likelihood during analysis step. The Default is TRUE for this flag.

  • -
  • process.variance : [optional] TRUE/FLASE flag for if process variance should be estimated (TRUE) or not (FALSE). If TRUE, a generalized ensemble filter will be used. If FALSE, an ensemble Kalman filter will be used. Default is FALSE. If you use the TRUE argument you can set three more optional tags to control the MCMCs built for the generalized esnsemble filter.

  • -
  • nitrGEF : [optional] numeric defining the length of the MCMC chains.

  • -
  • nthin : [optional] numeric defining thining length for the MCMC chains.

  • -
  • nburnin : [optional] numeric defining the number of burnins during the MCMCs.

  • -
  • q.type : [optional] If the process.variance is set to TRUE then this can take values of Single, Site or PFT.

  • -
  • censored.data : [optional] logical set TRUE for censored state variables.

  • -
  • sample.parameters : [optional] TRUE/FLASE flag for if parameters should be sampled for each ensemble member or not. This allows for more spread in the initial conditions of the forecast.

  • -
  • state.variable : [required] State variable that is to be assimilated (in PEcAn standard format).

  • -
  • spin.up : [required] start.date and end.date for initial model runs.

  • -
  • NOTE: start.date and end.date are distinct from values set in the run tag because initial runs can be done over a subset of the full run.

  • -
  • forecast.time.step : [optional] In the future, this will be used to allow the forecast time step to vary from the data time step.

  • -
  • start.date : [optional] start date of the state data assimilation (in YYYY/MM/DD format)

  • -
  • end.date : [optional] end date of the state data assimilation (in YYYY/MM/DD format)

  • -
  • NOTE: start.date and end.date are distinct from values set in the run tag because this analysis can be done over a subset of the run.

  • -
-
-
-

7.2.2.6 Model Specific Functions for SDA Workflow

-
-
-

7.2.2.7 read.restart.MODEL.R

-

The purpose of read.restart is to read model restart files and return a matrix that is site rows by state variable columns. The state variables must be in PEcAn names and units. The arguments are:

-
    -
  • outdir - output directory

  • -
  • runid - ensemble member run ID

  • -
  • stop.time - used to determine which restart file to read (in POSIX format)

  • -
  • settings - pecan.SDA.xml settings object

  • -
  • var.names - vector with state variable names with PEcAn standard naming. Example: c(‘AGB.pft’, ‘TotSoilCarb’)

  • -
  • params - parameters used by ensemble member (same format as write.configs)

  • -
-
-
-

7.2.2.8 write.restart.MODEL.R

-

This model specific function takes in new state and new parameter matrices from sda.enkf.R after the analysis step and translates new variables back to the model variables. Then, updates start.time, stop.time, and job.sh so that start_model_runs() does the correct runs with the new states. In write.restart.LINKAGES and write.restart.SIPNET, job.sh is updated by using write.configs.MODEL.

-
    -
  • outdir - output directory

  • -
  • runid - run ID for ensemble member

  • -
  • start.time - beginning of model run (in POSIX format)

  • -
  • stop.time - end of model run (in POSIX format)

  • -
  • settings - pecan.SDA.xml settings object

  • -
  • new.state - matrix from analysis of updated state variables with PEcAn names (dimensions: site rows by state variables columns)

  • -
  • new.params - In the future, this will allow us to update parameters based on states (same format as write.configs)

  • -
  • inputs - model specific inputs from split.inputs.MODEL used to run the model from start.time to stop.time

  • -
  • RENAME - [optional] Flag used in write.restart.LINKAGES.R for development.

  • -
-
-
-

7.2.2.9 split.inputs.MODEL.R

-

This model specific function gives the correct met and/or other model inputs to settings\(run\)inputs. This function returns settings\(run\)inputs to an inputs argument in sda.enkf.R. But, the inputs will not need to change for all models and should return settings\(run\)inputs unchanged if that is the case.

-
    -
  • settings - pecan.SDA.xml settings object

  • -
  • start.time - start time for model run (in POSIX format)

  • -
  • stop.time - stop time for model run (in POSIX format)

  • -
-
-
-

7.2.2.10 sample.IC.MODEL.R

-

This model specific function is optional. But, it can be used to create initial condition matrix (IC) with # state variables columns by # ensemble rows. This IC matrix is used for the initial runs in sda.enkf.R in the write.configs.MODEL function.

-
    -
  • ne - number of ensemble members

  • -
  • state - matrix of state variables to get initial conditions from

  • -
  • year - used to determine which year to sample initial conditions from

  • -
-
-
-

7.2.2.11 Analysis Options

-

There are four options depending on whether process variance is TRUE/FALSE and whether or not there is data or not.

-
    -
  • If there is no data and process variance = FALSE, there is no analysis step.

  • -
  • If there is no data and process variance = TRUE, process variance is added to the forecast.

  • -
  • If there is data and process variance = TRUE, the generalized ensemble filter is implemented with MCMC.

  • -
  • If there is data and process variance = FALSE, the Kalman filter is used and solved analytically.

  • -
-
-
-

7.2.2.12 The Generalized Ensemble Filter

-

An ensemble filter is a sequential data assimilation algorithm with two procedures at every time step: a forecast followed by an analysis. The forecast ensembles arise from a model while the analysis makes an adjustment of the forecasts ensembles from the model towards the data. An ensemble Kalman filter is typically suggested for this type of analysis because of its computationally efficient analytical solution and its ability to update states based on an estimate of covariance structure. But, in some cases, the ensemble Kalman filter fails because of filter divergence. Filter divergence occurs when forecast variability is too small, which causes the analysis to favor the forecast and diverge from the data. Models often produce low forecast variability because there is little internal stochasticity. Our ensemble filter overcomes this problem in a Bayesian framework by including an estimation of model process variance. This methodology also maintains the benefits of the ensemble Kalman filter by updating the state vector based on the estimated covariance structure.

-

This process begins after the model is spun up to equilibrium.

-

The likelihood function uses the data vector \(\left(\boldsymbol{y_{t}}\right)\) conditional on the estimated state vector \(\left(\boldsymbol{x_{t}}\right)\) such that

-

\(\boldsymbol{y}_{t}\sim\mathrm{multivariate\:normal}(\boldsymbol{x}_{t},\boldsymbol{R}_{t})\)

-

where \(\boldsymbol{R}_{t}=\boldsymbol{\sigma}_{t}^{2}\boldsymbol{I}\) and \(\boldsymbol{\sigma}_{t}^{2}\) is a vector of data variances. To obtain an estimate of the state vector \(\left(\boldsymbol{x}_{t}\right)\), we use a process model that incorporates a process covariance matrix \(\left(\boldsymbol{Q}_{t}\right)\). This process covariance matrix differentiates our methods from past ensemble filters. Our process model contains the following equations

-

\(\boldsymbol{x}_{t} \sim \mathrm{multivariate\: normal}(\boldsymbol{x}_{model_{t}},\boldsymbol{Q}_{t})\)

-

\(\boldsymbol{x}_{model_{t}} \sim \mathrm{multivariate\: normal}(\boldsymbol{\mu}_{forecast_{t}},\boldsymbol{P}_{forecast_{t}})\)

-

where \(\boldsymbol{\mu}_{forecast_{t}}\) is a vector of means from the ensemble forecasts and \(\boldsymbol{P}_{forecast_{t}}\) is a covariance matrix calculated from the ensemble forecasts. The prior for our process covariance matrix is \(\boldsymbol{Q}_{t}\sim\mathrm{Wishart}(\boldsymbol{V}_{t},n_{t})\) where \(\boldsymbol{V}_{t}\) is a scale matrix and \(n_{t}\) is the degrees of freedom. The prior shape parameters are updated at each time step through moment matching such that

-

\(\boldsymbol{V}_{t+1} = n_{t}\bar{\boldsymbol{Q}}_{t}\)

-

\(n_{t+1} = \frac{\sum_{i=1}^{I}\sum_{j=1}^{J}\frac{v_{ijt}^{2}+v_{iit}v_{jjt}}{Var(\boldsymbol{\bar{Q}}_{t})}}{I\times J}\)

-

where we calculate the mean of the process covariance matrix \(\left(\bar{\boldsymbol{Q}_{t}}\right)\) from the posterior samples at time t. Degrees of freedom for the Wishart are typically calculated element by element where \(v_{ij}\) are the elements of \(\boldsymbol{V}_{t}\). \(I\) and \(J\) index rows and columns of \(\boldsymbol{V}\). Here, we calculate a mean number of degrees of freedom for \(t+1\) by summing over all the elements of the scale matrix \(\left(\boldsymbol{V}\right)\) and dividing by the count of those elements \(\left(I\times J\right)\). We fit this model sequentially through time in the R computing environment using R package ‘rjags.’

-

Users have control over how they think is the best way to estimate \(Q\). Our code will look for the tag q.type in the XML settings under state.data.assimilation which can take 4 values of Single, Site, Vector, or Wishart. If q.type is set to single then one value of process variance will be estimated across all different sites and variables. When q.type is set to Site then a process variance will be estimated for each siteat a cost of more time and computation power. When the q.type is set to Vector or Wishart then process errors for each variable of each site will be estimated and propagated through time, while the Wishart Q support the estimation of covariance between sites and variables through the MCMC sampling of wishart distributions, which further support the propagation of process error through not just time but space and variables.

-
-
-

7.2.2.13 Multi-site State data assimilation.

-

sda.enkf.multisite is housed within: /pecan/modules/assim.sequential/R

-

The 4-site tutorial is housed within: ~/pecan/modules/assim.sequential/inst/MultiSite-Exs

-
-
-

7.2.2.14 sda.enkf.multisite.R Description

-

sda.enkf.multisite function allows for assimilation of observed data at multiple sites at the same time. In order to run a multi-site SDA, one needs to send a multisettings pecan xml file to this function. This multisettings xml file needs to contain information required for running at least two sites under run tag. The code will automatically run the ensembles for all the sites and reformats the outputs matching the required formats for analysis step. -#### sda.enkf.multisite.R Arguments -* settings - (required) State Data Assimilation Tags Example settings object

-
    -
  • obs.mean - (required) Lists of date times named by time points, which contains lists of sites named by site ids, which contains observation means for each state variables of each site for each time point.

  • -
  • obs.cov - (required) Lists of date times named by time points, which contains lists of sites named by site ids, which contains observation covariances for all state variables of each site for each time point.

  • -
  • Q - (optional) Process covariance matrix given if there is no data to estimate it. Default is NULL.

  • -
  • restart - (optional) Used for iterative updating previous forecasts. Default NULL. List object includes file path to previous runs and start date for SDA. Default is NULL.

  • -
  • pre_enkf_params - (optional) Used for carrying out SDA with pre-existed enkf.params, in which the Pf, aqq, and bqq can be used for the analysis step. Default is NULL.

  • -
  • ensemble.samples - (optional) Pass ensemble.samples from outside, which are lists of calibrated parameters for different plant functional types. This also helps to avoid GitHub check issues. Default is NULL.

  • -
  • control - (optional) List of flags controlling the behavior of the SDA. Here is an example of the control list. The detailed explanation of them are shown inside the sda.enkf.multisite function in the assim.sequential package.

  • -
-
control=list(trace = TRUE,
-             TimeseriesPlot = FALSE,
-             debug = FALSE,
-             pause = FALSE,
-             Profiling = FALSE,
-             OutlierDetection=FALSE,
-             parallel_qsub = TRUE,
-             send_email = NULL,
-             keepNC = TRUE,
-             run_parallel = TRUE,
-             MCMC.args = NULL)
-
-
-

7.2.2.15 obs.mean and obs.cov Description

-

The observations are required for passing the time points into the SDA workflow, which should match the start and end date in the settings object. For the generations of obs.mean and obs.cov, please use the function SDA_OBS_Assembler inside the assim.sequential package. For the unconstrained runs, please specify the free.run flag as TRUE inside the settings$state.data.assimilation$Obs_Prep section. Otherwise, please specify the arguments that are needed for preparations of different observations (note that, the observation preparation functions currently only support MODIS LAI, Landtrendr AGB, SMAP soil moisture, and SoilGrid soil organic carbon). For the details about how to setup those arguments, please reference the Create_Multi_settings.R script inside ~/pecan/modules/assim.sequential/inst/MultiSite-Exs/SDA directory. -The observed mean and covariance need to be formatted as list of different dates with observations. For each element of this list also there needs to be a list with mean and cov matrices of different sites named by their siteid. In case that zero variance was estimated for a variable inside the obs.cov, the SDA code will automatically replace that with half of the minimum variance from other non-zero variables in that time step.

-

Here are examples of the obs.mean and obs.cov for single time point, two sites, and two observations.

-
> obs.mean
-
-$`2010/12/31`
-$`2010/12/31`$`1000000650`
-   AbvGrndWood     GWBI
-    111.502    1.0746
-
-$`2010/12/31`$`1000000651`
-   AbvGrndWood     GWBI
-    114.302    1.574695
-
> obs.cov
-
-$`2010/12/31`
-$`2010/12/31`$`1000000650`
-           [,1]        [,2]
-[1,] 19.7821691 0.213584319
-[2,]  0.5135843 0.005162113
-
-$`2010/12/31`$`1000000651`
-           [,1]        [,2]
-[1,] 15.2821691 0.513584319
-[2,]  0.1213583 0.001162113
-
-
-

7.2.2.16 Anlysis SDA workflow

-

Before running the SDA analysis functions, the ensemble forecast results have to be generated, and arguments such as H matrix, MCMC arguments, and multi-site Y and R (by Construct.R function) have to be generated as well. Here are the workflows for three types of SDA analysis functions that we are currently used.

-
    -
  • Decide which analysis function to be used. Here we have three options: 1) traditional ensemble Kalman Filter (EnKF.MultiSite) with analytical solution, within which the process error needs to be prescribed from outside (see Q arguments in the sda.enkf.multisite function); 2) generalized ensemble Kalman Filter (GEF.MultiSite); and 3) block-based generalized ensemble Kalman Filter (analysis_sda_block). The latter two methods support the feature of propagating process variance across space and time. To choose the analysis method 1, we need to set the process.variance as FALSE. Otherwise, if we set the process.variance as TRUE and provide the q.type as either SINGLE or SITE the method GEF.MultiSite will be used, and if we provide the q.type as either vector or wishart the method analysis_sda_block will be used. The explanations for different Q types can be found in the The Generalized Ensemble Filter section in this documentation. For the analysis_sda_block method, there is also a special case for complete or partial missing of observations.

  • -
  • If we decide to use EnKF.MultiSite, then the analysis results will be calculated based on equations.

  • -
  • If we decide to use GEF.MultiSite, then it will first do censoring process based on how you setup the censored.data flag within settings xml file. Then, if t equals to 1, we will first initialize the aqq, bqq, aq, and bq based on how you setup the q.type argument within settings xml file. After preparing the initial conditions (ICs), data, and constants for the GEF.MultiSite.Nimble nimble model, the MCMC sampling will happen afterwards. Finally, the process variance and the analysis results will be calculated and updated and returned to the sda.enkf.multisite function.

  • -
  • If we decide to use analysis_sda_block method, then if t equals 1, the workflow will first build blocks using the matrix_network function for the calculations for indexes of variables by networks of site groups based on the spatial scale (see scalef argument in the Example of multi-settings pecan xml file section) that we specify inside the state.data.assimilation section. Then, the workflow will execute the build.block.xy to automatically initialize the overall block-based MCMC lists (block.list.all) and fill in datasets (mu.f, y.censored, or Pf) for each block and for all time points to facilitate the process of passing arguments between scripts/functions. After that, the MCMC_args (see the explanations inside the roxygen structure of the sda.enkf.multisite function) will be specified either from the control list or by default (see below). Then, the workflow will update the process error using the update_q function. If t equals 1, it will initialize the arguments for the process error. Otherwise, it will grab the previously updated process error. After that, in the MCMC_Init function, it will create the initial conditions (ICs) for the MCMC sampling based on randomly sampled data. Then, the completed block-based arguments (block.list.all) will be used by the MCMC_block_function function under the parallel mode. Finally, the block-based results will be converted into long vectors and large matrices by the block.2.vector function and values such as block.list.all, mu.f, mu.a, Pf, Pa will be returned to the sda.enkf.multisite function.

  • -
-
MCMC.args <- list(niter = 1e5,
-                  nthin = 10,
-                  nchain = 3,
-                  nburnin = 1e4)
-
    -
  • There is a special case for the analysis_sda_block method where NA values appear in the observations, which provides the opportunity for the estimations of process error without any observations. This special case currently is only working under restricted conditions when we set the scalef as 0 (that feature currently only works for isolated-site SDA runs) and turn on the free.run flag in the settings, which will then automatically fill in NA values to the observations by each site (see bellow).
  • -
-
<state.data.assimilation>
-  <scalef>0</scalef>
-  <free.run>TRUE</free.run>
-</state.data.assimilation>
-
-
-

7.2.2.17 Example of multi-settings pecan xml file

-

Here is an example of what does a multi-settings pecan xml file look like. The detailed explanation for the xml file can be found under the Multi-Settings section in the 03_pecan_xml.Rmd documentation.

-
<?xml version="1.0"?>
-<pecan.multi>
- <state.data.assimilation>
-    <process.variance>TRUE</process.variance>
-    <aqq.Init>1</aqq.Init>
-    <bqq.Init>1</bqq.Init>
-  <sample.parameters>FALSE</sample.parameters>
-  <adjustment>TRUE</adjustment>
-  <censored.data>FALSE</censored.data>
-  <FullYearNC>TRUE</FullYearNC>
-  <NC.Overwrite>FALSE</NC.Overwrite>
-  <NC.Prefix>sipnet.out</NC.Prefix>
-  <q.type>SINGLE</q.type>
-  <free.run>FALSE</free.run>
-  <Localization.FUN>Local.support</Localization.FUN>
-  <scalef>1</scalef>
-  <chains>5</chains>
-  <state.variables>
-    <variable>
-      <variable.name>AbvGrndWood</variable.name>
-      <unit>MgC/ha</unit>
-      <min_value>0</min_value>
-      <max_value>9999</max_value>
-    </variable>
-    <variable>
-      <variable.name>LAI</variable.name>
-      <unit></unit>
-      <min_value>0</min_value>
-      <max_value>9999</max_value>
-    </variable>
-    <variable>
-      <variable.name>SoilMoistFrac</variable.name>
-      <unit></unit>
-      <min_value>0</min_value>
-      <max_value>100</max_value>
-    </variable>
-    <variable>
-      <variable.name>TotSoilCarb</variable.name>
-      <unit>kg/m^2</unit>
-      <min_value>0</min_value>
-      <max_value>9999</max_value>
-    </variable>
-  </state.variables>
-  <Obs_Prep>
-    <Landtrendr_AGB>
-      <AGB_input_dir>/projectnb/dietzelab/dongchen/Multi-site/download_500_sites/AGB</AGB_input_dir>
-      <allow_download>TRUE</allow_download>
-      <export_csv>TRUE</export_csv>
-      <timestep>
-        <unit>year</unit>
-        <num>1</num>
-      </timestep>
-    </Landtrendr_AGB>
-    <MODIS_LAI>
-      <search_window>30</search_window>
-      <export_csv>TRUE</export_csv>
-      <run_parallel>TRUE</run_parallel>
-      <timestep>
-        <unit>year</unit>
-        <num>1</num>
-      </timestep>
-    </MODIS_LAI>
-    <SMAP_SMP>
-      <search_window>30</search_window>
-      <export_csv>TRUE</export_csv>
-      <update_csv>FALSE</update_csv>
-      <timestep>
-        <unit>year</unit>
-        <num>1</num>
-      </timestep>
-    </SMAP_SMP>
-    <Soilgrids_SoilC>
-      <timestep>
-        <unit>year</unit>
-        <num>1</num>
-      </timestep>
-    </Soilgrids_SoilC>
-    <outdir>/projectnb/dietzelab/dongchen/All_NEON_SDA/test_OBS</outdir>
-    <start.date>2012-07-15</start.date>
-    <end.date>2021-07-15</end.date>
-  </Obs_Prep>
-  <spin.up>
-    <start.date>2004/01/01</start.date>
-      <end.date>2006/12/31</end.date>
-  </spin.up>
-  <forecast.time.step>1</forecast.time.step>
-    <start.date>2004/01/01</start.date>
-    <end.date>2006/12/31</end.date>
-</state.data.assimilation>
- <info>
-    <notes></notes>
-    <userid>-1</userid>
-    <username></username>
-    <date>2017/12/06 21:19:33 +0000</date>
-  </info>
- <outdir>/fs/data3/hamzed/output/MultiSite_Sandbox/paleon_sda_SIPNET-8768</outdir>
- <database>
-    <bety>
-      <user>bety</user>
-      <password>bety</password>
-      <host>128.197.168.114</host>
-      <dbname>bety</dbname>
-      <driver>PostgreSQL</driver>
-      <write>false</write>
-    </bety>
-    <dbfiles>/fs/data1/pecan.data/dbfiles/</dbfiles>
-  </database>
- <pfts>
-  <pft>
-   <name>temperate.deciduous_SDA</name>
-   <constants>
-    <num>2</num>
-   </constants>
-   <outdir>/fs/data2/output//PEcAn_1000008768/pft/temperate.deciduous_SDA</outdir>
-   <posteriorid>1000008552</posteriorid>
-  </pft>
- </pfts>
- <meta.analysis>
-    <iter>3000</iter>
-    <random.effects>
-      <on>FALSE</on>
-      <use_ghs>TRUE</use_ghs>
-    </random.effects>
-  </meta.analysis>
- <ensemble>
-  <size>20</size>
-  <ensemble.id>1000016146</ensemble.id>
-  <start.year>1995</start.year>
-  <end.year>1999</end.year>
-  <samplingspace>
-  <parameters>
-    <method>uniform</method>
-  </parameters>
-  <met>
-    <method>sampling</method>
-  </met>
-  <soil>    
-  <parent>parameters</parent>
-  </soil>
-  <vegetation>
-  <parent>soil</parent>
-  </vegetation>
-  </samplingspace>
- </ensemble>
- <model>
-  <id>1000000022</id>
-  <default.param>/fs/data3/hamzed/output/paleon_sda_SIPNET-8768/Bartlett.param</default.param>
-  <type>SIPNET</type>
-  <revision>r136</revision>
-  <delete.raw>FALSE</delete.raw>
-  <binary>/fs/data5/pecan.models/SIPNET/trunk/sipnet_ssr</binary>
- </model>
- <workflow>
-    <id>1000008768</id>
-  </workflow>
- <run>
-  <settings.1000000650>
-  <site>
-   <id>1000000650</id>
-   <met.start>1960/01/01</met.start>
-   <met.end>1965/12/31</met.end>
-   <name>Harvard Forest - Lyford Plots (PalEON PHA)</name>
-   <lat>42.53</lat>
-   <lon>-72.18</lon>
-  </site>
-  <inputs>
-   <met>
-    <source>CRUNCEP</source>
-    <output>SIPNET</output>
-    <path>
-    <path1>/fs/data1/pecan.data/dbfiles/CRUNCEP_SIPNET_site_0-758/CRUNCEP.1960-01-01.2010-12-31.clim</path1>
-    </path>
-   </met>
-  </inputs>
-  <start.date>1960/01/01</start.date>
-  <end.date>1980/12/31</end.date>
-  </settings.1000000650>
-  <settings.1000000651>
-  <site>
-   <id>1000000651</id>
-   <met.start>1960/01/01</met.start>
-   <met.end>1965/12/31</met.end>
-   <name>Harvard Forest - Lyford Plots (PalEON PHA)</name>
-   <lat>42.53</lat>
-   <lon>-72.18</lon>
-  </site>
-  <inputs>
-   <met>
-    <source>CRUNCEP</source>
-    <output>SIPNET</output>
-    <path>
-    <path1>/fs/data1/pecan.data/dbfiles/CRUNCEP_SIPNET_site_0-758/CRUNCEP.1960-01-01.2010-12-31.clim</path1>
-    </path>
-   </met>
-  </inputs>
-  <start.date>1960/01/01</start.date>
-  <end.date>1980/12/31</end.date>
-  </settings.1000000651>
- </run>
- <host>
-  <name>localhost</name>
-  <rundir>/fs/data3/hamzed/output/MultiSite_Sandbox/paleon_sda_SIPNET-8768/run</rundir>
-  <outdir>/fs/data3/hamzed/output/MultiSite_Sandbox/paleon_sda_SIPNET-8768/out</outdir>
- </host>
- <settings.info>
-  <deprecated.settings.fixed>TRUE</deprecated.settings.fixed>
-  <settings.updated>TRUE</settings.updated>
-  <checked>TRUE</checked>
- </settings.info>
- <rundir>/fs/data3/hamzed/output/MultiSite_Sandbox/paleon_sda_SIPNET-8768/run</rundir>
- <modeloutdir>/fs/data3/hamzed/output/MultiSite_Sandbox/paleon_sda_SIPNET-8768/out</modeloutdir>
- <multisettings>run</multisettings>
-</pecan.multi>
-
-
-
-

7.2.3 Running SDA on remote

-

In general, the idea is that sending, running and monitoring an SDA job should all be done using two functions (SDA_remote_launcher and Remote_Sync_launcher). SDA_remote_launcher checks the XML settings defining the run, sets up the SDA on the remote machine, and then sends a qusb command for running the job. Remote_Sync_launcher, on the other hand, sits on the local machine and monitors the progress of the job(s) and brings back the outputs as long as the job is running.

-

SDA_remote_launcher sets up the job by copying a template SDA workflow R script and a bash file template that are ready for submission to the remote machine. This function checks the paths to all inputs including met, soil, site_pft and etc., testing whether they exists on the remote machine or not. If they do not exist, the function copies the missing paths over and replaces the settings accordingly. After submitting the bash script, the function returns the PID of the job writing the log file, allowing the Remote_Sync_launcher to monitor the progress of the run, checks to see if the job is still alive, and determines if sda.output.rdata has been updated since the last check or not.

-

Additionally, the Remote_Sync_launcher function follows the progress of the remote job by executing a nohup command on a template R script and keeps the R console open for further use. This R script, as mentioned above, constantly pings the given PID every 5 minutes and copies over the SDA output.

-

Several points on how to prepare your xml settings for the remote SDA run: -1 - In the main pecan workflow.R, if you were able to generate pecan.TRAIT.xml, your settings are ready to be used for an SDA run. All you need to add is your state data assimilation tags. -2 - Inside the xml setting an <outdir> flag needs to be included and point to a local directory where SDA_remote_launcher will look for either a sample.Rdata file or a pft folder. -3 - You need to set your <host> tag according to the desired remote machine. You can learn more about this on the Remote execution with PEcAn section of the documentation. Please make sure that the <folder> tag inside <host> is pointing to a directory where you would like to store and run your SDA job(s). -4 - Finally, make sure the tag inside the tag is set to the correct path on the remote machine.

-
-
-

7.2.4 Restart functionality in SDA

-

If you prefer to run your SDA analysis in multiple stages, where each phase picks up where the previous one left off, you can use the restart argument in the sda.enkf.multisite function. You need to make sure that the output from previous step exists in the SDA folder (in the outfolder), and the <start.date> is the same as <end.date> from the previous step. When you run the SDA with the restart parameter, it will load the output from the previous step and use configs already written in the run folder to set itself up for the next step. Using the restart argument could be as easy as :

-
sda.enkf.multisite(settings,
-                   obs.mean =obs.mean ,
-                   obs.cov = obs.cov,
-                   control = SDA.arguments(debug = FALSE, TimeseriesPlot = FALSE),
-                   restart = FALSE
-        )
-
-

Where the new settings, obs.mean and obs.cov contain the relevant information for the next phase.

-
-
-

7.2.5 State Data Assimilation Methods

-

By Ann Raiho

-

Our goal is build a fully generalizable state data assimilation (SDA) workflow that will assimilate multiple types of data and data products into ecosystem models within PEcAn temporally and spatially. But, during development, specifically with PalEON goals in mind, we have been focusing on assimilating tree ring estimated NPP and AGB and pollen derived fractional composition into two ecosystem models, SIPNET and LINKAGES, at Harvard Forest. This methodology will soon be expanded to include the PalEON sites listed on the state data assimilation wiki page.

-
-

7.2.5.1 Data Products

-

During workflow development, we have been working with tree ring estimated NPP and AGB and pollen derived fractional composition data products. Both of these data products have been estimated with a full accounting of uncertainty, which provides us with state variable observation mean vector and covariance matrix at each time step. These data products are discussed in more detail below. Even though we have been working with specific data products during development, our workflow is generalizable to alternative data products as long as we can calculate a state variable observation mean vector and covariance for a time point.

-
-
-

7.2.5.2 Tree Rings

-

We have been primarily been working with the tree ring data product created by Andria Dawson and Chris Paciorek and the PEcAn tree ring allometry module. They have developed a Bayesian model that estimates annual aboveground biomass increment (Mg/ha/yr) and aboveground biomass (Mg/ha) for each tree in a dataset. We obtain this data and aggregate to the level appropriate for the ecosystem model. In SIPNET, we are assimilating annual gross woody increment (Mg/ha/yr) and above ground woody biomass (Mg/ha). In LINKAGES, we are assimilating annual species biomass. More information on deriving these tree ring data products can be found in Dawson et al 201?.

-

We have been working mostly with tree data collected at Harvard Forest. Tree rings and census data were collected at Lyford Plot between 1960 and 2010 in three separate plots. Other tree ring data will be added to this analysis in the future from past PEON courses (UNDERC), Kelly Heilman (Billy’s Lake and Bigwoods), and Alex Dye (Huron Mt. Club).

-
-
-

7.2.5.3 Pollen

-

STEPPS is a Bayesian model developed by Paciorek and McLachlan 2009 and Dawson et al 2016 to estimate spatially gridded fractional composition from fossil pollen. We have been working with STEPPS1 output, specifically with the grid cell that contains Harvard Forest. The temporal resolution of this data product is centennial. Our workflow currently operates at annual time steps, but does not require data at every time step. So, it is possible to assimilate fractional composition every one hundred years or to assimilate fractional composition data every year by accounting for variance inflation.

-

In the future, pollen derived biomass (ReFAB) will also be available for data assimilation. Although, we have not discussed how STEPPS and ReFAB data assimilation will work.

-
-
-

7.2.5.4 Variance Inflation

-

*Side Note: Probably want to call this something else now.

-

Since the fractional composition data product has a centennial resolution, in order to use fractional composition information every year we need to change the weight the data has on the analysis. The basic idea is to downweight the likelihood relative to the prior to account for (a) the fact that we assimilate an observation multiple times and (b) the fact that the number of STEPPS observations is ‘inflated’ because of the autocorrelation. To do this, we take the likelihood and raise it to the power of (1/w) where ‘w’ is an inflation factor.

-

w = D * (N / ESS)

-

where D is the length of the time step. In our case D = 100. N is the number of time steps. In our case N = 11. and ESS is the effective sample size. The ESS is calculated with the following function where ntimes is the same as N above and sims is a matrix with the dimensions number of MCMC samples by number of state variables.

-
ESS_calc <- function(ntimes, sims){
-        # center based on mean at each time to remove baseline temporal correlation 
-        # (we want to estimate effective sample size effect from correlation of the errors)
-        row.means.sims <- sims - rowMeans(sims)  
-        
-        # compute all pairwise covariances at different times
-        covars <- NULL
-        for(lag in 1:(ntimes-1)){
-          covars <- c(covars, rowMeans(row.means.sims[(lag+1):ntimes, , drop = FALSE] * row.means.sims[1:(ntimes-lag), , drop = FALSE])) 
-        }
-        vars <- apply(row.means.sims, 1, var) # pointwise post variances at each time, might not be homoscedastic
-        
-        # nominal sample size scaled by ratio of variance of an average
-        # under independence to variance of average of correlated values
-        neff <- ntimes * sum(vars) / (sum(vars) + 2 * sum(covars))
-        return(neff)
-      }
-

The ESS for the STEPPS1 data product is 3.6, so w in our assimilation of fractional composition at Harvard Forest will be w = 305.6.

-
-
-

7.2.5.5 Current Models

-

SIPNET and LINKAGES are the two ecosystem models that have been used during state data assimilation development within PEcAn. SIPNET is a simple ecosystem model that was built for… LINKAGES is a forest gap model created to simulate the process of succession that occurs when a gap is opened in the forest canopy. LINKAGES has 72 species level plant functional types and the ability to simulate some below ground processes (C and N cycles).

-
-
-

7.2.5.6 Model Calibration

-

Without model calibration both SIPNET and LINKAGES make incorrect predictions about Harvard Forest. To confront this problem, SIPNET and LINKAGES will both be calibrated using data collected at the Harvard Forest flux tower. Istem has completed calibration for SIPNET using a parameter data assimilation emulator contained within the PEcAn workflow. LINKAGES will also be calibrated using this method. This method is also generalizable to other sites assuming there is data independent of data assimilation data available to calibrate against.

-
-
-

7.2.5.7 Initial Conditions

-

The initial conditions for SIPNET are sampled across state space based on data distributions at the time when the data assimilation will begin. We do not sample LINAKGES for initial conditions and instead perform model spin up for 100 years prior to beginning data assimilation. In the future, we would like to estimate initial conditions based on data. We achieve adequate spread in the initial conditions by allowing the parameters to vary across ensemble members.

-
-
-

7.2.5.8 Drivers

-

We are currently using Global Climate Model (GCM) drivers from the PaLEON model intercomparison. Christy Rollinson and John Tipton are creating MET downscaled GCM drivers for the Paleon data assimilation sites. We will use these drivers when they are available because they are a closer representation of reality.

-
-
-

7.2.5.9 Sequential State Data Assimilation

-

We are using sequential state data assimilation methods to assimilate paleon data products into ecosystem models because less computation power is required for sequential state data assimilation than for particle filter methods.

-
-
-

7.2.5.10 General Description

-

The general sequential data assimilation framework consists of three steps at each time step: -1. Read the state variable output for time t from the model forecast ensembles and save the forecast mean (muf) and covariance (Pf). -2. If there are data mean (y) and covariance (R) at this time step, perform data assimilation analysis (either EnKF or generalized ensemble filter) to calculate the new mean (mua) and covariance (Pa) of the state variables. -3. Use mua and Pa to restart and run the ecosystem model ensembles with new state variables for time t+1.

-
-
-

7.2.5.11 EnKF

-

There are two ways to implement sequential state data assimilation at this time. The first is the Ensemble Kalman Filter (EnKF). EnKF has an analytical solution, so the kalman gain, analysis mean vector, and analysis covariance matrix can be calculated directly:

-
       
-        K <- Pf %*% t(H) %*% solve((R + H %*% Pf %*% t(H))) ## Kalman Gain
-        
-        mu.a <- mu.f + K %*% (Y - H %*% mu.f) # Analysis mean vector
-        
-        Pa   <- (diag(ncol(X)) - K %*% H) %*% Pf # Analysis covariance matrix
-        
-

The EnKF is typically used for sequential state data assimilation, but we found that EnKF lead to filter divergence when combined with our uncertain data products. Filter divergence led us to create a generalized ensemble filter that estimates process variance.

-
-
-

7.2.5.12 Generalized Ensemble Filter

-

The generalized ensemble filter follows generally the three steps of sequential state data assimilation. But, in the generalized ensemble filter we add a latent state vector that accounts for added process variance. Furthermore, instead of solving the analysis analytically like the EnKF, we have to estimate the mean analysis vector and covariance matrix with MCMC.

-
-
-

7.2.5.13 Mapping Ensemble Output to Tobit Space

-

There are some instances when we have right or left censored variables from the model forecast. For example, a model estimating species level biomass may have several ensemble members that produce zero biomass for a given species. We are considering this case a left censored state variable that needs to be mapped to normal space using a tobit model. We do this by creating two matrices with dimensions number of ensembles by state variable. The first matrix is a matrix of indicator variables (y.ind), and the second is a matrix of censored variables (y.censored). When the indicator variable is 0 the state variable (j) for ensemble member (i) is sampled. This allows us to impute a normal distribution for each state variable that contains ‘missing’ forecasts or forecasts of zero.

-
tobit2space.model <- nimbleCode({
-    for(i in 1:N){
-      y.censored[i,1:J] ~ dmnorm(muf[1:J], cov = pf[1:J,1:J])
-      for(j in 1:J){
-        y.ind[i,j] ~ dconstraint(y.censored[i,j] > 0)
-      }
-    }
-    
-    muf[1:J] ~ dmnorm(mean = mu_0[1:J], cov = pf[1:J,1:J])
-    
-    Sigma[1:J,1:J] <- lambda_0[1:J,1:J]/nu_0
-    pf[1:J,1:J] ~ dinvwish(S = Sigma[1:J,1:J], df = J)
-    
-  })
-
-
-

7.2.5.14 Generalized Ensemble Filter Model Description

-

Below is the BUGS code for the full analysis model. The forecast mean an covariance are calculated from the tobit2space model above. We use a tobit likelihood in this model because there are instances when the data may be left or right censored. Process variance is included by adding a latent model state (X) with a process precision matrix (q). We update our prior on q at each time step using our estimate of q from the previous time step.

-
  tobit.model <- nimbleCode({ 
-    
-    q[1:N,1:N]  ~ dwish(R = aq[1:N,1:N], df = bq) ## aq and bq are estimated over time
-    Q[1:N,1:N] <- inverse(q[1:N,1:N])
-    X.mod[1:N] ~ dmnorm(muf[1:N], prec = pf[1:N,1:N]) ## Model Forecast ##muf and pf are assigned from ensembles
-    
-    ## add process error
-    X[1:N]  ~ dmnorm(X.mod[1:N], prec = q[1:N,1:N])
-    
-    #agb linear
-    #y_star[1:YN,1:YN] <- X[1:YN,1:YN] #[choose]
-    
-    #f.comp non linear
-    #y_star[1:YN] <- X[1:YN] / sum(X[1:YN])
-    
-    ## Analysis
-    y.censored[1:YN] ~ dmnorm(X[1:YN], prec = r[1:YN,1:YN]) #is it an okay assumpution to just have X and Y in the same order?
-    
-    #don't flag y.censored as data, y.censored in inits
-    #remove y.censored samplers and only assign univariate samplers on NAs
-    
-    for(i in 1:YN){
-      y.ind[i] ~ dconstraint(y.censored[i] > 0)
-    }
-    
-  })
-
-
-

7.2.5.15 Ensemble Adjustment

-

Each ensemble member has a different set of species parameters. We adjust the updated state variables by using an ensemble adjustment. The ensemble adjustment weights the ensemble members based on their likelihood during the analysis step.

-
      S_f  <- svd(Pf)
-      L_f  <- S_f$d
-      V_f  <- S_f$v
-      
-      ## normalize
-      Z <- X*0
-      for(i in seq_len(nrow(X))){
-          Z[i,] <- 1/sqrt(L_f) * t(V_f)%*%(X[i,]-mu.f)
-      }
-      Z[is.na(Z)]<-0
-      
-      ## analysis
-      S_a  <- svd(Pa)
-      L_a  <- S_a$d
-      V_a  <- S_a$v
-      
-      ## analysis ensemble
-      X_a <- X*0
-      for(i in seq_len(nrow(X))){
-        X_a[i,] <- V_a %*%diag(sqrt(L_a))%*%Z[i,] + mu.a
-      }
-
-
-

7.2.5.16 Diagnostics

-

There are three diagnostics we have currently implemented: time series, bias time series, and process variance. The time series diagnostics show the data, forecast, and analysis time series for each state variable. These are useful for visually assessing variance and magnitude of change of state variables through time. These time series are also updated throughout the analysis and are also created as a pdf at the end of the SDA workflow. There are two types of bias time series the first assess the bias in the update (the forecast minus the analysis) and the second assess the bias in the error (the forecast minus the data). These bias time series are useful for identifying which state variables have intrinsic bias within the model. For example, if red oak biomass in LINKAGES increases at every time step (the update and the error are always positive), this would suggest that LINKAGES has a positive growth or recruitment bias for red oak. Finally, when using the generalized ensemble filter to estimate process variance, there are two additional plots to assess estimation of process variance. The first is a correlation plot of the process covariance matrix. This tells us what correlations are incorrectly represented by the model. For example, if red oak biomass and white pine biomass are highly negatively correlated in the process covariance matrix, this means that the model either 1) has no relationship between red oak and white pine and they should affect each other negatively or 2) there is a positive relationship between red oak and white pine and there shouldn’t be any relationship. We can determine which of these is true by comparing the process covariance matrix to the model covariance matrix. The second process variance diagnostic plot shows how the degrees of freedom associated with estimating the process covariance matrix have changed through time. This plot should show increasing degrees of freedom through time.

-
-
-
-

7.2.6 MultiSettings

-

(TODO: Under construction…)

-
-
-

7.2.7 Benchmarking

-

Benchmarking is the process of comparing model outputs against either experimental data or against other model outputs as a way to validate model performance. -We have a suit of statistical comparisons that provide benchmarking scores as well as visual comparisons that help in diagnosing data-model and/or model-model differences.

-
-

7.2.7.1 Data Preparation

-

All data that you want to compare with model runs must be registered in the database. -This is currently a step that must be done by hand either from the command line or through the online BETY interface. -The data must have three records:

-
    -
  1. An input record (Instructions here)

  2. -
  3. A database file record (Instructions here)

  4. -
  5. A format record (Instructions here)

  6. -
-
-
-

7.2.7.2 Model Runs

-

Model runs can be setup and executed -- Using the PEcAn web interface online or with a VM (see setup) -- By hand using the pecan.xml

-
-
-

7.2.7.3 The Benchmarking Shiny App

-

The entire benchmarking process can be done through the Benchmarking R Shiny app.

-

When the model run has completed, navigate to the workflow visualization Shiny app.

-
    -
  • Load model data -
      -
    • Select the workflow and run id
    • -
    • Make sure that your model output is loading properly (i.e. you can see plots of your data)
    • -
  • -
  • Load benchmarking data -
      -
    • Again make sure that you can see the uploaded data plotted alongside the model output. In the future there will be more tools for double checking that your uploaded data is appropriate for benchmarking, but for now you may need to do the sanity checks by hand.
    • -
  • -
-
-
-

7.2.7.4 Create a reference run record

-
    -
  • Navigate to the Benchmarking tab -
      -
    • The first step is to register the new model run as a reference run in the database. Benchmarking cannot be done before this step is completed. When the reference run record has been created, additional menus for benchmarking will appear.
    • -
  • -
-
-
-

7.2.7.5 Setup Benchmarks and metrics

-
    -
  • From the menus select -
      -
    • The variables in the uploaded data that you wish to compare with model output.
    • -
    • The numerical metrics you would like to use in your comparison.
    • -
    • Additional comparison plots that you would like to see.
    • -
  • -
  • Note: All these selections populate the benchmarking section of the pecan.BENCH.xml which is then saved in the same location as the original run output. This xml is purely for reference.
  • -
-
-
7.2.7.5.1 Benchmarking Output
-
    -
  • All benchmarking results are stored in the benchmarking directory which is created in the same folder as the original model run.

  • -
  • The benchmaking directory contains subdirectories for each of the datasets compared with the model output. The names of these directories are the same as the corresponding data set’s input id in BETY.

  • -
  • Each input directory contains benchmarking.output.Rdata, an Rdata file contianing all the results of the benchmarking workflow. load(benchmarking.output.Rdata) loads a list called result.out which contains the following:

    -
      -
    • bench.results: a data frame of all numeric benchmarking scores
    • -
    • format: a data frame that can be used to see how the input data was transformed to make it comparable to the model output. This involves converting from the original variable names and units to the internal pecan standard.
    • -
    • aligned.dat: a data frame of the final aligned model and input values.
    • -
  • -
  • All plots are saved as pdf files with names with “benchmark_plot-type_variable_input-id.pdf”

  • -
  • To view interactive results, naviage to the Benchmarking Plots tab in the shiny app.

  • -
-
-
-
-

7.2.7.6 Benchmarking in pecan.xml

-

Before reading this section, it is recommended that you familiarize yourself with basics of the pecan.xml file.

-

The pecan.xml has an optional benchmarking section. Below are all the tags in the benchmarking section explained. Many of these field are filled in automatically during the benchmarking process when using the benchmarking shiny app.

-

The only time one should edit the benchmarking section by hand is for performing clone runs. See clone run documentation.

-

<benchmarking> settings:

-
    -
  • ensemble_id: the id of the ensemble that you will be using - the settings from this ensemble will be saved in a reference run record and then ensemble_id will be replaced with reference_run_id
  • -
  • new_run: TRUE = create new run, FALSE = use existing run (required, default FALSE)
  • -
-

It is possible to look at more than one benchmark with a particular run. -The specific settings related to each benchmark are in a sub section called benchmark

-
    -
  • input_id: the id of the benchmarking data (required)
  • -
  • variable_id: the id of the variable of interest within the data. If you leave this blank, all variables that are shared between the input and model output will be used.
  • -
  • metric_id: the id(s) of the metric(s) to be calculated. If you leave this blank, all metrics will be used.
  • -
-

Example: -In this example, -- we are using a pre-existing run from ensemble_id = 1000010983 (new_run = FALSE) -- the output will be compared to data from input_id = 1000013743, specifically two variables of interest: variable_id = 411, variable_id = 18 -- for variable_id = 411 we will perform only one metric of comparison metric_id = 1000000001 -- for for variable_id = 18 we will perform two metrics of comparison metric_id = 1000000001, metric_id = 1000000002

-
<benchmarking>
-  <ensemble_id>1000010983</ensemble_id>
-  <new_run>FALSE</new_run>
-  <benchmark>
-   <input_id>1000013743</input_id>
-   <variable_id>411</variable_id>
-   <site_id>853</site_id>
-   <metrics>
-    <metric_id>1000000001</metric_id>
-   </metrics>
-  </benchmark>
-  <benchmark>
-   <input_id>1000013743</input_id>
-   <variable_id>18</variable_id>
-   <site_id>853</site_id>
-   <metrics>
-    <metric_id>1000000001</metric_id>
-    <metric_id>1000000002</metric_id>
-   </metrics>
-  </benchmark>
-</benchmarking>
- -
-
-
- -
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/sharing-data.html b/master/sharing-data.html deleted file mode 100644 index 029f78598..000000000 --- a/master/sharing-data.html +++ /dev/null @@ -1,885 +0,0 @@ - - - - - - - 17.4 Sharing data | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

17.4 Sharing data

-

Sharing your data requires a few steps. First, before entering any data, you will need to request an ID from the PEcAn developers. Simply open an issue at github and we will generate an ID for you. If possible, add the URL of your data host.

-

You will now need to synchronize the database again and use your ID. For example if you are given ID=42 you can use the following command: MYID=42 REMOTEID=0 ./scripts/load.bety.sh. This will load the EBI database and set the ID’s such that any data you insert will have the right ID.

-

To share your data you can now run the dump.bey.sh. The script is configured using environment variables, the following variables are recognized: -- DATABASE: the database where the script should write the results. The default is bety. -- PG_OPT: additional options to be added to psql (default is nothing). -- MYSITE: the ID of your site. If you have not requested an ID, use 99, which is used for all sites that do not want to share their data (i.e. VM). 99 is the default. -- LEVEL: the minimum access-protection level of the data to be dumped (0=private, 1=restricted, 2=internal collaborators, 3=external collaborators, 4=public). The default level for exported data is level 3. -- note that currently only the traits and yields tables have restrictions on sharing. If you share data, records from other (meta-data) tables will be shared. If you wish to extend the access_level to other tables please submit a feature request. -- UNCHECKED: specifies whether unchecked traits and yields be dumped. Set to YES (all caps) to dump unchecked data. The default is NO. -- ANONYMOUS: specifies whether all users be anonymized. Set to YES (all caps) to keep the original users (INCLUDING PASSWORD) in the dump file. The default is NO. -- OUTPUT: the location of where on disk to write the result file. The default is ${PWD}/dump.

-

NOTE: If you want your dumps to be accessible to other PEcAn servers you need to perform the following additional steps

-
    -
  1. Open pecan/scripts/load.bety.sh
  2. -
  3. In the DUMPURL section of the code add a new record indicating where you are dumping your data. Below is the example for SITE number 1 (Boston University)
  4. -
-
 elif [ "${REMOTESITE}" == "1" ]; then
- DUMPURL="http://psql-pecan.bu.edu/sync/dump/bety.tar.gz"
-
    -
  1. Check your Apache settings to make sure this location is public
  2. -
  3. Commit this code and submit a Pull Request
  4. -
  5. From the URL in the Pull Request, PEcAn administrators will update the machines table, the status map, and notify other users to update their cron jobs (see Automation below)
  6. -
-

Plans to simplify this process are in the works

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/shiny-setup.html b/master/shiny-setup.html deleted file mode 100644 index 7b027ae0b..000000000 --- a/master/shiny-setup.html +++ /dev/null @@ -1,970 +0,0 @@ - - - - - - - 24.3 Shiny Setup | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

24.3 Shiny Setup

-

Installing and configuring Shiny for PEcAn -authors - Alexey Shiklomanov -- Rob Kooper

-

NOTE: Instructions are only tested for CentOS 6.5 and Ubuntu 16.04 -NOTE: Pretty much every step here requires root access.

-
-

24.3.1 Install the Shiny R package and Shiny server

-

Follow the instructions on the Shiny download page for the operating system you are using.

-
-
-

24.3.2 Modify the shiny configuration file

-

The Shiny configuration file is located in /etc/shiny-server/shiny-server.conf. Comment out the entire file and add the following, replacing <username> with your user name and <location> with the URL location you want for your app. This will allow you to run Shiny apps from your web browser at https://your.server.edu/shiny/your-location

-
run as shiny;
-server {
-    listen 3838;
-    location /<location>/ {
-        run as <username>;
-        site_dir /path/to/your/shiny/app;
-        log_dir /var/log/shiny-server;
-        directory_index on;
-    }
-}
-

For example, my configuration on the old test-pecan looks like this.

-
run as shiny;
-server {
-    listen 3838;
-    location /ashiklom/ {
-        run as ashiklom;
-        site_dir /home/ashiklom/fs-data/pecan/shiny/;
-        log_dir /var/log/shiny-server;
-        directory_index on;
-    }
-}
-

…and I can access my Shiny apps at, for instance, https://test-pecan.bu.edu/shiny/ashiklom/workflowPlots.

-

You can add as many location <loc> { ... } fields as you would like.

-
run as shiny;
-server {
-    listen 3838;
-    location /ashiklom/ {
-        ...
-    }
-    location /bety/ {
-        ...
-    }
-}
-

If you change the configuration, for example to add a new location, you will need to restart Shiny server. -If you are setting up a new instance of Shiny, skip this step and continue with the guide, since there are a few more steps to get Shiny working. -If there is an instance of Shiny already running, you can restart it with:

-
## On CentOS
-sudo service shiny-server stop
-sudo service shiny-server start
-
-## On Ubuntu
-sudo systemctl stop shiny-server.service
-sudo systemctl start shiny-server.service
-
-
-

24.3.3 Set the Apache proxy

-

Create a file with the following name, based on the version of the operating system you are using:

-
    -
  • Ubuntu 16.04 (pecan1, pecan2, test-pecan) – /etc/apache2/conf-available/shiny.conf
  • -
  • CentOS 6.5 (psql-pecan) – /etc/httpd/conf.d/shiny.conf
  • -
-

Into this file, add the following:

-
ProxyPass           /shiny/ http://localhost:3838/
-ProxyPassReverse    /shiny/ http://localhost:3838/
-RedirectMatch permanent ^/shiny$ /shiny/
-
-

24.3.3.1 Ubuntu only: Enable the new shiny configuration

-
sudo a2enconf shiny
-

This will create a symbolic link to the newly created shiny.conf file inside the /etc/apache2/conf-enabled directory. -You can do ls -l /etc/apache2/conf-enabled to confirm that this worked.

-
-
-
-

24.3.4 Enable and start the shiny server, and restart apache

-
-

24.3.4.1 On CentOS

-
sudo ln -s /opt/shiny-server/config/init.d/redhat/shiny-server /etc/init.d
-sudo service shiny-server stop
-sudo service shiny-server start
-sudo service httpd restart
-

You can check that Shiny is running with service shiny-server status.

-
-
-

24.3.4.2 On Ubuntu

-

Enable the Shiny server service. -This will make sure Shiny runs automatically on startup.

-
sudo systemctl enable shiny-server.service
-

Restart Apache.

-
sudo apachectl restart
-

Start the Shiny server.

-
sudo systemctl start shiny-server.service
-

If there are problems, you can stop the shiny-server.service with…

-
sudo systemctl stop shiny-server.service
-

…and then use start again to restart it.

-
-
-
-

24.3.5 Troubleshooting

-

Refer to the log files for shiny (/var/log/shiny-server.log) and httpd (on CentOS, /var/log/httpd/error-log; on Ubuntu, /var/log/apache2/error-log).

-
-
-

24.3.6 Further reading

- - -
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/shiny.html b/master/shiny.html deleted file mode 100644 index c4d8e3f4f..000000000 --- a/master/shiny.html +++ /dev/null @@ -1,861 +0,0 @@ - - - - - - - 19 Shiny | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

19 Shiny

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/sibcasa.html b/master/sibcasa.html deleted file mode 100644 index e1a1d3edc..000000000 --- a/master/sibcasa.html +++ /dev/null @@ -1,921 +0,0 @@ - - - - - - - 35 SiBCASA | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

35 SiBCASA

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Model Information
Home Page
Source CodeContact Kevin Schaefer at (kevin.schaefer[at]nsidc.org
License
AuthorsKevin Shaefer
PEcAn IntegrationTony Gardella, Yasin Elshorbany
-

Introduction

-

SiBCASA was created from the combination of the Carnegie-Ames_Stanford Approach (CASA) and the Simple Biosphere(SiB) model.They have added other features, including dynamic allocation of GPP for the growth and maintance of leaves, roots, and wood andd explicit calculation of autotrophic respiration.

-

Schaefer, Kevin, et al. “The combined Simple Biosphere/Carnegie-Ames-Stanford Approach (SiBCASA) Model.” J. Geophys. Res 113: G03034.

-

PEcAn configuration file additions

-

Model specific input files

-

Software libraries-
-PGI 16.5 or later -https://www.pgroup.com/products/community.htm

-

NETCDF 3.6.0

-

Input - -Driver data: Made to use CRUNCEP data by default. -Param File -Initial Condition File

-

Model configuration files -The namel_sibdrv is the namelist file that controls input and output file locations.

-

Installation notes -Update $PATH to the netcdf library version 3.6 (compiled with the same PGI Fortran compiler) in: -PEcAn/sim_setup/Makefile & -PEcAn/SiB/sibcasa_arctic4/Makefile

-

Change paths in: -Line 379: /SiB/sibcasa_ arctic4/read_ti.F90 -Line 260, 273, 286: /SiB/sibcasa_ arctic4/sibdrv_read_ncep2.F90 -Update $PATH variables in: /SiB/sibcasa_arctic4/sibmerg.in -IMPORTANT: update “fmt_type=‘sing_proc’” even if running on parallel computing system, since the file names will otherwise be incompatible with the outputted data..check

-

Compile code: in ~/SiB/sibcasa_arctic4/ -Make clean -Make

-

VM -Currently Not Avialable on the VM

- -
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/special-case-geo.bu.html b/master/special-case-geo.bu.html deleted file mode 100644 index c0113423c..000000000 --- a/master/special-case-geo.bu.html +++ /dev/null @@ -1,873 +0,0 @@ - - - - - - - 26.10 Special case: geo.bu.edu | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

26.10 Special case: geo.bu.edu

-

Following modules need to be loaded:

-
module load hdf5 udunits R/R-3.0.0_gnu-4.4.6
-

Next the following packages need to be installed, otherwise it -will fall back on the older versions install site-library

-
install.packages(c('udunits2', 'lubridate'), 
-   configure.args=c(udunits2='--with-udunits2-lib=/project/earth/packages/udunits-2.1.24/lib --with-udunits2-include=/project/earth/packages/udunits-2.1.24/include'))
-

Finally to install support for both ED and SIPNET:

-
devtools::install_github("pecanproject/pecan", subdir = 'base/utils')
-devtools::install_github("pecanproject/pecan", subdir = 'models/sipnet')
-devtools::install_github("pecanproject/pecan", subdir = 'models/ed')
- -
- -
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/ssh-authentication-password-vs.-ssh-key.html b/master/ssh-authentication-password-vs.-ssh-key.html deleted file mode 100644 index ea982c5ea..000000000 --- a/master/ssh-authentication-password-vs.-ssh-key.html +++ /dev/null @@ -1,869 +0,0 @@ - - - - - - - 26.2 SSH authentication – password vs. SSH key | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

26.2 SSH authentication – password vs. SSH key

-

Because this server uses passwords for authentication, this command will then prompt me for my password.

-

An alternative to password authentication is using SSH keys. -Under this system, the host machine (say, your laptop, or the PEcAn VM) has to generate a public and private key pair (using the ssh-keygen command). -The private key (by default, a file in ~/.ssh/id_rsa) lives on the host machine, and should never be shared with anyone. -The public key will be distributed to any remote machines to which you want the host to be able to connect. -On each remote machine, the public key should be added to a list of authorized keys located in the ~/.ssh/authorized_keys file (on the remote machine). -The authorized keys list indicates which machines (technically, which keys – a single machine, and even a single user, can have many keys) are allowed to connect to it. -This is the system used by all of the PEcAn servers (pecan1, pecan2, test-pecan).

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/ssh-tunneling.html b/master/ssh-tunneling.html deleted file mode 100644 index f09dc3cea..000000000 --- a/master/ssh-tunneling.html +++ /dev/null @@ -1,886 +0,0 @@ - - - - - - - 26.3 SSH tunneling | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

26.3 SSH tunneling

-

SSH authentication can be more advanced than indicated above, especially on systems that require dual authentication. -Even simple password-protection can be tricky in scripts, since (by design) it is fairly difficult to get SSH to accept a password from anything other than the raw keyboard input (i.e. SSH doesn’t let you pass passwords as input or arguments, because this exposes your password as plain text).

-

A convenient and secure way to follow SSH security protocol, but prevent having to go through the full authentication process every time, is to use SSH tunnels (or “sockets”, which are effectively synonymous). -Essentially, an SSH socket is a read- and write-protectected file that contains all of the information about an SSH connection.

-

To create an SSH tunnel, use a command like the following:

-
ssh -n -N -f -o ControlMaster=yes -S /path/to/socket/file <username>@<hostname>
-

If appropriate, this will prompt you for your password (if using password authentication), and then will drop you back to the command line (thanks to the -N flag, which runs SSH without executing a command, the -f flag, which pushes SSH into the background, and the -n flag, which prevents ssh from reading any input). -It will also create the file /path/to/socket/file.

-

To use this socket with another command, use the -S /path/to/file flag, pointing to the same tunnel file you just created.

-
ssh -S /path/to/socket/file <hostname> <optional command>
-

This will let you access the server without any sort of authentication step. -As before, if <optional command> is blank, you will be dropped into an interactive shell on the remote, or if it’s a command, that command will be executed and the output returned.

-

To close a socket, use the following:

-
ssh -S /path/to/socket/file <hostname> -O exit
-

This will delete the socket file and close the connection. -Alternatively, a scorched earth approach to closing the SSH tunnel if you don’t remember where you put the socket file is something like the following:

-
pgrep ssh   # See which processes will be killed
-pkill ssh   # Kill those processes
-

…which will kill all user processes called ssh.

-

To automatically create tunnels following a specific pattern, you can add the following to your -~/.ssh/config

-
Host <hostname goes here>
- ControlMaster auto
- ControlPath /tmp/%r@%h:%p
-

For more information, see man ssh.

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/ssh-tunnels-and-pecan.html b/master/ssh-tunnels-and-pecan.html deleted file mode 100644 index 1b63a7b20..000000000 --- a/master/ssh-tunnels-and-pecan.html +++ /dev/null @@ -1,870 +0,0 @@ - - - - - - - 26.4 SSH tunnels and PEcAn | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

26.4 SSH tunnels and PEcAn

-

Many of the PEcAn.remote functions assume that a tunnel is already open. -If working from the web interface, the tunnel will be opened for you by some under-the-hood PHP and Bash code, but if debugging or working locally, you will have to create the tunnel yourself. -The best way to do this is to create the tunnel first, outside of R, as described above. -(In the following examples, I’ll use my username ashiklom connecting to the test-pecan server with a socket stored in /tmp/testpecan. -To follow along, replace these with your own username and designated server, respectively).

-
ssh -nNf -o ControlMaster=yes -S /tmp/testpecan ashiklom@test-pecan.bu.edu
-

Then, in R, create a host object, which is just a list containing the elements name (hostname) and tunnel (path to tunnel file).

-
my_host <- list(name = "test-pecan.bu.edu", tunnel = "/tmp/testpecan")
-

This host object can then be used in any of the remote execution functions.

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/ssh-vm-bety.html b/master/ssh-vm-bety.html deleted file mode 100644 index 12db6704b..000000000 --- a/master/ssh-vm-bety.html +++ /dev/null @@ -1,1033 +0,0 @@ - - - - - - - 10.3 Connecting to BETYdb on the VM via SSH | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

10.3 Connecting to BETYdb on the VM via SSH

-

Sometimes, you may want to develop code locally but connect to an instance of BETYdb on the VM. -To do this, first open a new terminal and connect to the VM while enabling port forwarding (with the -L flag) and setting the port number. Using 5433 does not conflict with the postgres default port of 5432, the forwarded port will not conflict with a postgres database server running locally.

-
ssh -L 5433:localhost:5432 carya@localhost:6422
-

This makes port 5433 on the local machine match port 5432 on the VM. -This means that connecting to localhost:5433 will give you access to BETYdb on the VM.

-

To test this on the command line, try the following command, which, if successful, will drop you into the psql console.

-
psql -d bety -U bety -h localhost -p 5433
-

To test this in R, open a Postgres using the analogous parameters:

-
library(DBI)
-library(RPostgres)
-con <- dbConnect(
-  drv = Postgres(),
-  user = "bety",
-  password = "bety",
-  dbname = "bety",
-  host = "localhost",
-  port = 5433
-)
-dbListTables(con)   # This should return a vector of bety tables
-

Note that the same general approach will work on any BETYdb server where port forwarding is enabled, but it requires ssh access.

-
-

10.3.1 Using Amazon Web Services for a VM (AWS)

-

Login to Amazon Web Services (AWS) and select the EC2 Dashboard. If this is your first time using AWS you will need to set up an account before you are able to access the EC2 Dashboard. Important: You will need a credit card number and access to a phone to be able to verify AWS account registration. AWS is free for one year.

-
    -
  1. Choose AMI
  2. -
-
    -
  • On the top right next to your name, make sure the location setting is on U.S. East (N. Virginia), not U.S. West (Oregon)
  • -
  • On the left click, click on EC2 (Virtual servers), then click on “AMIs”, also on the left
  • -
  • In the search window toggle to change “Owned by me” to “Public images”
  • -
  • Type “pecan” into the search window
  • -
  • Click on the toggle button on the left next to PEcAn1.4.6
  • -
  • Click on the “Launch” button at the top
  • -
-
    -
  1. Choose an Instance Type
  2. -
-
    -
  • Select what type of machine you want to run. For this demo the default, t2.micro, will be adequate. Be aware that different machine types incur very different costs, from 1.3 cents/hour to over $5/hr https://aws.amazon.com/ec2/pricing/
    -
  • -
  • Select t2.micro, then click “Next: Configure Instance Details”
  • -
-
    -
  1. Configure Instance Details
  2. -
-
    -
  • The defaults are OK. Click “Next: Add Storage”
  • -
-
    -
  1. Add Storage
  2. -
-
    -
  • The defaults are OK. Click “Next: Tag Instance”
  • -
-
    -
  1. Tag Instance
  2. -
-
    -
  • You can name your instance if you want. Click “Next: Configure Security Group”
  • -
-
    -
  1. Configure Security Group
  2. -
-
    -
  • You will need to add two new rules:
  • -
  • Click “Add Rule” then select “HTTP” from the pull down menu. This rule allows you to access the webserver on PEcAn.
  • -
  • Click “Add Rule”, leave the pull down on “Custom TCP Rule”, and then change the Port Range from 0 to 8787. Set “Source” to Anywhere. This rule allows you to access RStudio Server on PEcAn.
  • -
  • Click “Review and Launch” . You will then see this pop-up:
  • -
-

-

Select the default drive volume type and click Next

-
    -
  1. Review and Launch
  2. -
-
    -
  • Review the settings and then click “Launch”, which will pop up a select/create Key Pair window.
  • -
-
    -
  1. Key Pair
  2. -
-
    -
  • Select “Create a new key pair” and give it a name. You won’t actually need this key unless you need to SSH into your PEcAn server, but AWS requires you to create one. Click on “Download Key Pair” then on “Launch Instances”. Next click on “View Instances” at the bottom of the following page.
  • -
-

-
    -
  1. Instances
  2. -
-
    -
  • You will see the status of your PEcAn VM, which will take a minute to boot up. Wait until the Instance State reads “running”. The most important piece of information here is the Public IP, which is the URL you will need in order to access your PEcAn instance from within your web browser (see Demo 1 below).
  • -
  • Be aware that it often takes ~1 hr for AWS instances to become fully operational, so if you get an error when you put the Public IP in you web browser, most of the time you just need to wait a bit longer. -Congratulations! You just started a PEcAn server in the “cloud”!
  • -
-
    -
  1. When you are done using PEcAn, you will want to return to the “Instances” menu to turn off your VM.
  2. -
-
    -
  • To STOP the instance (which will turn the machine off but keep your work), select your PEcAn instance and click Actions > Instance state > Stop. Be aware that a stopped instance will still accrue a small storage cost on AWS. To restart this instance at any point in the future you do not want to repeat all the steps above, but instead you just need to select your instance and then click Actions > Instance state > Start
  • -
  • To TERMINATE the instance (which will DELETE your PEcAn machine), select your instance and click Actions > Instance state > Terminate. Terminated instances will not incur costs. In most cases you will also want to go to the Volumes menu and delete the storage associated with your PEcAn VM.Remember, AWS is free for one year, but will automatically charge a fee in second year if account is not cancelled.
  • -
-
-
-

10.3.2 Creating a Virtual Machine

-

First create virtual machine

-
# ----------------------------------------------------------------------
-# CREATE VM USING FOLLOWING:
-# - VM NAME  = PEcAn
-# - CPU      = 2
-# - MEMORY   = 2GB 
-# - DISK     = 100GB
-# - HOSTNAME = pecan
-# - FULLNAME = PEcAn Demo User
-# - USERNAME = xxxxxxx
-# - PASSWORD = yyyyyyy
-# - PACKAGE  = openssh
-# ----------------------------------------------------------------------
-

To enable tunnels run the following on the host machine:

-
VBoxManage modifyvm "PEcAn" --natpf1 "ssh,tcp,,6422,,22"
-VBoxManage modifyvm "PEcAn" --natpf1 "www,tcp,,6480,,80"
-

Make sure machine is up to date.

-

UBUNTU

-
sudo apt-get update
-sudo apt-get -y dist-upgrade
-sudo reboot
-

CENTOS/REDHAT

-
sudo yum -y update
-sudo reboot
-

Install compiler and other packages needed and install the tools.

-

UBUNTU

-
sudo apt-get -y install build-essential linux-headers-server dkms
-

CENTOS/REDHAT

-
sudo yum -y groupinstall "Development Tools"
-sudo yum -y install wget
-

Install Virtual Box additions for better integration

-
sudo mount /dev/cdrom /mnt
-sudo /mnt/VBoxLinuxAdditions.run
-sudo umount /mnt
-sudo usermod -a -G vboxsf carya
-

Finishing up the machine

-

Add a message to the login:

-
sudo -s
-export PORT=$( hostname | sed 's/pecan//' )
-cat > /etc/motd << EOF
-PEcAn version 1.4.3
-
-For more information about:
-Pecan    - http://pecanproject.org
-BETY     - http://www.betydb.org
-
-For a list of all models currently navigate [here](../users_guide/basic_users_guide/models_table.md)
-
-
-You can access this system using a webbrowser at
- http://<hosting machine>:${PORT}80/
-or using SSH at
- ssh -l carya -p ${PORT}22 <hosting machine>
-where <hosting machine> is the machine where the VM runs on.
-EOF
-exit
-

Finishing up

-

Script to clean the VM and remove as much as possible history cleanvm.sh

-
wget -O ~/cleanvm.sh http://isda.ncsa.uiuc.edu/~kooper/EBI/cleanvm.sh
-chmod 755 ~/cleanvm.sh
-

Make sure machine has SSH keys rc.local

-
sudo wget -O /etc/rc.local http://isda.ncsa.illinois.edu/~kooper/EBI/rc.local
-

Change the resolution of the console

-
sudo sed -i -e 's/#GRUB_GFXMODE=640x480/GRUB_GFXMODE=1024x768/' /etc/default/grub
-sudo update-grub
-

Once all done, stop the virtual machine

-
history -c && ${HOME}/cleanvm.sh
- -
-
- -
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/ssh-vm.html b/master/ssh-vm.html deleted file mode 100644 index b95e7bc8c..000000000 --- a/master/ssh-vm.html +++ /dev/null @@ -1,871 +0,0 @@ - - - - - - - 10.2 Connecting to the VM via SSH | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

10.2 Connecting to the VM via SSH

-

Once the VM is running anywhere on your machine, you can connect to it from a separate terminal via SSH as follows:

-
ssh -p 6422 carya@localhost
-

You will be prompted for a password. Like everywhere else in PEcAn, the username is carya and the password is illinois. The same password is used for any system maintenance you wish to do on the VM via sudo.

-

As a shortcut, you can add the following to your ~/.ssh/config file (or create one if it does not exist).

-
Host pecan-vm
-    Hostname localhost
-    Port 6422
-    user carya
-    ForwardX11Trusted yes
-

This will allow you to SSH into the VM with the simplified command, ssh pecan-vm.

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/standalone-tools-modules.html b/master/standalone-tools-modules.html deleted file mode 100644 index 1ad2383a3..000000000 --- a/master/standalone-tools-modules.html +++ /dev/null @@ -1,867 +0,0 @@ - - - - - - - 18 Standalone tools (modules) | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

18 Standalone tools (modules)

- -
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/start-runs.html b/master/start-runs.html deleted file mode 100644 index a1406ae92..000000000 --- a/master/start-runs.html +++ /dev/null @@ -1,865 +0,0 @@ - - - - - - - 23.6 Start Runs | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

23.6 Start Runs

-
-

23.6.1 start.runs(model)

-

This code starts the model runs using a model specific run function named start.runs.model. If the ecosystem model is running on a remote server, this module also takes care of all of the communication with the remote server and its run queue. Each of your subdirectories should now have a [run.id].out file in it. One instance of the model is run for each configuration file generated by the previous write configs module.

-
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/summer-courses-workshops.html b/master/summer-courses-workshops.html deleted file mode 100644 index e16a8ecf7..000000000 --- a/master/summer-courses-workshops.html +++ /dev/null @@ -1,881 +0,0 @@ - - - - - - - 30.2 Summer Courses / Workshops | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

30.2 Summer Courses / Workshops

-
-

30.2.1 Annual summer course in flux measurement and advanced modeling (Mike Dietze, Ankur Desai) Niwot Ridge, CO

-

About 1/3 lecture, 2/3 hands-on (the syllabus is actually wrong as it list the other way around). Each class has 24 students.

-

2013 Syllabus see Tuesday Week 2 Data Assimilation lectures and PEcAn demo and the Class projects and presentations on Thursday and Friday. (Most students use PEcAn for their group projects. 2014 will be the third year that PEcAn has been used for this course.

-
-
-

30.2.2 Assimilating Long-Term Data into Ecosystem Models: Paleo-Ecological Observatory Network (PalEON) Project

-

Here is a link to the course: https://www3.nd.edu/~paleolab/paleonproject/summer-course/

-

This course uses the same demo as above, including collecting data in the field and assimilating it (part 3)

-
-
-

30.2.3 Integrating Evidence on Forest Response to Climate Change: Physiology to Regional Abundance

-

http://blue.for.msu.edu/macrosystems/workshop

-

May 13-14, 2013

-

Session 4: Integrating Forest Data Into Ecosystem Models

-
-
-

30.2.4 Ecological Society of America meetings

-

Workshop: Combining Field Measurements and Ecosystem Models

-
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/tasks.html b/master/tasks.html deleted file mode 100644 index c3b46aa90..000000000 --- a/master/tasks.html +++ /dev/null @@ -1,865 +0,0 @@ - - - - - - - 17.9 Tasks | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

17.9 Tasks

-

Following is a list of tasks we plan on working on to improve these scripts: -- pecanproject/bety#368 allow site-specific customization of information and UI elements including title, contacts, logo, color scheme.

- -
- -
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/testing-the-shiny-server.html b/master/testing-the-shiny-server.html deleted file mode 100644 index 652aa220a..000000000 --- a/master/testing-the-shiny-server.html +++ /dev/null @@ -1,882 +0,0 @@ - - - - - - - 19.1 Testing the Shiny Server | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

19.1 Testing the Shiny Server

-

Shiny can be difficult to debug because, when run as a web service, the R output is hidden in system log files that are hard to find and read. -One useful approach to debugging is to use port forwarding, as follows.

-

First, on the remote machine (including the VM), make sure R’s working directory is set to the directory of the Shiny app (e.g., setwd(/path/to/pecan/shiny/WorkflowPlots), or just open the app as an RStudio project). -Then, in the R console, run the app as:

-
shiny::runApp(port = XXXX)
-# E.g. shiny::runApp(port = 5638)
-

Then, on your local machine, open a terminal and run the following command, matching XXXX to the port above and YYYY to any unused port on your local machine (any 4-digit number should work).

-
ssh -L YYYY:localhost:XXXX <remote connection>
-# E.g., for the PEcAn VM, given the above port:
-# ssh -L 5639:localhost:5638 carya@localhost -p 6422
-

Now, in a web browser on your local machine, browse to localhost:YYYY (e.g., localhost:5639) to run whatever app you started with shiny::runApp in the previous step. -All of the output should display in the R console where the shiny::runApp command was executed. -Note that this includes any print, message, logger.*, etc. statements in your Shiny app.

-

If the Shiny app hits an R error, the backtrace should include a line like Hit error at of server.R#LXX – that XX being a line number that you can use to track down the error. -To return from the error to a normal R prompt, hit <Control>-C (alternatively, the “Stop” button in RStudio). -To restart the app, run shiny::runApp(port = XXXX) again (keeping the same port).

-

Note that Shiny runs any code in the pecan/shiny/<app> directory at the moment the app is launched. -So, any changes you make to the code in server.R and ui.R or scripts loaded therein will take effect the next time the app is started.

-

If for whatever reason this doesn’t work with RStudio, you can always run R from the command line. -Also, note that the ability to forward ports (ssh -L) may depend on the ssh configuration of your remote machine. -These instructions have been tested on the PEcAn VM (v.1.5.2+).

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/the-pecan-docker-install-process-in-detail.html b/master/the-pecan-docker-install-process-in-detail.html deleted file mode 100644 index 0363c167e..000000000 --- a/master/the-pecan-docker-install-process-in-detail.html +++ /dev/null @@ -1,1035 +0,0 @@ - - - - - - - 25.3 The PEcAn docker install process in detail | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

25.3 The PEcAn docker install process in detail

-
-

25.3.1 Configure docker-compose

-

This section will let you download some configuration files. The documentation provides links to the latest released version (master branch in GitHub) or the develop version that we are working on (develop branch in GitHub) which will become the next release. If you cloned the PEcAn GitHub repository you can use git checkout <branch> to switch branches.

-

The PEcAn Docker stack is configured using a docker-compose.yml file. You can download just this file directly from GitHub latest or develop. You can also find this file in the root of cloned PEcAn GitHub repository. There is no need to edit the docker-compose.yml file. You can use either the .env file to change some of the settings, or the docker-compose.override.yml file to modify the docker-compose.yml file. This makes it easier for you to get an updated version of the docker-compose.yml file and not lose any changes you have made to it.

-

Some of the settings in the docker-compose.yml can be set using a .env file. You can download either the latest or the develop version. If you have cloned the GitHub repository it is also located in the docker folder. This file should be called .env and be placed in the same folder as your docker-compose.yml file. This file will allow you to set which version of PEcAn or BETY to use. See the comments in this file to control the settings. Option you might want to set are:

-
    -
  • PECAN_VERSION : The docker images to use for PEcAn. The default is latest which is the latest released version of PEcAn. Setting this to develop will result in using the version of PEcAn which will become the next release.
  • -
  • PECAN_FQDN : Is the name of the server where PEcAn is running. This is what is used to register all files generated by this version of PEcAn (see also TRAEFIK_HOST).
  • -
  • PECAN_NAME : A short name of this PEcAn server that is shown in the pull down menu and might be easier to recognize.
  • -
  • BETY_VERSION : This controls the version of BETY. The default is latest which is the latest released version of BETY. Setting this to develop will result in using the version of BETY which will become the next release.
  • -
  • TRAEFIK_HOST : Should be the FQDN of the server, this is needed when generating a SSL certificate. For SSL certificates you will need to set TRAEFIK_ACME_ENABLE as well as TRAEFIK_ACME_EMAIL.
  • -
  • TRAEFIK_IPFILTER : is used to limit access to certain resources, such as RabbitMQ and the Traefik dashboard.
  • -
-

A final file, which is optional, is a docker-compose.override.yml. You can download a version for the latest and develop versions. If you have cloned the GitHub repository it is located in the docker folder. Use this file as an example of what you can do, only copy the pieces over that you really need. This will allow you to make changes to the docker-compose file for your local installation. You can use this to add additional containers to your stack, change the path where docker stores the data for the containers, or you can use this to open up the postgresql port.

-
version: "3"
-
-services:
-  # expose database to localhost for ease of access
-  postgres:
-    ports:
-      - 5432:5432
-

Once you have the docker-compose.yml file as well as the optional .env and docker-compose.override.yml in a folder you can start the PEcAn stack. The following instructions assume you are in the same directory as the file (if not, cd into it).

-

In the rest of this section we will use a few arguments for the docker-compose application. The location of these arguments are important. The general syntax of docker-compose is docker-compose <ARGUMENTS FOR DOCKER COMPOSE> <COMMAND> <ARGUMENTS FOR COMMAND> [SERVICES]. More generally, docker-compose options are very sensitive to their location relative to other commands in the same line – that is, docker-compose -f /my/docker-compose.yml -p pecan up -d postgres is not the same as docker-compose -d postgres -p pecan up -f /my/docker-compose.yml. If expected ever don’t seem to be working, check that the arguments are in the right order.)

-
    -
  • -f <filename> : ARGUMENTS FOR DOCKER COMPOSE : Allows you to specify a docker-compose.yml file explicitly. You can use this argument multiple times. Default is to use the docker-compose.yml and docker-compose.override.yml in your current folder.
  • -
  • -p <projectname> : ARGUMENTS FOR DOCKER COMPOSE : Project name, all volumes, networks, and containers will be prefixed with this argument. The default value is to use the current folder name.
  • -
  • -d : ARGUMENTS FOR up COMMAND : Will start all the containers in the background and return back to the command shell.
  • -
-

If no services as added to the docker-compose command all services possible will be started.

-
-
-

25.3.2 Initialize PEcAn (first time only)

-

Before you can start to use PEcAn for the first time you will need to initialize the database (and optionally add some data). The following two sections will first initialize the database and secondly add some data to the system.

-
-

25.3.2.1 Initialize the PEcAn database

-

The commands described in this section will set up the PEcAn database (BETY) and pre-load it with some common “default” data.

-
docker-compose -p pecan up -d postgres
-
-# If you have a custom docker-compose file:
-# docker-compose -f /path/to/my-docker-compose.yml -p pecan up -d postgres
-

The breakdown of this command is as follows:

-
    -
  • -p pecan – This tells docker-compose to do all of this as part of a “project” -p we’ll call pecan. By default, the project name is set to the name of the current working directory. The project name will be used as a prefix to all containers started by this docker-compose instance (so, if we have a service called postgres, this will create a container called pecan_postgres).
  • -
  • up -dup is a command that initializes the containers. Initialization involves downloading and building the target containers and any containers they depend on, and then running them. Normally, this happens in the foreground, printing logs directly to stderr/stdout (meaning you would have to interrupt it with Ctrl-C), but the -d flag forces this to happen more quietly and in the background.
  • -
  • postgres – This indicates that we only want to initialize the service called postgres (and its dependencies). If we omitted this, docker-compose would initialize all containers in the stack.
  • -
-

The end result of this command is to initialize a “blank” PostGIS container that will run in the background. -This container is not connected to any data (yet), and is basically analogous to just installing and starting PostgreSQL to your system. -As a side effect, the above command will also create blank data “volumes” and a “network” that containers will use to communicate with each other. -Because our project is called pecan and docker-compose.yml describes a network called pecan, the resulting network is called pecan_pecan. -This is relevant to the following commands, which will actually initialize and populate the BETY database.

-

Assuming the above has run successfully, next run the following:

-
docker run --rm --network pecan_pecan pecan/db
-

The breakdown of this command is as follows: {#docker-run-init}

-
    -
  • docker run – This says we will be running a container.
  • -
  • --rm – This automatically removes the resulting container once the specified command exits, as well as any volumes associated with the container. This is useful as a general “clean-up” flag for one-off commands (like this one) to make sure you don’t leave any “zombie” containers or volumes around at the end.
  • -
  • --network pecan_pecan – Thsi will start the container in the same network space as the posgres container, allowing it to push data into the database.
  • -
  • pecan/db – This is the name of the container, this holds a copy of the database used to initialize the postgresql database.
  • -
-

Note that this command may throw a bunch of errors related to functions and/or operators already existing. -This is normal – it just means that the PostGIS extension to PostgreSQL is already installed. -The important thing is that you see output near the end like:

-
----------------------------------------------------------------------
-Safety checks
-
-----------------------------------------------------------------------
-
-----------------------------------------------------------------------
-Making sure user 'bety' exists.
-

If you do not see this output, you can look at the troubleshooting section at the end of this section for some troubleshooting tips, as well as some solutions to common problems.

-

Once the command has finished successfully, proceed with the next step which will load some initial data into the database and place the data in the docker volumes.

-
-
-

25.3.2.2 Add first user to PEcAn database

-

You can add an initial user to the BETY database, for example the following commands will add the guestuser account as well as the demo carya account:

-
# guest user
-docker-compose run --rm bety user guestuser guestuser "Guest User" guestuser@example.com 4 4
-
-# example user
-docker-compose run --rm bety user carya illinois "Carya Demo User" carya@example.com 1 1
-
-
-

25.3.2.3 Add example data (first time only)

-

The following command will add some initial data to the PEcAn stack and register the data with the database.

-
docker run -ti --rm --network pecan_pecan --volume pecan_pecan:/data --env FQDN=docker pecan/data:develop
-

The breakdown of this command is as follows:

-
    -
  • docker run – This says we will be running a specific command inside the target Docker container. See docker run --help and the Docker run reference for more information.
  • -
  • -ti – This is actually two flags, -t to allocate a pseudo-tty and -i to keep STDIN open even if detached. -t is necessary to ensure lower-level script commands run correctly. -i makes sure that the command output (stdin) is displayed.
  • -
  • --rm – This automatically removes the resulting container once the specified command exits, as well as any volumes associated with the container. This is useful as a general “clean-up” flag for one-off commands (like this one) to make sure you don’t leave any “zombie” containers or volumes around at the end.
  • -
  • --network pecan_pecan – This indicates that the container will use the existing pecan_pecan network. This network is what ensures communication between the postgres container (which, recall, is just a PostGIS installation with some data) and the “volumes” where the actual data are persistently stored.
  • -
  • pecan/data:develop – This is the name of the image in which to run the specified command, in the form repository/image:version. This is interpreted as follows: -
      -
    • First, it sees if there are any images called pecan/data:develop available on your local machine. If there are, it uses that one.
    • -
    • If that image version is not available locally, it will next try to find the image online. By default, it searches Docker Hub, such that pecan/data gets expanded to the container at https://hub.docker.com/r/pecan/data. For custom repositories, a full name can be given, such as hub.ncsa.illinois.edu/pecan/data:latest.
    • -
    • If :version is omitted, Docker assumes :latest. NOTE that while online containers should have a :latest version, not all of them do, and if a :latest version does not exist, Docker will be unable to find the image and will throw an error.
    • -
  • -
  • Everything after the image name (here, pecan/data:develop) is interpreted as an argument to the image’s specified entrypoint.
  • -
  • --volume pecan_pecan:/data – This mounts the data from the subsequent container (pecan/data:develop) onto the current project volume, called pecan_pecan (as with the network, the project name pecan is the prefix, and the volume name also happens to be pecan as specified in the docker-compose.yml file).
  • -
  • --env FQDN=docker – the Fully Qualified Domain Name, this is the same value as specified in the .env file (for the web, monitor and executor containers). This will link the data files to the name in the machines table in BETY.
  • -
  • pecan/data:develop – As above, this is the target image to run. Since there is no argument after the image name, this command will run the default command (CMD) specified for this docker container. In this case, it is the docker/add_data.sh script from the PEcAn repository.
  • -
-

Under the hood, this container runs the docker/add-data.sh script, which copies a bunch of input files and registers them with the PEcAn database.

-

Successful execution of this command should take some time because it involves copying reasonably large amounts of data and performing a number of database operations.

-
-
-

25.3.2.4 Start PEcAn

-

If you already completed the above steps, you can start the full stack by just running the following:

-
docker-compose -p pecan up -d
-

This will build and start all containers required to run PEcAn. -With the -d flag, this will run all of these containers quietly in the background, and show a nice architecture diagram with the name and status of each container while they are starting. -Once this is done you have a working instance of PEcAn.

-

If all of the containers started successfully, you should be able to access the various components from a browser via the following URLs (if you run these commands on a remote machine replace localhost with the actual hostname).

- -
-
-

25.3.2.5 Start model runs using curl

-

To test PEcAn you can use the following curl statement, or use the webpage to submit a request (if you run these commands on a remote machine replace localhost with the actual hostname):

-
curl -v -X POST \
-    -F 'hostname=docker' \
-    -F 'modelid=5000000002' \
-    -F 'sitegroupid=1' \
-    -F 'siteid=772' \
-    -F 'sitename=Niwot Ridge Forest/LTER NWT1 (US-NR1)' \
-    -F 'pft[]=temperate.coniferous' \
-    -F 'start=2004/01/01' \
-    -F 'end=2004/12/31' \
-    -F 'input_met=5000000005' \
-    -F 'email=' \
-    -F 'notes=' \
-    'http://pecan.localhost/pecan/04-runpecan.php'
-

This should return some text with in there Location: this is shows the workflow id, you can prepend http://pecan.localhost/pecan/ to the front of this, for example: http://pecan.localhost/pecan/05-running.php?workflowid=99000000001. Here you will be able to see the progress of the workflow.

-

To see what is happening behind the scenes you can use look at the log file of the specific docker containers, once of interest are pecan_executor_1 this is the container that will execute a single workflow and pecan_sipnet_1 which executes the sipnet mode. To see the logs you use docker logs pecan_executor_1 Following is an example output:

-
2018-06-13 15:50:37,903 [MainThread     ] INFO    : pika.adapters.base_connection - Connecting to 172.18.0.2:5672
-2018-06-13 15:50:37,924 [MainThread     ] INFO    : pika.adapters.blocking_connection - Created channel=1
-2018-06-13 15:50:37,941 [MainThread     ] INFO    : root -  [*] Waiting for messages. To exit press CTRL+C
-2018-06-13 19:44:49,523 [MainThread     ] INFO    : root - b'{"folder": "/data/workflows/PEcAn_99000000001", "workflowid": "99000000001"}'
-2018-06-13 19:44:49,524 [MainThread     ] INFO    : root - Starting job in /data/workflows/PEcAn_99000000001.
-2018-06-13 19:45:15,555 [MainThread     ] INFO    : root - Finished running job.
-

This shows that the executor connects to RabbitMQ, waits for messages. Once it picks up a message it will print the message, and execute the workflow in the folder passed in with the message. Once the workflow (including any model executions) is finished it will print Finished. The log file for pecan_sipnet_1 is very similar, in this case it runs the job.sh in the run folder.

-

To run multiple executors in parallel you can duplicate the executor section in the docker-compose file and just rename it from executor to executor1 and executor2 for example. The same can be done for the models. To make this easier it helps to deploy the containers using Kubernetes allowing to easily scale up and down the containers.

-
-
-
-

25.3.3 Troubleshooting

-

When initializing the database, you will know you have encountered more serious errors if the command exits or hangs with output resembling the following:

-
LINE 1: SELECT count(*) FROM formats WHERE ...
-                             ^
-Error: Relation `formats` does not exist
-

If the above command fails, you can try to fix things interactively by first opening a shell inside the container…

-
docker run -ti --rm --network pecan_pecan pecan/bety:latest /bin/bash
-

…and then running the following commands, which emulate the functionality of the entrypoint.sh with the initialize argument.

-
# Create the bety role in the postgresql database
-psql -h postgres -p 5432 -U postgres -c "CREATE ROLE bety WITH LOGIN CREATEDB NOSUPERUSER NOCREATEROLE PASSWORD 'bety'"
-
-# Initialize the bety database itself, and set to be owned by role bety
-psql -h postgres -p 5432 -U postgres -c "CREATE DATABASE bety WITH OWNER bety"
-
-# If either of these fail with a "role/database bety already exists",
-# that's fine. You can safely proceed to the next command.
-
-# Load the actual bety database tables and values
-./script/load.bety.sh -a "postgres" -d "bety" -p "-h postgres -p 5432" -o bety -c -u -g -m ${LOCAL_SERVER} -r 0 -w https://ebi-forecast.igb.illinois.edu/pecan/dump/all/bety.tar.gz
- -
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/thredds-setup.html b/master/thredds-setup.html deleted file mode 100644 index 7c7788754..000000000 --- a/master/thredds-setup.html +++ /dev/null @@ -1,1181 +0,0 @@ - - - - - - - 24.4 Thredds Setup | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

24.4 Thredds Setup

-

Installing and configuring Thredds for PEcAn -authors - Rob Kooper

-

NOTE: Instructions are only tested for Ubuntu 16.04 on the VM, if you have instructions for CENTOS/RedHat please update this documentation -NOTE: Pretty much every step here requires root access.

-
-

24.4.1 Install the Tomcat 8 and Thredds webapp

-

The Tomcat 8 server can be installed from the default Ubuntu repositories. The thredds webapp will be downloaded and installed from unidata.

-

First step is to install Tomcat 8 and configure it. The flag -Dtds.content.root.path should point to the location of where the thredds folder is located. This needs to be writeable by the user for tomcat. -Djava.security.egd is a special flag to use a different random number generator for tomcat. The default would take to long to generate a random number.

-
apt-get -y install tomcat8 openjdk-8-jdk
-echo JAVA_OPTS=\"-Dtds.content.root.path=/home/carya \${JAVA_OPTS}\" >> /etc/default/tomcat8
-echo JAVA_OPTS=\"-Djava.security.egd=file:/dev/./urandom \${JAVA_OPTS}\" >> /etc/default/tomcat8
-service tomcat8 restart
-

Next is to install the webapp.

-
mkdir /home/carya/thredds
-chmod 777 /home/carya/thredds
-
-wget -O /var/lib/tomcat8/webapps/thredds.war ftp://ftp.unidata.ucar.edu/pub/thredds/4.6/current/thredds.war
-

Finally we configure Apache to prox the thredds server

-
cat > /etc/apache2/conf-available/thredds.conf << EOF
-ProxyPass        /thredds/ http://localhost:8080/thredds/
-ProxyPassReverse /thredds/ http://localhost:8080/thredds/
-RedirectMatch permanent ^/thredds$ /thredds/
-EOF
-a2enmod proxy_http
-a2enconf thredds
-service apache2 reload
-
-

24.4.1.1 Customize the Thredds server

-

To customize the thredds server for your installation edit the file in /home/carya/thredds/threddsConfig.xml. For example the following file is included in the VM.

-
<?xml version="1.0" encoding="UTF-8"?>
-<threddsConfig>
-
-  <!-- all options are commented out in standard install - meaning use default values -->
-  <!-- see http://www.unidata.ucar.edu/software/thredds/current/tds/reference/ThreddsConfigXMLFile.html -->
-  <serverInformation>
-    <name>PEcAn</name>
-    <logoUrl>/pecan/images/pecan_small.jpg</logoUrl>
-    <logoAltText>PEcAn</logoAltText>
-
-    <abstract>Scientific Data</abstract>
-    <keywords>meteorology, atmosphere, climate, ocean, earth science</keywords>
-    
-    <contact>
-      <name>Rob Kooper</name>
-      <organization>NCSA</organization>
-      <email>kooper@illinois.edu</email>
-      <!--phone></phone-->
-    </contact>
-    <hostInstitution>
-      <name>PEcAn</name>
-      <webSite>http://www.pecanproject.org/</webSite>
-      <logoUrl>/pecan/images/pecan_small.jpg</logoUrl>
-      <logoAltText>PEcAn Project</logoAltText>
-    </hostInstitution>
-  </serverInformation>
-
-  <!--
-  The <catalogRoot> element:
-  For catalogs you don't want visible from the /thredds/catalog.xml chain
-  of catalogs, you can use catalogRoot elements. Each catalog root config
-  catalog is crawled and used in configuring the TDS.
-
-  <catalogRoot>myExtraCatalog.xml</catalogRoot>
-  <catalogRoot>myOtherExtraCatalog.xml</catalogRoot>
-  -->
-
-  <!--
-   * Setup for generated HTML pages.
-   *
-   * NOTE: URLs may be absolute or relative, relative URLs must be relative
-   * to the webapp URL, i.e., http://server:port/thredds/.
-    -->
-  <htmlSetup>
-    <!--
-     * CSS documents used in generated HTML pages.
-     * The CSS document given in the "catalogCssUrl" element is used for all pages
-     * that are HTML catalog views. The CSS document given in the "standardCssUrl"
-     * element is used in all other generated HTML pages.
-     * -->
-    <standardCssUrl>tds.css</standardCssUrl>
-    <catalogCssUrl>tdsCat.css</catalogCssUrl>
-    <openDapCssUrl>tdsDap.css</openDapCssUrl>
-
-    <!--
-     * The Google Analytics Tracking code you would like to use for the
-     * webpages associated with THREDDS. This will not track WMS or DAP
-     * requests for data, only browsing the catalog.
-    -->
-    <googleTrackingCode></googleTrackingCode>
-
-  </htmlSetup>
-  
-  <!-- 
-    The <TdsUpdateConfig> element controls if and how the TDS checks
-    for updates. The default is for the TDS to check for the current
-    stable and development release versions, and to log that information
-    in the TDS serverStartup.log file as INFO entries.
-
-  <TdsUpdateConfig>
-     <logVersionInfo>true</logVersionInfo>
-  </TdsUpdateConfig>
-  -->
-   
-  <!--
-   The <CORS> element controls Cross-Origin Resource Sharing (CORS).
-   CORS is a way to allow a website (such as THREDDS) to open up access
-   to resources to web pages and applications running on a different domain.
-   One example would be allowing a web-application to use fonts from
-   a separate host. For TDS, this can allow a javascript app running on a
-   different site to access data on a THREDDS server.
-   For more information see: https://en.wikipedia.org/wiki/Cross-origin_resource_sharing
-   The elements below represent defaults. Only the <enabled> tag is required
-   to enable CORS. The default allowed origin is '*', which allows sharing
-   to any domain.
-  <CORS>
-    <enabled>false</enabled>
-    <maxAge>1728000</maxAge>
-    <allowedMethods>GET</allowedMethods>
-    <allowedHeaders>Authorization</allowedHeaders>
-    <allowedOrigin>*</allowedOrigin>
-  </CORS>
-  -->
-
-  <!--
-   The <CatalogServices> element:
-   - Services on local TDS served catalogs are always on.
-   - Services on remote catalogs are set with the allowRemote element
-   below. They are off by default (recommended).
-   -->
-  <CatalogServices>
-    <allowRemote>false</allowRemote>
-  </CatalogServices>
-
-  <!--
-  Configuring the CDM (netcdf-java library)
-  see http://www.unidata.ucar.edu/software/netcdf-java/reference/RuntimeLoading.html
-
-  <nj22Config>
-    <ioServiceProvider class="edu.univ.ny.stuff.FooFiles"/>
-    <coordSysBuilder convention="foo" class="test.Foo"/>
-    <coordTransBuilder name="atmos_ln_sigma_coordinates" type="vertical" class="my.stuff.atmosSigmaLog"/>
-    <typedDatasetFactory datatype="Point" class="gov.noaa.obscure.file.Flabulate"/>
-  </nj22Config>
-  -->
-
-  <!--
-  CDM uses the DiskCache directory to store temporary files, like uncompressed files.
-  <DiskCache>
-    <alwaysUse>false</alwaysUse>
-    <scour>1 hour</scour>
-    <maxSize>1 Gb</maxSize>
-  </DiskCache>
-  -->
-
-  <!--
-  Caching open NetcdfFile objects.
-  default is to allow 50 - 100 open files, cleanup every 11 minutes
-  <NetcdfFileCache>
-    <minFiles>50</minFiles>
-    <maxFiles>100</maxFiles>
-    <scour>11 min</scour>
-  </NetcdfFileCache>
-  -->
-
-  <!--
-  The <HTTPFileCache> element:
-  allow 10 - 20 open datasets, cleanup every 17 minutes
-  used by HTTP Range requests.
-  <HTTPFileCache>
-    <minFiles>10</minFiles>
-    <maxFiles>20</maxFiles>
-    <scour>17 min</scour>
-  </HTTPFileCache>
-  -->
-
-  <!--
-  Writing GRIB indexes.
-  <GribIndexing>
-    <setExtendIndex>false</setExtendIndex>
-    <alwaysUseCache>false</alwaysUseCache>
-  </GribIndexing>
-  -->
-
-  <!--
-  Persist joinNew aggregations to named directory. scour every 24 hours, delete stuff older than 90 days
-  <AggregationCache>
-    <scour>24 hours</scour>
-    <maxAge>90 days</maxAge>
-    <cachePathPolicy>NestedDirectory</cachePathPolicy>
-  </AggregationCache>
-  -->
-
-  <!--
-  How to choose the template dataset for an aggregation. latest, random, or penultimate
-  <Aggregation>
-    <typicalDataset>penultimate</typicalDataset>
-  </Aggregation>
-  -->
-
-  <!--
-  The Netcdf Subset Service is off by default.
-  <NetcdfSubsetService>
-    <allow>false</allow>
-    <scour>10 min</scour>
-    <maxAge>-1 min</maxAge>
-  </NetcdfSubsetService>
-  -->
-
-  <!--
-  <Opendap>
-    <ascLimit>50</ascLimit>
-    <binLimit>500</binLimit>
-    <serverVersion>opendap/3.7</serverVersion>
-  </Opendap>
-    -->
-  
-  <!--
-  The WCS Service is off by default.
-  Also, off by default (and encouraged) is operating on a remote dataset.
-  <WCS>
-    <allow>false</allow>
-    <allowRemote>false</allowRemote>
-    <scour>15 min</scour>
-    <maxAge>30 min</maxAge>
-  </WCS>
-  -->
-
-  <!--
-  <WMS>
-    <allow>false</allow>
-    <allowRemote>false</allowRemote>
-    <maxImageWidth>2048</maxImageWidth>
-    <maxImageHeight>2048</maxImageHeight>
-  </WMS>
-  -->
-
-  <!--
-  <NCISO>
-    <ncmlAllow>false</ncmlAllow>
-    <uddcAllow>false</uddcAllow>
-    <isoAllow>false</isoAllow>
-  </NCISO>
-  -->
-
-  <!-- CatalogGen service is off by default.
-  <CatalogGen>
-    <allow>false</allow>
-  </CatalogGen>
-   -->
-
-  <!-- DLwriter service is off by default.
-       As is support for operating on remote catalogs.
-  <DLwriter>
-    <allow>false</allow>
-    <allowRemote>false</allowRemote>
-  </DLwriter>
-   -->
-
-  <!-- DqcService is off by default.
-  <DqcService>
-    <allow>false</allow>
-  </DqcService>
-   -->
-
-  <!--
-   Link to a Viewer application on the HTML page:
-   <Viewer>my.package.MyViewer</Viewer>
-   -->
-
-   <!--
-   Add a DataSource - essentially an IOSP with access to Servlet request parameters
-   <datasetSource>my.package.DatsetSourceImpl</datasetSource>
-   -->
-
-  <!--
-   set FeatureCollection logging
-  <FeatureCollection>
-     <RollingFileAppender>
-       <MaxFileSize>1 MB</MaxFileSize>
-       <MaxBackups>5</MaxBackups>
-       <Level>INFO</Level>
-     </RollingFileAppender>
-  </FeatureCollection>
-  -->
-
-  <!--
-    Configure how the NetCDF-4 C library is discovered and used.
-    libraryPath: The directory in which the native library is installed.
-    libraryName: The name of the native library. This will be used to locate the proper .DLL, .SO, or .DYLIB file
-      within the libraryPath directory.
-    useForReading: By default, the native library is only used for writing NetCDF-4 files; a pure-Java layer is
-      responsible for reading them. However, if this property is set to true, then it will be used for reading
-      NetCDF-4 (and HDF5) files as well.
-  -->
-  <!--
-  <Netcdf4Clibrary>
-    <libraryPath>/usr/local/lib</libraryPath>
-    <libraryName>netcdf</libraryName>
-    <useForReading>false</useForReading>
-  </Netcdf4Clibrary>
-  -->
-</threddsConfig>
-
-
-
-

24.4.2 Update the catalog

-

For example to update the catalog with the latest data, run the following command from the root crontab. This cronjob will also synchronize the database with remote servers and dump your database (by default in /home/carya/dump)

-
0 * * * * /home/carya/pecan/scripts/cron.sh -o /home/carya/dump
-
-
-

24.4.3 Troubleshooting

-

Refer to the log files for Tomcat (/var/log/tomcat8/*) and Thredds (/home/carya/thredds/logs).

-
-
-

24.4.4 Further reading

- - -
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/time-standard.html b/master/time-standard.html deleted file mode 100644 index e0fbf1bde..000000000 --- a/master/time-standard.html +++ /dev/null @@ -1,935 +0,0 @@ - - - - - - - 11.2 Time Standard | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

11.2 Time Standard

-

Internal PEcAn standard time follows ISO_8601 format for dates and time (https://en.wikipedia.org/wiki/ISO_8601). For example ordinal dates go from 1 365/366 (https://en.wikipedia.org/wiki/ISO_8601#Ordinal_dates). However, time used in met drivers or model outputs follows CF convention with julian dates following the 0 to 364/365 format

-

To aid in the conversion between PEcAn internal ISO_8601 standard and CF convention used in all met drivers and PEcAn standard output you can utilize the functions: “cf2datetime”,“datetime2doy”,“cf2doy”, and for SIPNET “sipnet2datetime”

-
-

11.2.1 Input Standards

-
-

11.2.1.1 Meterology Standards

-
-
11.2.1.1.1 Dimensions:
- - - - - - - - - - - - - - - - - - - - - -
CF standard-nameunits
timedays since 1700-01-01 00:00:00 UTC
longitudedegrees_east
latitudedegrees_north
-

General Note: dates in the database should be date-time (preferably with timezone), and datetime passed around in PEcAn should be of type POSIXct.

-
-
-
11.2.1.1.2 The variable names should be standard_name
-
- -
    -
  • preferred variables indicated in bold
  • -
  • wind_direction has no CF equivalent and should not be converted, instead the met2CF functions should convert wind_direction and wind_speed to eastward_wind and northward_wind
  • -
  • standard_name is CF-convention standard names
  • -
  • units can be converted by udunits, so these can vary (e.g. the time denominator may change with time frequency of inputs)
  • -
  • soil moisture for the full column, rather than a layer, is soil_moisture_content
  • -
  • A full list of PEcAn standard variable names, units and dimensions can be found here: https://github.com/PecanProject/pecan/blob/develop/base/utils/data/standard_vars.csv
  • -
-

For example, in the MsTMIP-CRUNCEP data, the variable rain should be precipitation_rate. -We want to standardize the units as well as part of the met2CF.<product> step. I believe we want to use the CF “canonical” units but retain the MsTMIP units any time CF is ambiguous about the units.

-

The key is to process each type of met data (site, reanalysis, forecast, climate scenario, etc) to the exact same standard. This way every operation after that (extract, gap fill, downscale, convert to a model, etc) will always have the exact same inputs. This will make everything else much simpler to code and allow us to avoid a lot of unnecessary data checking, tests, etc being repeated in every downstream function.

-
-
-
-
-

11.2.2 Soils and Vegetation Inputs

-
-
11.2.2.0.1 Soil Data
-

Check out the Soil Data section on more into on creating a standard soil data file.

-
-
-
11.2.2.0.2 Vegetation Data
-

Check Out the Vegetation Data section on more info on creating a standard vegetation data file

-
-
-
-

11.2.3 Output Standards

-
    -
  • created by model2netcdf functions
  • -
  • based on format used by MsTMIP
  • -
  • Can be seen at HERE
  • -
-

We originally used the MsTMIP conventions. Since then, we’ve added the PaLEON variable conventions to our standard as well. If a variable isn’t in one of those two, we stick to the CF conventions.

-
- - -
-
- -
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/todo.html b/master/todo.html deleted file mode 100644 index ea583e683..000000000 --- a/master/todo.html +++ /dev/null @@ -1,864 +0,0 @@ - - - - - - - 28.1 TODO | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

28.1 TODO

-
    -
  • Add list of developers
  • -
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/troubleshooting-1.html b/master/troubleshooting-1.html deleted file mode 100644 index ef0bdff54..000000000 --- a/master/troubleshooting-1.html +++ /dev/null @@ -1,876 +0,0 @@ - - - - - - - 17.7 Troubleshooting | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

17.7 Troubleshooting

-

There are several possibilities if a scheduled cron job apepars to be running but isn’t producing the expected results. The following are suggestions on what to try to resolve the issue.

-
-

17.7.1 Username and password

-

The user that scheduled a cron job may not have access permissions to the database. This can be easily confirmed by running the command line from the cron job while logged in as the user that scheduled the job. An error message will be shown if the user doesn’t have permissions.

-

To resolve this, be sure to include a valid database user (not a BETYdb user) with their credentials on the command in crontab.

-
-
-

17.7.2 db_hba.conf file

-

Iit’s possible that the machine hosting the docker image of the database doesn’t have permissions to access the database. This may due to the cron job running on a machine that is not the docker instance of the database.

-

It may be necessary to look at the loga on the hosting machine to determine if database access permissions are causing a problem. Logs are stored in different locations depending upon the Operating System of the host and upon other environmental factors. This document doesn’t provide information on where to find the logs.

-

To begin, it’s best to look at the contents of the relevent database configuration file. The following command will display the contents of the db_hba.conf file.

-
psql -U postgres -qAt -c "show hba_file" | xargs grep -v -E '^[[:space:]]*#'
-

This command should return a series of text lines. For each row except those begining with ‘local’, the fourth item describes the machines that can access the database. In some cases an IP mask is specified in the fifth that further restricts the machines that have access. The special work ‘all’ in the fourth column grants permissions to all machines. The last column on each line contains the authentication option for the machine(s) specified in the fourth column (with a possible fifth column IP mask modifier).

-

Ensure that the host machine is listed under the fourth column (machine addresse range, or ‘all’), is also included in the IP mask if one was specified, and finally that any authentication option are not set to ‘reject’. If the host machine is not included the db_hba.conf file will need to be updated to allow access.

-
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/troubleshooting-and-debugging-pecan.html b/master/troubleshooting-and-debugging-pecan.html deleted file mode 100644 index 47e3b4dbf..000000000 --- a/master/troubleshooting-and-debugging-pecan.html +++ /dev/null @@ -1,861 +0,0 @@ - - - - - - - 21 Troubleshooting and Debugging PEcAn | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

21 Troubleshooting and Debugging PEcAn

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/university-classes.html b/master/university-classes.html deleted file mode 100644 index 96a0cdd72..000000000 --- a/master/university-classes.html +++ /dev/null @@ -1,866 +0,0 @@ - - - - - - - 30.1 University classes | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

30.1 University classes

-
-

30.1.1 GE 375 - Environmental Modeling - Spring 2013, 2014 (Mike Dietze, Boston University)

-

The final “Case Study: Terrestrial Ecosystem Models” is a PEcAn-based hands-on activity. Each class has been 25 students.

-

GE 585 - Ecological forecasting Fall 2013 (Mike Dietze, Boston University)

-
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/updatebety.html b/master/updatebety.html deleted file mode 100644 index 4905df5f3..000000000 --- a/master/updatebety.html +++ /dev/null @@ -1,893 +0,0 @@ - - - - - - - 8.1 Updating PEcAn Code and Bety Database | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

8.1 Updating PEcAn Code and Bety Database

-

Release notes for all releases can be found here.

-

This page will only list any steps you have to do to upgrade an existing system. When updating PEcAn it is highly encouraged to update BETY. You can find instructions on how to do this, as well on how to update the database in the Updating BETYdb gitbook page.

-
-

8.1.1 Updating PEcAn

-

The latest version of PEcAn code can be obtained from the PEcAn repository on GitHub:

-
cd pecan        # If you are not already in the PEcAn directory
-git pull
-

The PEcAn build system is based on GNU Make. -The simplest way to install is to run make from inside the PEcAn directory. -This will update the documentation for all packages and install them, as well as all required dependencies.

-

For more control, the following make commands are available:

-
    -
  • make document – Use devtools::document to update the documentation for all package. -Under the hood, this uses the roxygen2 documentation system.

  • -
  • make install – Install all packages and their dependnencies using devtools::install. -By default, this only installs packages that have had their code changed and any dependent packages.

  • -
  • make check – Perform a rigorous check of packages using devtools::check

  • -
  • make test – Run all unit tests (based on testthat package) for all packages, using devtools::test

  • -
  • make clean – Remove the make build cache, which is used to track which packages have changed. -Cache files are stored in the .doc, .install, .check, and .test subdirectories in the PEcAn main directory. -Running make clean will force the next invocation of make commands to operate on all PEcAn packages, regardless of changes.

  • -
-

The following are some additional make tricks that may be useful:

-
    -
  • Install, check, document, or test a specific package – make .<cmd>/<pkg-dir>; e.g. make .install/utils or make .check/modules/rtm

  • -
  • Force make to run, even if package has not changed – make -B <command>

  • -
  • Run make commands in parallel – make -j<ncores>; e.g. make -j4 install to install packages using four parallel processes. Note that packages containing compiled code (e.g. PEcAn.RTM, PEcAn.BASGRA) might fail when j is greater than 1, because of limitations in the way R calls make internally while compiling them. See GitHub issue 1976 for more details.

  • -
-

All instructions for the make build system are contained in the Makefile in the PEcAn root directory. -For full documentation on make, see the man pages by running man make from a terminal.

- -
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/useful-scripts.html b/master/useful-scripts.html deleted file mode 100644 index 9f89b0181..000000000 --- a/master/useful-scripts.html +++ /dev/null @@ -1,868 +0,0 @@ - - - - - - - 21.5 Useful scripts | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

21.5 Useful scripts

-

The following scripts (in qaqc/vignettes identify, respectively:

-
    -
  1. relationships among functions across packages
  2. -
  3. function inputs and outputs (e.g. that will identify which functions and outputs are used in a workflow).
  4. -
- -
- -
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/user-section.html b/master/user-section.html deleted file mode 100644 index 06bc7d103..000000000 --- a/master/user-section.html +++ /dev/null @@ -1,861 +0,0 @@ - - - - - - - 5 Tutorials | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

5 Tutorials

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/using-the-pecan-download_file-function.html b/master/using-the-pecan-download_file-function.html deleted file mode 100644 index 909a16717..000000000 --- a/master/using-the-pecan-download_file-function.html +++ /dev/null @@ -1,918 +0,0 @@ - - - - - - - 28.2 Using the PEcAn download_file() function | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

28.2 Using the PEcAn download_file() function

-

download_file(url, destination_file, method)
-

-

This custom PEcAn function works together with the base R function download.file (https://stat.ethz.ch/R-manual/R-devel/library/utils/html/download.file.html). However, it provides expanded functionality to generalize the use for a broad range of environments. This is because some computing environments are behind a firewall or proxy, including FTP firewalls. This may require the use of a custom FTP program and/or initial proxy server authentication to retrieve the files needed by PEcAn (e.g. meteorology drivers, other inputs) to run certain model simulations or tools. For example, the Brookhaven National Laboratory (BNL) requires an initial connection to a FTP proxy before downloading files via FTP protocol. As a result, the computers running PEcAn behind the BNL firewall (e.g. https://modex.bnl.gov) use the ncftp cleint (http://www.ncftp.com/) to download files for PEcAn because the base options with R::base download.file() such as curl, libcurl which don’t have the functionality to provide credentials for a proxy or even those such as wget which do but don’t easily allow for connecting through a proxy server before downloading files. The current option for use in these instances is ncftp, specifically ncftpget

-


-

Examples:
-HTTP

-
download_file("http://lib.stat.cmu.edu/datasets/csb/ch11b.txt","~/test.download.txt") 
-

FTP

-
download_file("ftp://ftp.cdc.noaa.gov/Datasets/NARR/monolevel/pres.sfc.2000.nc", "~/pres.sfc.2000.nc")
-

customizing to use ncftp when running behind an FTP firewall (requires ncftp to be installed and availible)

-
download_file("ftp://ftp.cdc.noaa.gov/Datasets/NARR/monolevel/pres.sfc.2000.nc", "~/pres.sfc.2000.nc", method=""ncftpget")
-


-

On modex.bnl.gov, the ncftp firewall configuration file (e.g. ~/.ncftp/firewall) is configured as: -firewall-type=1 -firewall-host=ftpgateway.sec.bnl.local -firewall-port=21

-

which then allows for direct connection through the firewall using a command like:

-
ncftpget ftp://ftp.unidata.ucar.edu/pub/netcdf/netcdf-fortran-4.4.4.tar.gz
-

To allow the use of ncftpget from within the download.file() function you need to set your R profile download.ftp.method option in your options list. To see your current R options run options() from R cmd, which should look something like this:

-
> options()
-$add.smooth
-[1] TRUE
-
-$bitmapType
-[1] "cairo"
-
-$browser
-[1] "/usr/bin/xdg-open"
-
-$browserNLdisabled
-[1] FALSE
-
-$CBoundsCheck
-[1] FALSE
-
-$check.bounds
-[1] FALSE
-
-$citation.bibtex.max
-[1] 1
-
-$continue
-[1] "+ "
-
-$contrasts
-        unordered           ordered
-"contr.treatment"      "contr.poly"
-

In order to set your download.ftp.method option you need to add a line such as

-
# set default FTP
-options(download.ftp.method = "ncftpget")
-

In your ~/.Rprofile. On modex at BNL we have set the global option in /usr/lib64/R/etc/Rprofile.site.

-

Once this is done you should be able to see the option set using this command in R:

-
> options("download.ftp.method")
-$download.ftp.method
-[1] "ncftpget"
- -
- -
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/warning-mkdir-function.mkdir-no-such-file-or-directory.html b/master/warning-mkdir-function.mkdir-no-such-file-or-directory.html deleted file mode 100644 index fc9f197aa..000000000 --- a/master/warning-mkdir-function.mkdir-no-such-file-or-directory.html +++ /dev/null @@ -1,862 +0,0 @@ - - - - - - - 21.2 Warning: mkdir() [function.mkdir]: No such file or directory | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

21.2 Warning: mkdir() [function.mkdir]: No such file or directory

-

If you are seeing: Warning: mkdir() [function.mkdir]: No such file or directory in /path/to/pecan/web/runpecan.php at line 169 it is because you have used a relative path for $output_folder in system.php.

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/web-model-config.html b/master/web-model-config.html deleted file mode 100644 index 10ee51cd2..000000000 --- a/master/web-model-config.html +++ /dev/null @@ -1,909 +0,0 @@ - - - - - - - 6.2 Model configuration | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

6.2 Model configuration

-

This page is used for basic model configuration, including when your model will run and what input data it will use.

-
-

6.2.1 Choosing meteorology

-

Once a Machine, Model, and Site have been selected, PEcAn will take you to the Input selection page. From this page you will select what Plant Functional Type (PFT) you want to run at a site, the start and end dates of the run, and various Input selections. The most common of these across all models is the need to specify meteorological forcing data. The exact name of the menu item for meteorology will vary by model because all of the Input requirements are generated individually for each model based on the MODEL_TYPE table. In general there are 3 possible cases for meteorology

-
    -
  • PEcAn already has driver files in its database
  • -
  • PEcAn does not have drivers, but can generate them from publicly available data
  • -
  • You need (or want) to upload your own drivers
  • -
-

The first two cases will appear automatically in the the pull down menu. For meteorological files that already exist you will see the date range that’s available. By contrast, met that can be generated will appear as “Use ”, where is the origin of the data (e.g. “Use Ameriflux” will use the micromet from an Ameriflux eddy covariance tower, if one is present at the site).

-

If you want to upload your own met data this can be done in three ways.

-
    -
  1. The default way to add met data is to incorporate it into the overall meteorological processing workflow. This is preferred if you are working with a common meteorological data product that is not yet in PEcAn’s workflow. This case can be divided into two special cases:

    -
      -
    1. Data is in a common MIME-type that PEcAn already has a converter for (e.g. CSV). In this case you’ll want to create a new Format record for the meta-data so that the existing converter can process this data. See documentation for [Creating a new Format record in BETY] for more details.

    2. -
    3. Data is in a more complicated format or interactive database, but large/useful enough to warrent a custom conversion function. Details on creating custom met conversions is in the [Input Conversion], though at this stage you would also be strongly encouraged to contact the PEcAn development team.

    4. -
  2. -
  3. The second-best way is to upload data in PEcAn’s standard meteorological format (netCDF files, CF metadata). See [Input Conversion] for details about variables and units. From this standard, PEcAn can then convert the file to the model-specific format required by the model you have chosen. This approach is preferred for a rare or one-off meterological file format, because PEcAn will also be able to convert the file into the format required by any other model as well.

  4. -
  5. The last option for adding met data is to add it in a model-specific format, which is often easiest if you’ve already been running your model at a site and are just switching to using PEcAn.

  6. -
-
-
-

6.2.2 Met workflow

-

In a nutshell, the PEcAn met workflow is designed to reduce the problem of converting n possible met inputs into m possible model formats, which requires n x m conversion functions as well as numerous custom functions for downscaling, gap filling, etc. Instead, PEcAn works with a single met standard, and thus requires n conversion functions, one for converting each data source into the PEcAn standard, and then m conversion functions for converting from that standard to what an individual model requires. For a new model joining the PEcAn system the burden in particularly low – writing one conversion function provides access to n inputs. Similarly, PEcAn performs all other operations/manipulations (extracting a site, downscaling, gap filling, etc) within the PEcAn standard, which means these operations only need be implemented once.

-

Consider a generic met data product named MET for simplicity. PEcAn will use a function, download.MET, to pull data for the selected year from a public data source (e.g. Ameriflux, North American Regional Reanalysis, etc). Next, PEcAn will use a function, met2CF.MET, to convert the data into the PEcAn standard. If the data is already at the site scale it will then gapfill the data. If the data is a regional or global data product, PEcAn will then permute the data to allow easier site-level extraction, then it will extract data for the requested site and data range. Modules to address the temporal and spatial downscaling of meteorological data products, as well as their uncertainties, are in development but not yet part of the operational workflow. All of these functions are located within the data.atmosphere module.

-

Once data is in the standard format and processed, it will be converted to the model-specific format using a met2model.MODEL function (located in that MODEL’s module).

-

More detailed information on how PEcAn processes inputs can be found on our [Input Conversion] page.

-
-
-

6.2.3 Troubleshooting meteorological conversions

-

At the current moment, most of the issues below address possible errors that the Ameriflux meteorology workflow might report

-
-

6.2.3.1 Could not do gapfill … The following variables have NA’s

-

This error message means that there were gaps in the downloaded data, for whatever variables that were listed, which were larger than the current algorithm could fill. Particularly common is missing radiation or PAR data, as Ameriflux frequently converts nighttime data to NULL, and work is in progress to detect this based on solar geometry. Also common are incomplete years (first or last year of tower operations).

-
-
-

6.2.3.2 Could not get information about . Is this an Ameriflux site?

-

This message occurs when PEcAn believes that a site is part of Ameriflux (because it was listed on the Ameriflux or FLUXNET webpage and has a US-* site code), but no data is present on the Ameriflux server. The most common reasons for this is that you have selected a site that has not submitted data to Ameriflux yet (or that data hasn’t been processed yet), or you have selected a year that’s outside the tower’s operational period. Visit Ameriflux and FLUXNET for lists of available site years.

-
-
-

6.2.3.3 Could not download data for for the year

-

This is similar to the previous error, but in this case PEcAn did find data for the site listed, but just not for the year requested. This can usually be fixed by just altering the years of the run to match those with available data.

-
-
-

6.2.3.4 I could not find the requested var (or dimvar) in the file!

-

PEcAn could not find a required variable within the downloaded file. Most likely this is due to that variable not being measured at this site. The most common cause of failure is the absence of atmospheric pressure data (PRESS), but since most models have a low sensitivity to this variable we are working on methods to estimate this from other sources.

-
-
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/web-site-model.html b/master/web-site-model.html deleted file mode 100644 index 531e7ac1e..000000000 --- a/master/web-site-model.html +++ /dev/null @@ -1,923 +0,0 @@ - - - - - - - 6.1 Site and model selection | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

6.1 Site and model selection

-

This page is used to select the model to run and the site at which you would like to run that model.

-

NOTE: If this page does not load for you, it may be related to a known Google Maps API key issue. See issue #1269 for a possible solution.

-
-

6.1.1 Selecting a model

-
    -
  1. On the Select Host webpage use the Host pull-down menu to select the server you want to run on. PEcAn is designed to allow models to be run both locally and on remote high-performance computing (HPC) resources (i.e. clusters). We recommend that users start with local runs. More information about connecting your PEcAn instance to a cluster can be found on the Remote execution with PEcAn page.

  2. -
  3. Next, select the model you want to run under the Model pull-down menu. The list of models currently supported by PEcAn, along with information about these models, is available on the PEcAn Models page.

    -
      -
    1. If a PEcAn-supported model is not listed, this is most likely because the model has not been installed on the server. The PEcAn team does not have permissions to redistribute all of the models that are coupled to it, so you will have to install some PEcAn-compatible models yourself. Please consult the PEcAn model listing for information about obtaining and installing different models. Once the model is installed and you have added the location of the model executable to Bety (see Adding An Ecosystem Model), your model should appear on the PEcAn Select Host page after your refresh the page.

    2. -
    3. If you would like to add a new model to PEcAn please consult our guide for Adding an Ecosystem Model and contact the PEcAn team for assistance.

    4. -
  4. -
  5. If selecting your model causes your site to disappear from the Google Map, that means the site exists but there are no drivers for that model-site combination registered in the database.

    -
      -
    1. Click the “Conversion” checkbox. If your site reappears, that means PEcAn should be able to automatically generate the required inputs for this site by converting from existing input files in other formats.

    2. -
    3. If the site still does not reappear, that means there are required input files for that model-site combination that PEcAn cannot autogenerate. This may be because the model has unique input requirements or because it has not yet been fully coupled to the PEcAn input processing workflow. Go to the troubleshooting section under Selecting a site for more information on diagnosing what drivers are missing.

    4. -
  6. -
-
-
-

6.1.2 Selecting a site

-
-
-

6.1.3 Site Groups

-
    -
  1. PEcAn provides the option of organizing sites into groups to make them easier to find and easier to run as a group. We have pre-loaded a number of common research networks (e.g., FLUXNET, LTER, NEON), but you are free to create new site groups through Bety.

  2. -
  3. If you are searching for a site that is not part of an existing site group, or you are unsure which site group it belongs to, select “All Sites” to see all sites in Bety. Note that this may take a while to render.

  4. -
-
-
-

6.1.4 Using existing sites

-
    -
  1. Find the site on the map The simplest way of determining if a site exists in PEcAn is through the Google Map interface of the web-based workflow. You’ll want to make sure that the “Site Group” is set to “All Sites” and the “Model” is set to “All Models”.

  2. -
  3. Find the site in BETY If the site is not on the map, it may still be in Bety but with insufficient geographic information. To locate the site in Bety, first login to your local version of the BETY database. If using the VM, navigate to localhost:6480/bety and login with username bety and password illinois. Then, navigate to Data > Sites and use the “Search” box to search for your site. If you do find your site, click “Edit” and add geographic information so that the site will show up on the map. Also, note that the site ID number shows up in the URL for the “Show” or “Edit” pages. This ID is often useful to know, for example when editing a PEcAn settings file by hand. If you did not find you site, follow the instructions below to add a site.

  4. -
-
-
-

6.1.5 Adding a new site

-

(TODO: Move most of this out)

-
    -
  1. Log into Bety as described above.

  2. -
  3. Pick a citation for your site Each site requires an associated “citation” that must be added before the site itself is added. First, navigate to “Data > Citations” and use the “Search” box to see if the relevant citation already exists. If it does, click the check mark under “Actions” to proceed to site creation.

  4. -
-
    -
  • To create a new citation, click the New Citation button, fill in the fields, and then click “Create”. The “field URL” should contain the web address that takes you to this publication on the publisher’s website. The “PDF” field should be the full web address to a PDF for this citation.

  • -
  • Note that our definition of a citation is flexible, and a citation need not be a peer-reviewed publication. Most of the fields in “New Citation” can be left blank, but we recommend at least adding a descriptive title, such as “EBI Farm Field Data” and a relevant contact person as the “Author”.

  • -
-
    -
  1. Once the Citation is created or selected this should automatically take you to the Sites page and list any Sites already associated with this citation. To create a new site click the New Site button.

  2. -
  3. When creating a new site, the most important fields are the Site name and coordinates (latitude and longitude). The coordinates can be entered by hand or by clicking on the site location on the Google Map interface. All other information is optional, but can be useful for searching and indexing purposes.

  4. -
  5. When you are done click Create. At this point, once the PEcAn site-level page is refreshed, the site should automatically appear.

  6. -
-
-
-

6.1.6 Troubleshooting

-
-

6.1.6.1 My site shows up when I don’t have any model selected, but disappears once I select the model I want to run

-

Selecting a model will cause PEcAn to filter the available sites based on whether they possess the required Inputs for a given model (e.g. meteorology). To check what Inputs are missing for a site point your browser to the pecan/checksite.php webpage (e.g. localhost:6480/pecan/checksite.php). This page looks virtually identical to the site selection page, except that it has a Check button instead of Prev and Next. If you select a Machine, Model, and Site and then click Check the page should return a list of what Inputs are missing (listing both the name and the Format ID number). Don’t forget that its possible for PEcAn to have required Inputs in its database, but just not have them for the Machine where you want to run.

-

To see more about what Inputs a given model can accept, and which of those are required, take a look at the MODEL_TYPE table entry in the database (e.g. go to localhost:6480/bety; Select Runs > Model Type; and then click on the model you want to run).

-

For information about loading missing Inputs into the database visit Input records in BETY, and also read the rest of the pages under this section, which will provide important information about the specific classes of Inputs (e.g. meteorology, vegetation, etc).

-

Finally, we are continually developing and refining workflows and standards for processing Input data in a model-agnostic way. The details about what Inputs can be processed automatically are discussed input-by-input in the sections below. For those looking to dive into the code or troubleshoot further, these conversions are ultimately handled under the PEcAn.workflow::do_conversions workflow module.

-
-
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/workflow-input-data.html b/master/workflow-input-data.html deleted file mode 100644 index 43e45788a..000000000 --- a/master/workflow-input-data.html +++ /dev/null @@ -1,863 +0,0 @@ - - - - - - - 13.3 Input Data | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

13.3 Input Data

-

Models require input data as drivers, parameters, and boundary conditions. In order to make a variety of data sources that have unique formats compatible with models, conversion scripts are written to convert them into a PEcAn standard format. That format is a netcdf file with variables names and specified to our standard variable table.

-

Within the PEcAn repository, code pertaining to input conversion is in the MODULES directory under the data.atmosphere and data.land directories.

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/workflow-input-initial.html b/master/workflow-input-initial.html deleted file mode 100644 index 52e62164e..000000000 --- a/master/workflow-input-initial.html +++ /dev/null @@ -1,903 +0,0 @@ - - - - - - - 13.4 Initial Conditions | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

13.4 Initial Conditions

-
-

13.4.1 CONUS (NEON/FIA/BADM) Initial Conditions.

-

To convert initial condition data into the PEcAn Standard and then into the model formats we follow three main steps:

-
    -
  1. Downloading vegetation info --converting the vegetation info into .rd file format
  2. -
  3. Creating ensemble members based on veg file --resamples veg file to create ensmeble members
  4. -
  5. Converting ensemble members to model specific format
  6. -
-

Common Questions regarding IC Data:

-

How do I know if my data product is supported by ic_process workflow? --The current data products supported by ic_process are: NEON, FIA, and BADM. That said you if your vegetation files are registered with BETY and abide by the BETY formats and column names you will be able to use ic_process to create ensemble members and convert the ensemble members to model specific format. See section 6.3.3 for more info. -Can I use ic_process outside of the PEcAn workflow? --Short answer is yes, ic_process can be called as a function all by itself outside of do_conversions. -What about soil initial conditions? --Please reference section 6.3.6 for more info.

-

ic_process workflow:

-

Required inputs for ic_process are: settings object with and sections (see pecan.xml section for more info), dir or location where you would to store the output files, input object that contains all info from settings\(run\)inputs$poolinitcond, and the overwrite setting the default is overwrite = FALSE.

-

get_veg_module() -This function will either download your vegetation info from: NEON_veg, FIA, BADM sources or query BETY for existing veg files previously downloaded. The input and dbfile ids of your veg file are then added to a list getveg.id.

-

ens_veg_module() -This function will create ensemble member ncdf files by resampling the veg file supplied in getveg.id.

-

put_veg_module() -This function will convert the ensemble member ncdf files into model specific format. Currently the supported models are ED2 and SIPNET.

-
-
-

13.4.2 North America (NA) Initial Conditions.

-

To create initial condition files across North America, you will need to strictly follow the script located at ~/pecan/modules/assim.sequential/inst/anchor/IC_prep_anchorSites.Rmd. Within the script we will be following those main steps: -1. Loading settings.xml file and specify paths. -2. Downloading/extracting estimations of four major carbon/water pools (leaf, wood, soil C, soil water) into by-site and by-ensemble tables. -3. Doing unit conversion. For each ensemble of each site, we will be preparing the poolinfo object consisting of converted pool estimations. -4. We will finally be writing the NC files through the PEcAn.SIPNET::veg2model.SIPNET function. -5. Within the loop, we will store the NC file paths into the settings object and rewrite the settings into the XML file to the destination.

-

Within the script we proposed the following new datasets for handling the NA initial condition preparations:

-
    -
  1. The leaf carbon is initialized with MODIS LAI observations and the SLA for the corresponding PFT.
  2. -
  3. The above ground biomass (AGB) is initialized with the 2010 global AGB map (DOI: https://doi.org/10.3334/ORNLDAAC/1763).
  4. -
  5. The soil moisture (SM) is initialized with the SM estimations starting from 1978 (DOI: 10.24381/cds.d7782f18).
  6. -
  7. The soil organic carbon (SOC) is initialized with ISCN SOC estimations (data already prepared on PEcAn, use PEcAn.data.land::iscn_soc to load) based on the level 2 ecoregion map (pre-downloaded using the following link: https://www.epa.gov/eco-research/ecoregions).
  8. -
-
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/workflow-input-phenology.html b/master/workflow-input-phenology.html deleted file mode 100644 index f5fb44cb6..000000000 --- a/master/workflow-input-phenology.html +++ /dev/null @@ -1,864 +0,0 @@ - - - - - - - 13.6 Input phenological Data | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

13.6 Input phenological Data

-

To enable the use of MODIS phenology data (MODIS Land Cover Dynamics (MCD12Q2)) to update the phenological parameters (leaf-on date) and (leaf-off date) at each restart timepoint: -1. Generate the phenological parameter CSV file by running PEcAn.data.remote::extract_phenology_MODIS. -2. Provide the generated phenological parameter CSV file to settings$run$inputs$leaf_phenology$path.

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/workflow-input.html b/master/workflow-input.html deleted file mode 100644 index fc0d9062a..000000000 --- a/master/workflow-input.html +++ /dev/null @@ -1,861 +0,0 @@ - - - - - - - 13.2 Input Conversions | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

13.2 Input Conversions

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/workflow-met.html b/master/workflow-met.html deleted file mode 100644 index 17f6bf71b..000000000 --- a/master/workflow-met.html +++ /dev/null @@ -1,906 +0,0 @@ - - - - - - - 13.5 Meteorological Data | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

13.5 Meteorological Data

-

To convert meterological data into the PEcAn Standard and then into model formats we follow four main steps:

-
    -
  1. Downloading raw data -- Currently supported products -- Example Code
  2. -
  3. Converting raw data into a CF standard -- Example Code
  4. -
  5. Downscaling and gapfilling -- Example Code
  6. -
  7. Coverting to Model Specific format -- Example Code
  8. -
-

Common Questions regarding Met Data:

-

How do I add my Meterological data product to PEcAn? -How do I use PEcAn to convert Met data outside the workflow?

-

The main script that handles Met Processing, is met.process. It acts as a wrapper function that calls individual modules to facilitate the processing of meteorological data from it’s original form to a pecan standard, and then from that standard to model specific formats. It also handles recording these processes in the BETY database.

-
    -
  1. Downloading raw data -- Available Meteorological Drivers -- Example Code to download Ameriflux data
  2. -
  3. Converting raw data into a CF standard (if needed) -- Example Code to convert from raw csv to CF standard
  4. -
  5. Downscaling and gapfilling(if needed) -- Example Code to gapfill
  6. -
  7. Coverting to Model Specific format -- Example Code to convert Standard into Sipnet format
  8. -
-
-

13.5.1 Downloading Raw data (Description of Process)

-

Given the information passed from the pecan.xml met.process will call the download.raw.met.module to facilitate the execution of the necessary functions to download raw data.

-
  <met>
-    <source>AmerifluxLBL</source>
-    <output>SIPNET</output>
-    <username>pecan</username>
-  </met>
-
-
-

13.5.2 Converting raw data to PEcAn standard

-
-
-

13.5.3 Downscaling and gapfilling (optional)

-
-
-

13.5.4 Converting from PEcAn standard to model-specific format

-
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/workflow-metaanalysis.html b/master/workflow-metaanalysis.html deleted file mode 100644 index b55409cba..000000000 --- a/master/workflow-metaanalysis.html +++ /dev/null @@ -1,862 +0,0 @@ - - - - - - - 13.8 Meta Analysis | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

13.8 Meta Analysis

-

(TODO: Under construction)

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/workflow-modelconfig.html b/master/workflow-modelconfig.html deleted file mode 100644 index 7b873d230..000000000 --- a/master/workflow-modelconfig.html +++ /dev/null @@ -1,863 +0,0 @@ - - - - - - - 13.9 Model Configuration | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

13.9 Model Configuration

-

To enable the state data assimilation with sub-annual data, default conflict in model2netcdf should be TRUE.

-

(TODO: Under construction)

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/workflow-modelrun.html b/master/workflow-modelrun.html deleted file mode 100644 index 9fe9c265d..000000000 --- a/master/workflow-modelrun.html +++ /dev/null @@ -1,862 +0,0 @@ - - - - - - - 13.10 Run Execution | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

13.10 Run Execution

-

(TODO: Under construction)

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/workflow-modules.html b/master/workflow-modules.html deleted file mode 100644 index 2da124d42..000000000 --- a/master/workflow-modules.html +++ /dev/null @@ -1,863 +0,0 @@ - - - - - - - 23 Workflow modules | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

23 Workflow modules

-

NOTE: As of PEcAn 1.2.6 – needs to be updated significantly

- -
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/workflow-postrun.html b/master/workflow-postrun.html deleted file mode 100644 index fc114bcc2..000000000 --- a/master/workflow-postrun.html +++ /dev/null @@ -1,866 +0,0 @@ - - - - - - - 13.11 Post Run Analysis | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

13.11 Post Run Analysis

-

(TODO: Under construction) -## Advanced Analysis {#workflow-advanced}

-

(TODO: Under construction)

- -
- -
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/workflow-readsettings.html b/master/workflow-readsettings.html deleted file mode 100644 index c2ffcc03b..000000000 --- a/master/workflow-readsettings.html +++ /dev/null @@ -1,862 +0,0 @@ - - - - - - - 13.1 Read Settings | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

13.1 Read Settings

-

(TODO: Under construction…)

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/workflow-traits.html b/master/workflow-traits.html deleted file mode 100644 index 77e56e499..000000000 --- a/master/workflow-traits.html +++ /dev/null @@ -1,862 +0,0 @@ - - - - - - - 13.7 Traits | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

13.7 Traits

-

(TODO: Under construction)

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/workflow.html b/master/workflow.html deleted file mode 100644 index 6cc4b8ab4..000000000 --- a/master/workflow.html +++ /dev/null @@ -1,871 +0,0 @@ - - - - - - - 13 PEcAn workflow (web/workflow.R) | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

13 PEcAn workflow (web/workflow.R)

-
    -
  • How the workflow works
  • -
  • How each module is called
  • -
  • How to do outside of web interface
  • -
  • Link to “folder structure” section below for detailed descriptions
  • -
-
- -
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/working-with-vm.html b/master/working-with-vm.html deleted file mode 100644 index 699035df9..000000000 --- a/master/working-with-vm.html +++ /dev/null @@ -1,861 +0,0 @@ - - - - - - - 10 VM configuration and maintenance | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

10 VM configuration and maintenance

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/write-configuration-files.html b/master/write-configuration-files.html deleted file mode 100644 index daf2a6406..000000000 --- a/master/write-configuration-files.html +++ /dev/null @@ -1,869 +0,0 @@ - - - - - - - 23.5 Write Configuration Files | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

23.5 Write Configuration Files

-
-

23.5.1 write.configs(model)

-
    -
  • writes out a configuration file for each model run -** writes 500 configuration files for a 500 member ensemble -** for n traits, writes 6 * n + 1 files for running default Sensitivity Analysis (number can be changed in the pecan settings file)
  • -
-
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/xml-advanced.html b/master/xml-advanced.html deleted file mode 100644 index 1631936ed..000000000 --- a/master/xml-advanced.html +++ /dev/null @@ -1,1314 +0,0 @@ - - - - - - - 12.2 Advanced features | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

12.2 Advanced features

-
-

12.2.1 ensemble: Ensemble Runs

-

As with meta.analysis, if this section is missing, then PEcAn will not do an ensemble analysis.

-
  <ensemble>
-    <size>1</size>
-    <variable>NPP</variable>
-    <samplingspace>
-      <parameters>
-        <method>uniform</method>
-      </parameters>
-      <met>
-        <method>sampling</method>
-      </met>
-    </samplingspace>
-  </ensemble>
-

An alternative configuration is as follows:

-
<ensemble>
-  <size>5</size>
-  <variable>GPP</variable>
-  <start.year>1995</start.year>
-  <end.year>1999</end.year>
-  <samplingspace>
-  <parameters>
-    <method>lhc</method>
-  </parameters>
-  <met>
-    <method>sampling</method>
-  </met>
-  </samplingspace>
-</ensemble>
-

Tags in this block can be broken down into two categories: Those used for setup (which determine how the ensemble analysis runs) and those used for post-hoc analysis and visualization (i.e. which do not affect how the ensemble is generated).

-

Tags related to ensemble setup are:

-
    -
  • size : (required) the number of runs in the ensemble.
  • -
  • samplingspace: (optional) Contains tags for defining how the ensembles will be generated.
  • -
-

Each piece in the sampling space can potentially have a method tag and a parent tag. Method refers to the sampling method and parent refers to the cases where we need to link the samples of two components. When no tag is defined for one component, one sample will be generated and used for all the ensembles. This allows for partitioning/studying different sources of uncertainties. For example, if no met tag is defined then, one met path will be used for all the ensembles and as a result the output uncertainty will come from the variability in the parameters. At the moment no sampling method is implemented for soil and vegetation. -Available sampling methods for parameters can be found in the documentation of the PEcAn.utils::get.ensemble.samples function. -For the cases where we need simulations with a predefined set of parameters, met and initial condition we can use the restart argument. Restart needs to be a list with name tags of runid, inputs, new.params (parameters), new.state (initial condition), ensemble.id (ensemble ids), start.time, and stop.time.

-

The restart functionality is developed using model specific functions by called write_restart.modelname. You need to make sure first that this function is already exist for your desired model.

-

Note: if the ensemble size is set to 1, PEcAn will select the posterior median parameter values rather than taking a single random draw from the posterior

-

Tags related to post-hoc analysis and visualization are:

-
    -
  • variable: (optional) name of one (or more) variables the analysis should be run for. If not specified, sensitivity.analysis variable is used, otherwise default is GPP (Gross Primary Productivity).
  • -
-

(NOTE: This static visualization functionality will soon be deprecated as PEcAn moves towards interactive visualization tools based on Shiny and htmlwidgets).

-

This information is currently used by the following PEcAn workflow functions:

-
    -
  • PEcAn.<MODEL>::write.config.<MODEL> - See above.
  • -
  • PEcAn.uncertainty::write.ensemble.configs - Write configuration files for ensemble analysis
  • -
  • PEcAn.uncertainty::run.ensemble.analysis - Run ensemble analysis
  • -
-
-
-

12.2.2 sensitivity.analysis: Sensitivity analysis

-

Only if this section is defined a sensitivity analysis is done. This section will have <quantile> or <sigma> nodes. If neither are given, the default is to use the median +/- [1 2 3] x sigma (e.g. the 0.00135 0.0228 0.159 0.5 0.841 0.977 0.999 quantiles); If the 0.5 (median) quantile is omitted, it will be added in the code.

-
<sensitivity.analysis>
-    <quantiles>
-        <sigma>-3</sigma>
-        <sigma>-2</sigma>
-        <sigma>-1</sigma>
-        <sigma>1</sigma>
-        <sigma>2</sigma>
-        <sigma>3</sigma>
-    </quantiles>
-  <variable>GPP</variable>
-  <perpft>TRUE</perpft>
-    <start.year>2004</start.year>
-    <end.year>2006</end.year>
-</sensitivity.analysis>
-
    -
  • quantiles/sigma : [optional] The number of standard deviations relative to the standard normal (i.e. “Z-score”) for which to perform the ensemble analysis. For instance, <sigma>1</sigma> corresponds to the quantile associated with 1 standard deviation greater than the mean (i.e. 0.681). Use a separate <sigma> tag, all under the <quantiles> tag, to specify multiple quantiles. Note that we do not automatically add the quantile associated with -sigma – i.e. if you want +/- 1 standard deviation, then you must include both <sigma>1</sigma> and <sigma>-1</sigma>.
  • -
  • start.date : [required?] start date of the sensitivity analysis (in YYYY/MM/DD format)
  • -
  • end.date : [required?] end date of the sensitivity analysis (in YYYY/MM/DD format) -
      -
    • NOTE: start.date and end.date are distinct from values set in the run tag because this analysis can be done over a subset of the run.
    • -
  • -
  • variable : [optional] name of one (or more) variables the analysis should be run for. If not specified, sensitivity.analysis variable is used, otherwise default is GPP.
  • -
  • perpft : [optional] if TRUE a sensitivity analysis on PFT-specific outputs will be run. This is only possible if your model provides PFT-specific outputs for the variable requested. This tag only affects the output processing, not the number of samples proposed for the analysis nor the model execution.
  • -
-

This information is currently used by the following PEcAn workflow functions:

-
    -
  • PEcAn.<MODEL>::write.configs.<MODEL> – See above
  • -
  • PEcAn.uncertainty::run.sensitivity.analysis – Executes the uncertainty analysis
  • -
-
-
-

12.2.3 Parameter Data Assimilation

-

The following tags can be used for parameter data assimilation. More detailed information can be found here: Parameter Data Assimilation Documentation

-
-
-

12.2.4 Multi-Settings

-

Multi-settings allows you to do multiple runs across different sites. This customization can also leverage site group distinctions to expedite the customization. It takes your settings and applies the same settings, changing only the site level tags across sites.

-

To start, add the multisettings tag within the <run></run> section of your xml

-
<multisettings>
-  <multisettings>run</multisettings>
-<multisettings> 
-

Additional tags for this section exist and can fully be seen here:

-
 <multisettings>
-  <multisettings>assim.batch</multisettings>
-  <multisettings>ensemble</multisettings>
-  <multisettings>sensitivity.analysis</multisettings>
-  <multisettings>run</multisettings>
- </multisettings>
-

These tags correspond to different pecan analysis that need to know that there will be multiple settings read in.

-

Next you’ll want to add the following tags to denote the group of sites you want to use. It leverages site groups, which are defined in BETY.

-
 <sitegroup>
-   <id>1000000022</id>
- </sitegroup>
-

If you add this tag, you must remove the <site> </site> tags from the <run> tag portion of your xml. -The id of your sitegroup can be found by lookig up your site group within BETY.

-

You do not have to use the sitegroup tag. You can manually add multiple sites using the structure in the example below.

-

Lastly change the top level tag to <pecan.multi>, meaning the top and bootom of your xml should look like this:

-
<?xml version="1.0"?>
-<pecan.multi>
-...
-</pecan.multi>
-

Once you have defined these tags, you can run PEcAn, but there may be further specifications needed if you know that different data sources have different dates available.

-

Run workflow.R up until

-
# Write pecan.CHECKED.xml
-PEcAn.settings::write.settings(settings, outputfile = "pecan.CHECKED.xml")
-

Once this section is run, you’ll need to open pecan.CHECKED.xml. You will notice that it has expanded from your original pecan.xml.

-
 <run>
-  <settings.1>
-   <site>
-    <id>796</id>
-    <met.start>2005/01/01</met.start>
-    <met.end>2011/12/31</met.end>
-    <name>Bartlett Experimental Forest (US-Bar)</name>
-    <lat>44.06464</lat>
-    <lon>-71.288077</lon>
-   </site>
-   <start.date>2005/01/01</start.date>
-   <end.date>2011/12/31</end.date>
-   <inputs>
-    <met>
-     <path>/fs/data1/pecan.data/dbfiles/AmerifluxLBL_SIPNET_site_0-796/AMF_US-Bar_BASE_HH_4-1.2005-01-01.2011-12-31.clim</path>
-    </met>
-   </inputs>
-  </settings.1>
-  <settings.2>
-   <site>
-    <id>767</id>
-    <met.start>2001/01/01</met.start>
-    <met.end>2014/12/31</met.end>
-    <name>Morgan Monroe State Forest (US-MMS)</name>
-    <lat>39.3231</lat>
-    <lon>-86.4131</lon>
-   </site>
-   <start.date>2001/01/01</start.date>
-   <end.date>2014/12/31</end.date>
-   <inputs>
-    <met>
-     <path>/fs/data1/pecan.data/dbfiles/AmerifluxLBL_SIPNET_site_0-767/AMF_US-MMS_BASE_HR_8-1.2001-01-01.2014-12-31.clim</path>
-    </met>
-   </inputs>
-  </settings.2>
-....
-</run>
-
    -
  • The ... replaces the rest of the site settings for however many sites are within the site group.
  • -
-

Looking at the example above, take a close look at the <met.start></met.start> and <met.end></met.end>. You will notice that for both sites, the dates are different. In this example they were edited by hand to include the dates that are available for that site and source. You must know your source prior. Only the source CRUNCEP has a check that will tell you if your dates are outside the range available. PEcAn will automatically populate these dates across sites according the original setting of start and end dates.

-

In addition, you will notice that the <path></path> section contains the model specific meteorological data file. You can add that in by hand or you can you can leave the normal tags that met process workflow will use to process the data into your model specific format:

-
<met>
-  <source>AmerifluxLBL</source>
-  <output>SIPNET</output>
-  <username>pecan</username>
-</met>
-
-
-

12.2.5 (experimental) State Data Assimilation

-

The following tags can be used for state data assimilation. More detailed information can be found here: State Data Assimilation Documentation

-
<state.data.assimilation>
-    <process.variance>TRUE</process.variance>
-    <aqq.Init>1</aqq.Init>
-    <bqq.Init>1</bqq.Init>
-  <sample.parameters>FALSE</sample.parameters>
-  <adjustment>TRUE</adjustment>
-  <censored.data>FALSE</censored.data>
-  <FullYearNC>TRUE</FullYearNC>
-  <NC.Overwrite>FALSE</NC.Overwrite>
-  <NC.Prefix>sipnet.out</NC.Prefix>
-  <q.type>SINGLE</q.type>
-  <free.run>FALSE</free.run>
-  <Localization.FUN>Local.support</Localization.FUN>
-  <scalef>1</scalef>
-  <chains>5</chains>
-  <state.variables>
-   <variable>
-    <variable.name>AbvGrndWood</variable.name>
-    <unit>MgC/ha</unit>
-    <min_value>0</min_value>
-    <max_value>9999</max_value>
-   </variable>
-   <variable>
-    <variable.name>LAI</variable.name>
-    <unit></unit>
-    <min_value>0</min_value>
-    <max_value>9999</max_value>
-   </variable>
-   <variable>
-  <variable.name>SoilMoistFrac</variable.name>
-  <unit></unit>
-  <min_value>0</min_value>
-  <max_value>100</max_value>
-  </variable>
-   <variable>
-    <variable.name>TotSoilCarb</variable.name>
-    <unit>kg/m^2</unit>
-    <min_value>0</min_value>
-    <max_value>9999</max_value>
-   </variable>
-  </state.variables>
-  <Obs_Prep>
-   <Landtrendr_AGB>
-    <AGB_input_dir>/projectnb/dietzelab/dongchen/Multi-site/download_500_sites/AGB</AGB_input_dir>
-    <allow_download>TRUE</allow_download>
-    <export_csv>TRUE</export_csv>
-    <timestep>
-     <unit>year</unit>
-     <num>1</num>
-    </timestep>
-   </Landtrendr_AGB>
-   <MODIS_LAI>
-    <search_window>30</search_window>
-    <export_csv>TRUE</export_csv>
-    <run_parallel>TRUE</run_parallel>
-    <timestep>
-     <unit>year</unit>
-     <num>1</num>
-    </timestep>
-   </MODIS_LAI>
-   <SMAP_SMP>
-    <search_window>30</search_window>
-    <export_csv>TRUE</export_csv>
-    <update_csv>FALSE</update_csv>
-    <timestep>
-     <unit>year</unit>
-     <num>1</num>
-    </timestep>
-   </SMAP_SMP>
-   <Soilgrids_SoilC>
-    <timestep>
-     <unit>year</unit>
-     <num>1</num>
-    </timestep>
-   </Soilgrids_SoilC>
-   <outdir>/projectnb/dietzelab/dongchen/All_NEON_SDA/test_OBS</outdir>
-   <start.date>2012-07-15</start.date>
-   <end.date>2021-07-15</end.date>
-  </Obs_Prep>
-  <spin.up>
-    <start.date>2004/01/01</start.date>
-      <end.date>2006/12/31</end.date>
-  </spin.up>
-  <forecast.time.step>1</forecast.time.step>
-    <start.date>2004/01/01</start.date>
-    <end.date>2006/12/31</end.date>
-</state.data.assimilation>
-
    -
  • process.variance : [optional] TRUE/FLASE flag for if process variance should be estimated (TRUE) or not (FALSE). If TRUE, a generalized ensemble filter will be used. If FALSE, an ensemble Kalman filter will be used. Default is FALSE.
  • -
  • aqq.Init : [optional] The initial value of aqq used for estimate the Q distribution, the default value is 1 (note that, the aqq.init and bqq.init right now only work on the VECTOR q type, and we didn’t account for the variabilities of them across sites or variables, meaning we initialize the aqq and bqq given single value).
  • -
  • bqq.Init : [optional] The initial value of bqq used for estimate the Q distribution, the default value is 1.
  • -
  • sample.parameters : [optional] TRUE/FLASE flag for if parameters should be sampled for each ensemble member or not. This allows for more spread in the intial conditions of the forecast.
  • -
  • adjustment : [optional] Bool variable decide if you want to adjust analysis results by the likelihood.
  • -
  • censored.data : [optional] Bool variable decide if you want to do MCMC sampling for the forecast ensemble space, the default is FALSE.
  • -
  • FullYearNC : [optional] Bool variable decide if you want to generate the full-year netcdf file when there is a overlap in time, the default is TRUE.
  • -
  • NC.Overwrite : [optional] Bool variable decide if you want to overwrite the previous netcdf file when there is a overlap in time, the default is FALSE.
  • -
  • NC.Prefix : [optional] The prefix for the generation of the full-year netcdf file, the default is sipnet.out.
  • -
  • q.type : [optional] The type of process variance that will be estimated, the default is SINGLE.
  • -
  • free.run : [optional] If it’s a free run without any observations, the default is FALSE.
  • -
  • Localization.FUN : [optional] The localization function name for the localization operation, the default is Local.support.
  • -
  • scalef : [optional] The scale parameter used for the localization operation, the smaller the value is, the sites are more isolated.
  • -
  • chains : [optional] The number of chains needed to be estimated during the MCMC sampling process.
  • -
  • NOTE: If TRUE, you must also assign a vector of trait names to pick.trait.params within the sda.enkf function.
  • -
  • state.variable : [required] State variable that is to be assimilated (in PEcAn standard format, with pre-specified variable name, unit, and range). Four variables can be assimilated so far: including Aboveground biomass (AbvGrndWood), LAI, SoilMoistFrac, and Soil carbon (TotSoilCarb).
  • -
  • Obs_Prep : [required] This section will be handled through the SDA_Obs_Assembler function, if you want to proceed with this function, this section is required.
  • -
  • spin.up : [required] start.date and end.date for model spin up.
  • -
  • NOTE: start.date and end.date are distinct from values set in the run tag because spin up can be done over a subset of the run.
  • -
  • forecast.time.step : [optional] start.date and end.date for model spin up.
  • -
  • start.date : [required?] start date of the state data assimilation (in YYYY/MM/DD format)
  • -
  • end.date : [required?] end date of the state data assimilation (in YYYY/MM/DD format)
  • -
  • NOTE: start.date and end.date are distinct from values set in the run tag because this analysis can be done over a subset of the run.
  • -
-
-
-

12.2.6 State Variables for State Data Assimilation

-

The following tags can be used for documentation of state variables required for the SDA workflow.

-
<state.data.assimilation>
-  <state.variables>
-   <variable>
-    <variable.name>AbvGrndWood</variable.name>
-    <unit>MgC/ha</unit>
-    <min_value>0</min_value>
-    <max_value>9999</max_value>
-   </variable>
-   <variable>
-    <variable.name>LAI</variable.name>
-    <unit></unit>
-    <min_value>0</min_value>
-    <max_value>9999</max_value>
-   </variable>
-   <variable>
-  <variable.name>SoilMoistFrac</variable.name>
-  <unit></unit>
-  <min_value>0</min_value>
-  <max_value>100</max_value>
-  </variable>
-   <variable>
-    <variable.name>TotSoilCarb</variable.name>
-    <unit>kg/m^2</unit>
-    <min_value>0</min_value>
-    <max_value>9999</max_value>
-   </variable>
-  </state.variables>
-</state.data.assimilation>
-
    -
  • variable : [required] Each of this section should include each state variables separately.
  • -
  • variable.name : [required] The name of the state variable (same as what we call it in the model output file. for example, “SIPNET.out” file).
  • -
  • unit : [required] The unit of the state variable (can be empty if it’s unitless).
  • -
  • min_value : [required] The minimum range of the state variable.
  • -
  • max_value : [required] The maximum range of the state variable.
  • -
-
-
-

12.2.7 Observation Preparation for State Data Assimilation

-

The following tags can be used for observation preparation for the SDA workflow.

-
<state.data.assimilation>
-  <Obs_Prep>
-   <Landtrendr_AGB>
-    <AGB_indir>/projectnb/dietzelab/dongchen/Multi-site/download_500_sites/AGB</AGB_indir>
-    <allow_download>TRUE</allow_download>
-    <export_csv>TRUE</export_csv>
-    <timestep>
-     <unit>year</unit>
-     <num>1</num>
-    </timestep>
-   </Landtrendr_AGB>
-   
-   <MODIS_LAI>
-    <search_window>30</search_window>
-    <export_csv>TRUE</export_csv>
-    <run_parallel>TRUE</run_parallel>
-    <timestep>
-     <unit>year</unit>
-     <num>1</num>
-    </timestep>
-   </MODIS_LAI>
-   
-   <SMAP_SMP>
-    <search_window>30</search_window>
-    <export_csv>TRUE</export_csv>
-    <update_csv>FALSE</update_csv>
-    <timestep>
-     <unit>year</unit>
-     <num>1</num>
-    </timestep>
-   </SMAP_SMP>
-   
-   <Soilgrids_SoilC>
-    <timestep>
-     <unit>year</unit>
-     <num>1</num>
-    </timestep>
-   </Soilgrids_SoilC>
-   <outdir>/projectnb/dietzelab/dongchen/All_NEON_SDA/test_OBS</outdir>
-   <start.date>2012-07-15</start.date>
-   <end.date>2021-07-15</end.date>
-  </Obs_Prep>
-</state.data.assimilation>
-

The Obs_Prep section is specifically designed for the SDA_OBS_Assembler function within the state.data.assimilation section, which helps construct the obs.mean and obs.cov objects more efficiently. Within the Obs_Prep section, the user needs to specify data streams that will be proceeded in the assembler function as DataSource_AbbreviationOfData (for example: Landtrendr_AGB for Landtrendr aboveground biomass observations, or Soilgrids_SoilC for soilgrids soil organic carbon concentration). There are four functions that can be used for preparing observations: MODIS_LAI_prep, Soilgrids_SoilC_prep, SMAP_SMP_prep, and Landtrendr_AGB_prep functions. -Other than that, the output directory, and start and end date need to be set within the Obs_Prep section, note that if you choose to export csv file for any data, you will get the corresponding csv file just under the outdir, for the Rdata of obs.mean and obs.cov objects, they will be stored whthin the Rdata folder within the outdir, if the Rdata folder is not created, then the assembler will help to create this folder automatically. -* outdir : [required] This tag is for every observation preparation function, which points to the directory where the csv file associated with each data stream should be generated, read, or updated. -* start.date : [required] This tag defines the exact start point of time, which differs from the start.date in the state.data.assimilation section in a way that it is the time when first observation should be taken. -* end.date : [required] This tag defines the exact end point of time, which differs from the end.date in the state.data.assimilation section in a way that it is the time when last observation should be taken.

-

Within each data-specific section (for example, within Landtrendr_AGB section), there are few general settings need to be set like the export_csv and timestep arguments. -* export_csv : [optional] This tag is for every observation preparation function, which decide if we want to export the csv file to the outdir. Normally the outdir should be given in order to set export_csv as TRUE. The default value is TRUE. -* timestep : [optional] This tag defines the time unit and how many unit time per each time step. It supports year, month, week, and day as time unit. If you assign a general timestep just under the Obs_Prep section, all variable will be handled with the same timestep. If you assign each variable with each timestep, then the assembler function will create obs.mean and obs.cov with mixed temporal resolution. The default value is list(unit=“year”, num=1).

-

There are also several settings that are data-specific, for example, the AGB_indir only applies to Landtrendr AGB data that points to the directory where the AGB files are stored. Beyond that, the allow_download is also AGB specific, which decide if you want to download the AGB files if some are missing. -* AGB_indir : [required] This tag is only for Landtrendr_AGB_prep function, which points to the directory where the pre-downloaded AGB files existed. -* allow_download : [optional] This tag is only for Landtrendr_AGB_prep function, which decide if we want to proceed to download the AGB files (that will take a while, and a lot of space) if some of them are detected to be empty. The default value is FALSE.

-

For the MODIS LAI and SMAP soil moisture observations, the search_window specifies how many days you want to search for the data with desired dates. Beyond that, the update_csv is specifically used for the SMAP data, which decide if you want to reproduce formatted csv file based on the downloaded SMAP_gee.csv file. For the run_parallel in MODIS LAI settings, it specify if you want to proceed the function parallely. -* search_window : [optional] This tag is used for LAI and SMAP observation preparation functions, which defines the search window within which the closest observation to the target date is selected. The default value is 30 days. -* update_csv : [optional] This tag is used for SMAP preparation function only, which decide if we want to update the CSV file. Normally, we will only set it to be TRUE if we redownload the SMAP_GEE csv file from Google Earth Engine, the tutorial can be found in the SMAP_SMP_prep function itself. The default value is FALSE. -* run_parallel : [optional] This tag defines if you want to proceed the MODIS LAI function parallely, the default value is FALSE.

-
-
-

12.2.8 (experimental) Brown Dog

-

This section describes how to connect to Brown Dog. This facilitates processing and conversions of data.

-
  <browndog>
-    <url>...</url>
-    <username>...</username>
-    <password>...</password>
-  </browndog>
-
    -
  • url: (required) endpoint for Brown Dog to be used.
  • -
  • username: (optional) username to be used with the endpoint for Brown Dog.
  • -
  • password: (optional) password to be used with the endpoint for Brown Dog.
  • -
-

This information is currently used by the following R functions:

-
    -
  • PEcAn.data.atmosphere::met.process – Generic function for processing meteorological input data.
  • -
  • PEcAn.benchmark::load_data – Generic, versatile function for loading data in various formats.
  • -
-
-
-

12.2.9 (experimental) Benchmarking

-

Coming soon…

-
-
-

12.2.10 Remote data module

-

This section describes the tags required for configuring remote_process.

-
  <remotedata>
-  <out_get_data>...</out_get_data>
-  <source>...</source>
-  <collection>...</collection>
-  <scale>...</scale>
-  <projection>...</projection>
-  <qc>...</qc>
-  <algorithm>...</algorithm>
-  <credfile>...</credfile>
-  <out_process_data>...</out_process_data>
-  <overwrite>...</overwrite>
-  </remotedata>
-
    -
  • out_get_data: (required) type of raw output requested, e.g, bands, smap
  • -
  • source: (required) source of remote data, e.g., gee or AppEEARS
  • -
  • collection: (required) dataset or product name as it is provided on the source, e.g. “COPERNICUS/S2_SR” for gee or “SPL3SMP_E.003” for AppEEARS
  • -
  • scale: (optional) pixel resolution required for some gee collections, recommended to use 10 for Sentinel 2
  • -
  • projection: (optional) type of projection. Only required for AppEEARS polygon AOI type
  • -
  • qc: (optional) quality control parameter, required for some gee collections
  • -
  • overwrite: (optional) if TRUE database checks will be skipped and existing data of same type will be replaced entirely. When processed data is requested, the raw data required for creating it will also be replaced. By default FALSE
  • -
-

These tags are only required if processed data is requested:

-
    -
  • out_process_data: (optional) type of processed output requested, e.g, LAI
  • -
  • algorithm: (optional) algorithm used for processing data, currently only SNAP is implemented to estimate LAI from Sentinel-2 bands
  • -
  • credfile: (optional) absolute path to JSON file containing Earthdata username and password, only required for AppEEARS
  • -
  • pro_mimetype: (optional) MIME type of the processed file
  • -
  • pro_formatname: (optional) format name of the processed file
  • -
-

Additional information for the module are taken from the registration files located at data.remote/inst/registration

-

The output data from the module are returned in the following tags:

-
    -
  • raw_id: input id of the raw file
  • -
  • raw_path: absolute path to the raw file
  • -
  • pro_id: input id of the processed file
  • -
  • pro_path: absolute path to the processed file
  • -
- -
-
- -
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/xml-configuration.html b/master/xml-configuration.html deleted file mode 100644 index 6d2f44dbb..000000000 --- a/master/xml-configuration.html +++ /dev/null @@ -1,903 +0,0 @@ - - - - - - - 26.7 XML configuration | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

26.7 XML configuration

-

The relevant section of the PEcAn XML file is the <host> block. -Here is a minimal example from one of my recent runs:

-
<host>
-    <name>geo.bu.edu</name>
-    <user>ashiklom</user>
-    <tunnel>/home/carya/output//PEcAn_99000000008/tunnel/tunnel</tunnel>
-</host>
-

Breaking this down:

-
    -
  • name – The hostname of the machine where the runs will be performed. -Set it to localhost to run on the local machine.
  • -
  • user – Your username on the remote machine (note that this may be different from the username on your local machine).
  • -
  • tunnel – This is the tunnel file for the connection used by all remote execution files. -The tunnel is created automatically by the web interface, but must be created by the user for command line execution.
  • -
-

This configuration will run in serialized mode. -To use qsub, the configuration is slightly more involved:

-
<host>
-  <name>geo.bu.edu</name>
-  <user>ashiklom</user>
-  <qsub>qsub -V -N @NAME@ -o @STDOUT@ -e @STDERR@ -S /bin/bash</qsub>
-  <qsub.jobid>Your job ([0-9]+) .*</qsub.jobid>
-  <qstat>qstat -j @JOBID@ || echo DONE</qstat>
-  <tunnel>/home/carya/output//PEcAn_99000000008/tunnel/tunnel</tunnel>
-</host>
-

The additional fields are as follows:

-
    -
  • qsub – The command used to submit jobs to the queue system. -Despite the name, this can be any command used for any queue system. -The following variables are available to be set here: -
      -
    • @NAME@ – Job name to display
    • -
    • @STDOUT@ – File to which stdout will be redirected
    • -
    • @STDERR@ – File to which stderr will be redirected
    • -
  • -
  • qsub.jobid – A regular expression, from which the job ID will be determined. -This string will be parsed by R as jobid <- gsub(qsub.jobid, "\\1", output) – note that the first pattern match is taken as the job ID.
  • -
  • qstat – The command used to check the status of a job. -Internally, PEcAn will look for the DONE string at the end, so a structure like <some command indicating if any jobs are still running> || echo DONE is required. -The @JOBID@ here is the job ID determined from the qsub.jobid parsing.
  • -
-

Documentation for using the model launcher is currently unavailable.

-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/master/xml-core-config.html b/master/xml-core-config.html deleted file mode 100644 index 245f2d887..000000000 --- a/master/xml-core-config.html +++ /dev/null @@ -1,1223 +0,0 @@ - - - - - - - 12.1 Core configuration | The Predictive Ecosystem Analyzer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- -
-
- - -
-
- -
-
-

12.1 Core configuration

-
-

12.1.1 Top-level structure

-

The first line of the XML file should contain version and encoding information.

-
<?xml version="1.0" encoding="UTF-8"?>
-

The rest of the XML file should be surrounded by <pecan>...</pecan> tags.

-
<pecan>
-  ...XML body here...
-</pecan>
-
-
-

12.1.2 info: Run metadata

-

This section contains run metadata. -This information is not essential to a successful model run, but is useful for tracking run provenance.

-
  <info>
-    <notes>Example run</notes>
-    <userid>-1</userid>
-    <username>guestuser</username>
-    <date>2018/09/18 19:12:28 +0000</date>
-  </info>
-

The <notes> tag will be filled in by the web GUI if you provide notes, or you can add notes yourself within these tags. We suggest adding notes that help identify your run and a brief description of what the run is for. Because these notes are searchable within the PEcAn database and web interface, they can be a useful way to distinguish between similar runs.

-

The <userid> and <username> section is filled in from the GUI if you are signed in. If you are not using the GUI, add the user name and ID you are associated with that exists within the PEcAn database.

-

The <date></date> tag is filled automatically at the time of your run from the GUI. If you are not using the GUI, add the date you execute the run. This tag is not the tag for the dates you would like to run your model simulation.

-
-
-

12.1.3 outdir: Output directory

-

The <outdir> tag is used to configure the output folder used by PEcAn. -This is the directory where all model input and output files will be stored. -By default, the web interface names this folder PEcAn_<workflow ID>, and higher-level location is set by the $output_folder$ variable in the web/config.php file. -If no outdir is specified, PEcAn defaults to the working directory from which it is called, which may be counterintuitive.

-
  <outdir>/data/workflows/PEcAn_99000000006</outdir>
-
-
-

12.1.4 database: PEcAn database settings

-
-

12.1.4.1 bety: PEcAn database (Bety) configuration

-

The bety tag defines the driver to use to connect to the database (we support PostgreSQL, which is the default, and Postgres) and parameters required to connect to the database. Note that connection parameters are passed exactly as entered to the underlying R database driver, and any invalid or extra parameters will result in an error.

-

In other words, this configuration…

-
  <database>
-    ...
-    <bety>
-      <user>bety</user>
-      <password>bety</password>
-      <host>postgres</host>
-      <dbname>bety</dbname>
-      <driver>PostgreSQL</driver>
-      <port>5432</port>
-      <write>true</write>
-    </bety>
-    ...
-  </database>
-

…will be translated (by way of PEcAn.DB::db.open(settings$database$bety)) into R code like the following:

-
con <- DBI::dbConnect(
-  drv = RPostgreSQL::PostgreSQL(),
-  user = "bety",
-  password = "bety",
-  dbname = "bety",
-  host = "postgres",
-  port = "5432",
-  write = TRUE
-)
-

Common parameters are described as follows:

-
    -
  • driver: The driver to use to connect to the database. This should always be set to PostgreSQL, unless you absolutely know what you’re doing.
  • -
  • dbname: The name of the database (formerly name), corresponding to the -d argument to psql. In most cases, this should be set to bety, and will only be different if you named your Bety instance something else (e.g. if you have multiple instances running at once). If unset, it will default to the user name of the current user, which is usually wrong!
  • -
  • user: The username to connect to the database (formerly userid), corresponding to the -U argument to psql. default value is the username of the current user logged in (PostgreSQL uses user for this field).
  • -
  • password: The password to connect to the database (was passwd), corresponding to the -p argument to psql. If unspecified, no password is used. On standard PEcAn installations, the username and password are both bety (all lowercase).
  • -
  • host: The hostname of the bety database, corresponding to the -h argument to psql. On the VM, this will be localhost (the default). If using docker, this will be the name of the PostgreSQL container, which is postgres if using our standard docker-compose. If connecting to the PEcAn database on a remote server (e.g. psql-pecan.bu.edu), this should be the same as the hostname used for ssh access.
  • -
  • write: Logical. If true (the default), write results to the database. If false, PEcAn will run but will not store any information to bety.
  • -
-

When using the web interface, this section is configured by the web/config.php file. -The default config.php settings on any given platform (VM, Docker, etc.) or in example files (e.g. config.php.example) are a good place to get default values for these fields if writing pecan.xml by hand.

-

Key R functions using these parameters are as follows:

-
    -
  • PEcAn.DB::db.open – Open a database connection and create a connection object, which is used by many other functions for communicating with the PEcAn database.
  • -
-
-
-

12.1.4.2 dbfiles: Location of database files

-

The dbfiles is a path to the local location of files needed to run models using PEcAn, including model executables and inputs.

-
  <database>
-    ...
-    <dbfiles>/data/dbfiles</dbfiles>
-    ...
-  </database>
-
-
-

12.1.4.3 (Experimental) fia: FIA database connection parameters

-

If a version of the FIA database is available, it can be configured using <fia> node, whose syntax is identical to that of the <bety> node.

-
  <database>
-    ...
-    <fia>
-        <dbname>fia5data</dbname>
-        <username>bety</username>
-        <password>bety</password>
-        <host>localhost</host>
-    </fia>
-    ...
-  </database>
-

Currently, this is only used for extraction of specific site vegetation information (notably, for ED2 css, pss, and site files). -Stability not ensured as of 1.5.3.

-
-
-
-

12.1.5 pft: Plant functional type selection

-

The PEcAn system requires at least 1 plant functional type (PFT) to be specified inside the <pfts> section.

-
  <pfts>
-    <pft>
-      <name>tundra.grasses</name> 
-      <constants>
-        <num>1</num>
-      </constants>
-      <posterior.files>Path to a post.distns.*.Rdata or prior.distns.Rdata</posterior.files>
-    </pft>
-  </pfts>
-
    -
  • name : (required) the name of the PFT, which must exactly match the name in the PEcAn database.
  • -
  • outdir: (optional) Directory path in which PFT-specific output will be stored during meta-analysis and sensitivity analysis. If not specified (recommended), it will be written into <outdir>/<pftname>.
  • -
  • contants: (optional) this section contains information that will be written directly into the model specific configuration files. For example, some models like ED2 use PFT numbers instead of names for PFTs, and those numbers can be specified here. See documentation for model-specific code for details.
  • -
  • posterior.files (Optional) this tag helps to signal write.config functions to use specific posterior/prior files (such as HPDA or MA analysis) for generating samples without needing to access to the bety database.
  • -
-

``

-

This information is currently used by the following PEcAn workflow function:

-
    -
  • get.traits - ??????
  • -
-
-
-

12.1.6 meta.analysis: Trait Meta Analysis

-

The section meta.analysis needs to exists for a meta.analysis to be executed, even though all tags inside are optional. -Conversely, if you do not want to do a trait meta-analysis (e.g. if you want to manually set all parameters), you should omit this node.

-
  <meta.analysis>
-    <iter>3000</iter>
-    <random.effects>
-      <on>FALSE</on>
-      <use_ghs>TRUE</use_ghs>
-    </random.effects>
-  </meta.analysis>
-

Some of the tags that can go in this section are:

-
    -
  • iter: MCMC (Markov Chain Monte Carlo) chain length, i.e. the total number of posterior samples in the meta-analysis, default is 3000. Smaller numbers will run faster but produce larger errors.
  • -
  • random.effects: Settings related to whether to include random effects (site, treatment) in meta-analysis model.
  • -
  • on: Default is set to FALSE to work around convergence problems caused by an over parameterized model (e.g. too many sites, not enough data). Can be turned to TRUE for including hierarchical random effects.
  • -
  • use_ghs: Default is set to TRUE to include greenhouse measurements. Can be set to FALSE to exclude cases where all data is from greenhouse.
  • -
  • update: Should previous results of meta.analysis and get.traits be re-used. If set to TRUE the meta-analysis and get.trait.data will always be executed. Setting this to FALSE will try and reuse existing results. Future versions will allow for AUTO as well which will try and reuse if the PFT/traits have not changed. The default value is FALSE.
  • -
  • threshold: threshold for Gelman-Rubin convergence diagnostic (MGPRF); default is 1.2.
  • -
-

This information is currently used by the following PEcAn workflow function:

-
    -
  • PEcAn.MA::run.meta.analysis - ???
  • -
-
-
-

12.1.7 model: Model configuration

-

This section describes which model PEcAn should run and some instructions for how to run it.

-
<model>
-    <id>7</id>
-    <type>ED2</type>
-    <binary>/usr/local/bin/ed2.r82</binary>
-    <prerun>module load hdf5</prerun>
-    <config.header>
-        <!--...xml code passed directly to config file...-->
-    </config.header>
-</model>
-

Some important tags are as follows:

-
    -
  • id – The unique numeric ID of the model in the PEcAn database models table. If this is present, then type and binary are optional since they can be determined from the PEcAn database.
  • -
  • type – The model “type”, matching the PEcAn database modeltypes table name column. This also refers to which PEcAn model-specific package will be used. In PEcAn, a “model” refers to a specific version (e.g. release, git commit) of a specific model, and “model type” is used to link different releases of the same model. Model “types” also have specific PFT definitions and other requirements associated with them (e.g. the ED2 model “type” requires a global land cover database).
  • -
  • binary – The file path to the model executable. If omitted, PEcAn will use whatever path is registered in the PEcAn database for the current machine.
  • -
  • prerun – Additional options added to the job.sh script, which is used to execute the model. This is useful for setting specific environment variables, load modules, etc.
  • -
-

This information is currently used by the following PEcAn workflow function:

- -
-

12.1.7.1 Model-specific configuration

-

See the following:

- -
-
-

12.1.7.2 ED2 specific tags

-

Following variables are ED specific and are used in the ED2 Configuration.

-

Starting at 1.3.7 the tags for inputs have moved to <run><inputs>. This includes, veg, soil, psscss, inputs.

-
    <edin>/home/carya/runs/PEcAn_4/ED2IN.template</edin>
-    <config.header>
-        <radiation>
-            <lai_min>0.01</lai_min>
-        </radiation>
-        <ed_misc>
-            <output_month>12</output_month>
-        </ed_misc> 
-    </config.header>
-    <phenol.scheme>0</phenol.scheme>
-
    -
  • edin : [required] template used to write ED2IN file
  • -
  • veg : OBSOLETE [required] location of VEG database, now part of <run><inputs>
  • -
  • soil : OBSOLETE [required] location of soild database, now part of <run><inputs>
  • -
  • psscss : OBSOLETE [required] location of site inforation, now part of <run><inputs>. Should be specified as <pss>, <css> and <site>.
  • -
  • inputs : OBSOLETE [required] location of additional input files (e.g. data assimilation data), now part of <run><inputs>. Should be specified as <lu> and <thsums>.
  • -
-
-
-
-

12.1.8 run: Run Setup

-

This section provides detailed configuration for the model run, including the site and time period for the simulation and what input files will be used.

-
  <run>
-    <site>
-      <id>1000000098</id>
-      <met.start>2004/01/01</met.start>
-      <met.end>2004/12/31</met.end>
-      <site.pft>
-        <pft.name>temperate.needleleaf.evergreen</pft.name>
-        <pft.name>temperate.needleleaf.evergreen.test</pft.ame>
-      </site.pft>
-    </site>
-    <inputs>
-      <met>
-        <source>CRUNCEP</source>
-        <output>SIPNET</output>
-      </met>
-      <poolinitcond>
-        <source>NEON_veg</source>
-        <output>poolinitcond</output>
-        <ensemble>100</ensemble>
-        <startdate>2019-01-01</startdate>
-        <enddate>2019-12-31</enddate>
-        <storedir>/projectnb/dietzelab/neon_store</storedir>
-      </poolinitcond>
-    </inputs>
-    <start.date>2004/01/01</start.date>
-    <end.date>2004/12/31</end.date>
-    <stop_on_error>TRUE</stop_on_error>
-  </run>
-
-

12.1.8.1 site: Where to run the model

-

This contains the following tags:

-
    -
  • id – This is the numeric ID of the site in the PEcAn database (table sites, column id). PEcAn can automatically fill in other relevant information for the site (e.g. name, lat, lon) using the site ID, so those fields are optional if ID is provided.
  • -
  • name – The name of the site, as a string.
  • -
  • lat, lon – The latitude and longitude coordinates of the site, as decimals.
  • -
  • met.start, met.end – ???
  • -
  • <site.pft> (optional) If this tag is found under the site tag, then PEcAn automatically makes sure that only PFTs defined under this tag is used for generating parameter’s samples. Following shows an example of how this tag can be added to the PEcAn xml :
  • -
-
    <site.pft>
-     <pft.name>temperate.needleleaf.evergreen</pft.name>
-     <pft.name>temperate.needleleaf.evergreen</pft.name>
-    </site.pft>
-

For multi-site runs if the pft.site tag (see {#xml-run-inputs}) is defined under input, then the above process will be done automatically under prepare settings step in PEcAn main workflow and there is no need for adding the tags manually. Using the pft.site tag however, requires a lookup table as an input (see {#xml-run-inputs}).

-
-
-

12.1.8.2 inputs: Model inputs

-

Models require several different types of inputs to run. -Exact requirements differ from model to model, but common inputs include meteorological/climate drivers, site initial conditions (e.g. vegetation composition, carbon pools), and land use drivers.

-

In general, all inputs should have the following tags:

-
    -
  • id: Numeric ID of the input in the PEcAn database (table inputs, column id). If not specified, PEcAn will try to figure this out based on the source tag (described below).
  • -
  • path: The file path of the input. Usually, PEcAn will set this automatically based on the id (which, in turn, is determined from the source). However, this can be set manually for data that PEcAn does not know about (e.g. data that you have processed yourself and have not registered with the PEcAn database).
  • -
  • source: The input data type. This tag name needs to match the names in the corresponding conversion functions. If you are using PEcAn’s automatic input processing, this is the only field you need to set. However, this field is ignored if id and/or path are provided.
  • -
  • output: ???
  • -
-

The following are the most common types of inputs, along with their corresponding tags:

-
-
12.1.8.2.1 met: Meteorological inputs
-

(Under construction. See the PEcAn.data.atmosphere package, located in modules/data.atmosphere, for more details.)

-
-
-
12.1.8.2.2 (Experimental) soil: Soil inputs
-

(Under construction. See the PEcAn.data.land package, located in modules/data.land, for more details).

-
-
-
12.1.8.2.3 (Experimental) veg: Vegetation initial conditions
-
-
-
12.1.8.2.4 poolinitcond: initial condition inputs
-
    -
  • source: Data source of initial condition .rd veg files ex: NEON_veg, FIA.
  • -
  • output: This tag can only must match the cooresponding tag in the modeltypes_formats table that matches with your model type ex for SIPNET model tag is poolinitcond.
  • -
  • ensemble: Number of initial conditions ensemble member files ex: 30.
  • -
-

(Under construction. Follow developments in the PEcAn.data.land package, located in modules/data.land in the source code).

-
-
-
12.1.8.2.5 pft.site Multi-site site / PFT mapping
-

When performing multi-site runs, it is not uncommon to find that different sites need to be run with different PFTs, rather than running all PFTs at all sites. If you’re interested to use a specific PFT for your site/sites you can use the following tag to tell PEcAn which PFT needs to be used for what site.

-
<pft.site>
-  <path>site_pft.csv</path>
-</pft.site>
-

For example using the above tag, user needs to have a csv file named site_pft stored in the pecan folder. At the moment we have functions supporting just the .csv and .txt files which are comma separated and have the following format:

-
site_id, pft_name
-1000025731,temperate.broadleaf.deciduous
-764,temperate.broadleaf.deciduous
-

Then pecan would use this lookup table to inform write.ensemble.config function about what PFTs need to be used for what sites.

-
-
-
-

12.1.8.3 start.date and end.date

-

The start and end date for the run, in a format parseable by R (e.g. YYYY/MM/DD or YYYY-MM-DD). -These dates are inclusive; in other words, they refer to the first and last days of the run, respectively.

-

NOTE: Any time-series inputs (e.g. meteorology drivers) must contain all of these dates. -PEcAn tries to detect and throw informative errors when dates are out of bounds inputs, but it may not know about some edge cases.

-
-
-

12.1.8.4 Other tags

-

The following tags are optional run settings that apply to any model:

-
    -
  • jobtemplate: the template used when creating a job.sh file, which is used to launch the actual model. Each model has its own default template in the inst folder of the corresponding R package (for instance, here is the one for ED2). The following variables can be used: @SITE_LAT@, @SITE_LON@, @SITE_MET@, @START_DATE@, @END_DATE@, @OUTDIR@, @RUNDIR@ which all come variables in the pecan.xml file. The following two command can be used to copy and clean the results from a scratch folder (specified as scratch in the run section below, for example local disk vs network disk) : @SCRATCH_COPY@, @SCRATCH_CLEAR@.

  • -
  • stop_on_error: (logical) Whether the workflow should immediately terminate if any of the model runs fail. If unset, this defaults to TRUE unless you are running an ensemble simulation (and ensemble size is greater than 1).

  • -
-

Some models also have model-specific tags, which are described in the PEcAn Models section.

-
-
-
-

12.1.9 host: Host information for remote execution

-

This section provides settings for remote model execution, i.e. any execution that happens on a machine (including “virtual” machines, like Docker containers) different from the one on which the main PEcAn workflow is running. -A common use case for this section is to submit model runs as jobs to a high-performance computing cluster. -If no host tag is provided, PEcAn assumes models are run on localhost, a.k.a. the same machine as PEcAn itself.

-

For detailed instructions on remote execution, see the Remote Execution page. -For detailed information on configuring this for RabbitMQ, see the RabbitMQ page. -The following provides a quick overview of XML tags related to remote execution.

-

NOTE: Any paths specified in the pecan.xml refer to paths on the host specified in this section, /not/ the machine on which PEcAn is running (unless models are running on localhost or this section is omitted).

-
    <host>
-        <name>pecan2.bu.edu</name>
-        <rundir>/fs/data3/guestuser/pecan/testworkflow/run</rundir>
-        <outdir>/fs/data3/guestuser/pecan/testworkflow/out</outdir>
-        <scratchdir>/tmp/carya</scratchdir>
-        <clearscratch>TRUE</clearscratch>
-        <qsub>qsub -N @NAME@ -o @STDOUT@ -e @STDERR@ -S /bin/bash</qsub>
-        <qsub.jobid>Your job ([0-9]+) .*</qsub.jobid>
-        <qstat>'qstat -j @JOBID@ &amp;> /dev/null || echo DONE'</qstat>
-        <prerun>module load udunits R/R-3.0.0_gnu-4.4.6</prerun>
-        <cdosetup>module load cdo/2.0.6</cdosetup>
-        <modellauncher>
-      <binary>/usr/local/bin/modellauncher</binary>
-      <qsub.extra>-pe omp 20</qsub.extra>
-        </modellauncher>
-    </host>
-

The host section has the following tags:

-
    -
  • name: [optional] name of host server where model is located and executed, if not specified localhost is assumed.
  • -
  • folder: [required] The location to store files on the remote machine. For localhost this is optional (<outdir> is the default), for any other host this is required.
  • -
  • rundir: [optional] location where all the configuration files are written. If not specified, this will be generated starting at the path specified in folder.
  • -
  • outdir: [optional] location where all the outputs of the model are written. If not specified, this will be generated starting at the path specified in folder.
  • -
  • scratchdir: [optional] location where output is written. If specified the output from the model is written to this folder and copied to the outdir when the model is finished, this could significantly speed up the model execution (by using local or ram disk).
  • -
  • clearscratch: [optional] if set to TRUE the scratchfolder is cleaned up after copying the results to the outdir, otherwise the folder will be left. The default is to clean up after copying.
  • -
  • qsub: [optional] the command to submit a job to the queuing system. There are 3 parameters you can use when specifying the qsub command, you can add additional values for your specific setup (for example -l walltime to specify the walltime, etc). You can specify @NAME@ the pretty name, @STDOUT@ where to write stdout and @STDERR@, where to write stderr. You can specify an empty element (<qsub/>) in which case it will use the default value is qsub -V -N @NAME@ -o @STDOUT@ -e @STDERR@ -s /bin/bash.
  • -
  • qsub.jobid: [optional] the regular expression used to find the jobid returned from qsub. If not specified (and qsub is) it will use the default value is Your job ([0-9]+) .*
  • -
  • qstat: [optional] the command to execute to check if a job is finished, this should return DONE if the job is finished. There is one parameter this command should take @JOBID@ which is the ID of the job as returned by qsub.jobid. If not specified (and qsub is) it will use the default value is qstat -j @JOBID@ || echo DONE
  • -
  • prerun: [optional] additional options to add to the job.sh at the top.
  • -
  • cdosetup: [optional] additional options to add to the job.sh at the top, specifically work for the CDO Linux command line package, allowing the user to generate the full year netCDF file through model2netcdf.SIPNET function (there has been an issue while this function will iteratively overlap the previous netCDF file, resulting in partial data loss).
  • -
  • modellauncher: [optional] this is an experimental section that will allow you to submit all the runs as a single job to a HPC system.
  • -
-

The modellauncher section if specified will group all runs together and only submit a single job to the HPC cluster. This single job will leverage of a MPI program that will execute a single run. Some HPC systems will place a limit on the number of jobs that can be executed in parallel, this will only submit a single job (using multiple nodes). In case there is no limit on the number of jobs, a single PEcAn run could potentially submit a lot of jobs resulting in the full cluster running jobs for a single PEcAn run, preventing others from executing on the cluster.

-

The modellauncher has 3 arguments: -* binary : [required] The full path to the binary modellauncher. Source code for this file can be found in pecan/contrib/modellauncher](https://github.com/PecanProject/pecan/tree/develop/contrib/modellauncher). -* qsub.extra : [optional] Additional flags to pass to qsub besides those specified in the qsub tag in host. This option can be used to specify that the MPI environment needs to be used and the number of nodes that should be used. -* mpirun: [optional] Additional commands to be added to the front of launcher.sh. Default is mpirun <path to binary> <path to joblist.txt>. Edit this to, for example, load necessary modules to run mpirun.

-
-
-
- -
-
-
- - -
-
- - - - - - - - - - - - - - - diff --git a/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/README.txt b/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/README.txt deleted file mode 100644 index 40f7c3623..000000000 --- a/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/README.txt +++ /dev/null @@ -1 +0,0 @@ -Autogenerated by https://github.com/PecanProject/pecan/actions/workflows/render-quarto.yml diff --git a/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/run_pecan.html b/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/run_pecan.html deleted file mode 100644 index 88b4a7824..000000000 --- a/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/run_pecan.html +++ /dev/null @@ -1,1215 +0,0 @@ - - - - - - - - - - - -Running Ecosystem Simulations Using PEcAn - - - - - - - - - - - - - - - - - - - -
- -
- -
-
-

Running Ecosystem Simulations Using PEcAn

-
- - - -
- -
-
Authors
-
-

Aritra Dey

-

David LeBauer

-
-
- - - -
- - - -
- - -
-

Introduction

-

Welcome to this PEcAn workflow notebook! This notebook will guide you through running an ecosystem model using PEcAn’s programmatic interface.

-
-

What Is PEcAn?

-

PEcAn (Predictive Ecosystem Analyzer) is a scientific workflow system designed to make ecosystem modeling more transparent, repeatable, and accessible. It helps researchers:

-
    -
  • Run ecosystem models with standardized inputs and outputs
  • -
  • Perform uncertainty analysis on model parameters
  • -
  • Compare model predictions with observations
  • -
  • Share and reproduce scientific workflows
  • -
-
-
-

What This Notebook Does

-

This notebook demonstrates how to:

-
    -
  1. Set up and configure a PEcAn workflow
  2. -
  3. Run an ecosystem model simulation
  4. -
  5. Analyze and visualize the results
  6. -
-
-

The Scenario Being Modeled:

-

We are modeling carbon and productivity dynamics at the Niwot Ridge Forest AmeriFlux site (US-NR1, a high-elevation temperate coniferous forest in Colorado. The model configuration uses the SIPNET process-based ecosystem model, parameterized with a temperate coniferous plant functional type (PFT).

-

The simulation is run for the full year 2004 (January 1 – December 31) using AmeriFlux LBL meteorological drivers from the Niwot Ridge site. The ensemble setup specifies one model run focusing on net primary productivity (NPP) as the target output variable.

-

This scenario is designed to be a minimal, reproducible example to demonstrate how to run SIPNET within the PEcAn workflow. In later steps, this same framework can be extended to include more ensemble members, additional PFTs, longer time periods, or alternative meteorological inputs.

-

This run is based on a study by Moore et. al. (2007) that uses SIPNET to understand the relationship between water and carbon balance at this site.

-
-
-
-

Prerequisites

-

Before running this notebook, make sure you have:

-
    -
  • All the PEcAn packages installed. You can install all PEcAn packages and their dependencies by running the following command in the root of your PEcAn repository:
  • -
-

-# Enable repository from pecanproject
-options(repos = c(
-  pecanproject = 'https://pecanproject.r-universe.dev',
-  CRAN = 'https://cloud.r-project.org'))
-# Download and install PEcAn.all in R
-install.packages('PEcAn.all')
-
-
    -
  • A valid pecan.xml configuration file or use the example provided: pecan/documentation/tutorials/Demo_1_Basic_Run/pecan.xml
  • -
-
-
-

How to Use This Notebook

-
    -
  1. Each section is clearly marked with a heading
  2. -
  3. Code chunks are provided with explanations
  4. -
  5. You can run the code chunks sequentially
  6. -
  7. Once you have successfully run the demo, you can modify parameters to configure new runs and analyses
  8. -
-

Objective:

-

This demo illustrates how to run a basic PEcAn workflow using an R-based Quarto notebook. It will cover loading settings, writing model configuration files, and running model simulations. This approach provides a programmatic alternative to the web-based PEcAn interface for executing ecosystem models.

-
-
-
-

Session Info

-

This section prints your R session information for reproducibility. Having this information at the beginning helps with debugging even if the notebook encounters errors later.

-
-
PEcAn.all::pecan_version()
-
-
 package               v1.9.0 installed  source              
- PEcAn.all             1.9.0  1.9.0.9000 local (/pecan/bas...
- PEcAn.allometry       1.7.4  1.7.4.9000 local (/pecan/mod...
- PEcAn.assim.batch     1.9.0  1.9.0.9000 local (/pecan/mod...
- PEcAn.BASGRA          1.8.1  1.8.1.9000 local (/pecan/mod...
- PEcAn.benchmark       1.7.4  1.7.4.9000 local (/pecan/mod...
- PEcAn.BIOCRO          1.7.4  1.7.5      local (/pecan/mod...
- PEcAn.CABLE           1.7.4  NA         NA                  
- PEcAn.CLM45           1.7.4  1.7.4.9000 local (/pecan/mod...
- PEcAn.DALEC           1.7.4  1.7.5      local (/pecan/mod...
- PEcAn.data.atmosphere 1.9.0  1.9.1      local (/pecan/mod...
- PEcAn.data.land       1.8.1  1.8.2      local (/pecan/mod...
- PEcAn.data.mining     1.7.4  NA         NA                  
- PEcAn.data.remote     1.9.0  1.9.1      local (/pecan/mod...
- PEcAn.DB              1.8.1  1.8.1.9000 local (/pecan/bas...
- PEcAn.dvmdostem       1.7.4  1.7.5      local (/pecan/mod...
- PEcAn.ED2             1.8.1  1.8.2      local (/pecan/mod...
- PEcAn.emulator        1.8.1  1.8.1.9000 local (/pecan/mod...
- PEcAn.FATES           1.8.0  1.8.1      local (/pecan/mod...
- PEcAn.GDAY            1.7.4  1.7.5      local (/pecan/mod...
- PEcAn.JULES           1.7.4  1.7.5      local (/pecan/mod...
- PEcAn.LDNDC           1.0.1  1.0.2      local (/pecan/mod...
- PEcAn.LINKAGES        1.7.4  1.7.5      local (/pecan/mod...
- PEcAn.logger          1.8.3  1.8.4      local (/pecan/bas...
- PEcAn.LPJGUESS        1.8.0  1.8.1      local (/pecan/mod...
- PEcAn.MA              1.7.4  1.7.4.9000 local (/pecan/mod...
- PEcAn.MAAT            1.7.4  1.7.5      local (/pecan/mod...
- PEcAn.MAESPA          1.7.4  1.7.5      local (/pecan/mod...
- PEcAn.ModelName       1.8.1  1.8.1.9000 local (/pecan/mod...
- PEcAn.photosynthesis  1.7.4  1.7.4.9000 local (/pecan/mod...
- PEcAn.PRELES          1.7.4  NA         NA                  
- PEcAn.priors          1.7.4  1.7.4.9000 local (/pecan/mod...
- PEcAn.qaqc            1.7.4  1.7.4.9000 local (/pecan/bas...
- PEcAn.remote          1.9.0  1.9.0.9000 local (/pecan/bas...
- PEcAn.settings        1.9.0  1.9.1      local (/pecan/bas...
- PEcAn.SIBCASA         0.0.2  0.0.3      local (/pecan/mod...
- PEcAn.SIPNET          1.9.0  1.9.1      local (/pecan/mod...
- PEcAn.STICS           1.8.1  1.8.2      local (/pecan/mod...
- PEcAn.uncertainty     1.8.1  1.8.2      local (/pecan/mod...
- PEcAn.utils           1.8.1  1.8.2      local (/pecan/bas...
- PEcAn.visualization   1.8.1  1.8.1.9000 local (/pecan/bas...
- PEcAn.workflow        1.9.0  1.9.0.9000 local (/pecan/bas...
- PEcAnAssimSequential  1.9.0  1.9.0.9000 local (/pecan/mod...
- PEcAnRTM              1.7.4  1.9.0.9000 local (/pecan/mod...
-
-
-
-
-

Install SIPNET v1.3.0

-

If you haven’t already installed the SIPNET binary, you can do so by running the following code. This will download the SIPNET binary to demo_outdir/sipnet and make it executable.

-
-

Note: The demo_outdir directory will be created in the root of your PEcAn installation (i.e., at pecan/demo_outdir/). This directory will contain the SIPNET binary as well as the output generated by PEcAn in this demo.

-
-
-
# Download and install SIPNET v1.3.0
-source(
-  here::here(
-    "documentation/tutorials/Demo_1_Basic_Run/download_sipnet.R"
-  )
-)
-
-
-

Note: You can find the most recent version of the SIPNET binary at: SIPNET GitHub Releases, but this notebook is designed to work with SIPNET v1.3.0.

-
-
-
-

Load PEcAn Packages

-

First, we need to load the PEcAn R packages. These packages provide all the functions we’ll use to run the workflow.

-
-
# Load the PEcAn.all package, which includes all necessary PEcAn functionality
-library("PEcAn.all")
-
-
Loading required package: PEcAn.DB
-
-
-
Loading required package: PEcAn.settings
-
-
-
Loading required package: PEcAn.MA
-
-
-
Loading required package: PEcAn.logger
-
-
-
Loading required package: PEcAn.utils
-
-
-
Loading required package: PEcAn.uncertainty
-
-
-
Loading required package: PEcAn.data.atmosphere
-
-
-
Loading required package: PEcAn.data.land
-
-
-
Loading required package: PEcAn.data.remote
-
-
-
Loading required package: PEcAn.assim.batch
-
-
-
Loading required package: PEcAn.emulator
-
-
-
Loading required package: PEcAn.priors
-
-
-
Loading required package: PEcAn.benchmark
-
-
-
Loading required package: PEcAn.remote
-
-
-
Loading required package: PEcAn.workflow
-
-
-
-
-

Load PEcAn Settings File

-

PEcAn uses an XML-based settings file (pecan.xml) to configure model runs. This file defines key information about the run including: PFT(s), site location, time period of the run, the location of input files and where outputs will be saved. Other settings outside the scope of this demo include the types of analyses that will be performed, how to connect to a database, and how to run it on a high performance computing cluster (we are using the default single model run on a single computer).

-

You can read more about the settings file in the “PEcAn XML” chapter of the documentation.

-

There is an example pecan.xml that has been configured for this demonstration. You can find it at pecan/documentation/tutorials/Demo_1_Basic_Run/pecan.xml.

-

This is how PEcAn loads the settings file:

-
-
settings_path <- here::here("documentation/tutorials/Demo_1_Basic_Run/pecan.xml")
-
-
-
-

Prepare and Validate Settings

-

After specifying the path to the pecan.xml file, the next step involves reading and preparing these settings. PEcAn provides utilities to process and validate the configurations before execution begins.

-
    -
  • PEcAn.settings::read.settings(settings_path): Reads the pecan.xml file and converts it to an R list object.
  • -
  • PEcAn.settings::prepare.settings(settings): Prepares and validates settings. It sets defaults for missing fields, changes file paths to absolute paths, and generally ensures consistency.
  • -
-
-
# Read the settings from the pecan.xml file
-settings <- PEcAn.settings::read.settings(settings_path)
-
-# Prepare and validate the settings
-settings <- PEcAn.settings::prepare.settings(settings)
-
-
-
-

Explore the Settings Object

-

Once the settings have been read and prepared, it is useful to inspect the structure of the settings object. This object is an R list containing all parameters and configurations for the PEcAn workflow.

-
    -
  • str(settings) displays the internal structure of the settings object. This shows how the settings are represented in R and is useful for debugging and verifying settings.
  • -
-
-
str(settings)
-
-
List of 12
- $ info         :List of 4
-  ..$ notes   : NULL
-  ..$ userid  : chr "-1"
-  ..$ username: NULL
-  ..$ date    : chr "2025-06-19-15-34-01"
- $ outdir       : chr "/work/documentation/tutorials/Demo_1_Basic_Run/demo_outdir"
- $ pfts         :List of 1
-  ..$ pft:List of 3
-  .. ..$ name           : chr "temperate.coniferous"
-  .. ..$ posterior.files: chr "pft/temperate.coniferous/prior.distns.Rdata"
-  .. ..$ outdir         : chr "pft/temperate.coniferous"
- $ ensemble     :List of 5
-  ..$ variable     : chr "NPP"
-  ..$ size         : num 1
-  ..$ start.year   : num 2004
-  ..$ end.year     : num 2004
-  ..$ samplingspace:List of 2
-  .. ..$ parameters:List of 1
-  .. .. ..$ method: chr "uniform"
-  .. ..$ met       :List of 1
-  .. .. ..$ method: chr "sampling"
- $ model        :List of 5
-  ..$ type      : chr "SIPNET"
-  ..$ revision  : chr "git"
-  ..$ delete.raw: chr "FALSE"
-  ..$ binary    : chr "demo_outdir/sipnet"
-  ..$ id        : num -1
- $ run          :List of 4
-  ..$ site      :List of 6
-  .. ..$ met.start: chr "2004/01/01"
-  .. ..$ met.end  : chr "2004/12/31"
-  .. ..$ name     : chr "Niwot Ridge Forest/LTER NWT1 (US-NR1)"
-  .. ..$ lat      : chr "40.0329"
-  .. ..$ lon      : chr "-105.546"
-  .. ..$ id       : num -1
-  ..$ inputs    :List of 1
-  .. ..$ met:List of 4
-  .. .. ..$ source  : chr "AmerifluxLBL"
-  .. .. ..$ output  : chr "SIPNET"
-  .. .. ..$ username: chr "Aritra_2004"
-  .. .. ..$ path    :List of 1
-  .. .. .. ..$ path1: chr "dbfiles/AMF_US-NR1_BASE_HH_23-5.2004-01-01.2004-12-31.clim"
-  ..$ start.date: chr "2004/01/01"
-  ..$ end.date  : chr "2004/12/31"
- $ host         :List of 3
-  ..$ name  : chr "localhost"
-  ..$ rundir: chr "/work/documentation/tutorials/Demo_1_Basic_Run/demo_outdir/run"
-  ..$ outdir: chr "/work/documentation/tutorials/Demo_1_Basic_Run/demo_outdir/out"
- $ settings.info:List of 3
-  ..$ deprecated.settings.fixed: logi TRUE
-  ..$ settings.updated         : logi TRUE
-  ..$ checked                  : logi TRUE
- $ database     :List of 1
-  ..$ dbfiles: chr "/root/.pecan/dbfiles"
- $ workflow     :List of 1
-  ..$ id: chr "2025-12-05-16-59-39"
- $ rundir       : chr "/work/documentation/tutorials/Demo_1_Basic_Run/demo_outdir/run"
- $ modeloutdir  : chr "/work/documentation/tutorials/Demo_1_Basic_Run/demo_outdir/out"
- - attr(*, "class")= chr [1:3] "Settings" "SafeList" "list"
-
-
-

Your turn: explore the settings object further using the following commands: * names(settings) to list the top-level keys in the settings object * Once you know the names, you can look at each component in detail, for example: * settings$run to access the run-specific settings, such as start and end dates, model type, and output directory * settings$pfts to explore the Plant Functional Types settings

-

Now you can update each of these settings. Here is a simple example:

-
-
settings$info <- list(
-  author = "Aritra Dey",
-  date = Sys.Date(),
-  description = "Demo run of PEcAn using SIPNET"
-)
-
-

Editing the more interesting settings to change the PFT (settings$pfts) or extend the run (settings$run$end.date) is beyond the scope of this demo. You could change the pft or the end date, but you would need a new file containing parameters for that PFT (settings$pfts$pft$posterior.files), or a climate file (settings$run$met$path$path1) that extends to the desired simulation period.

-

The directory structure created by PEcAn for this demo run will look like this:

-
demo_outdir/               # Root output directory
-├── run/                   # Configuration & execution metadata
-│   ├── runs.txt           # List of run IDs (one per model realization)
-│   ├── <runid>/           # Model-specific config copies (sometimes)
-│   └── config.*           # Generated model configs (e.g., SIPNET)
-├── out/                   # Raw model outputs by run ID
-│   └── <runid>/           # E.g., daily or sub-daily SIPNET output files
-

The root output directory is defined here as demo_outdir/ by settings$outdir. This directory contains log and record files from the PEcAn workflow. They provide a detailed record of how data was generated and are key components of the analysis metadata and provenance. These can be useful for debugging as well as for downstream analysis.

-

Key subdirectories include run/ and out/ that contain files used to configure and run the model, files generated by the underlying ecosystem model, and PEcAn standard outputs used in downstream analyses. These are described in subsequent sections.

-

Additional outputs include logs, a STATUS file that records the steps of the workflow along with timestamps and whether each step was successful, and a copy of the pecan.*.xml file.

-
-
-

Write Model Configuration Files

-

This step generates the model-specific configuration files and scripts that will be used to run the ecosystem model. The process involves:

-
    -
  1. Disabling database write operations because we are not using a database
  2. -
  3. Generating SIPNET configuration files using the runModule.run.write.configs() function.
  4. -
-
-
settings$database <- NULL # Disable database operations for this demo
-settings <- PEcAn.workflow::runModule.run.write.configs(settings)
-
-
Error in postgresqlNewConnection(drv, ...) : 
-  RPosgreSQL error: could not connect root@/var/run/postgresql:5432 on dbname "root": connection to server on socket "/var/run/postgresql/.s.PGSQL.5432" failed: No such file or directory
-    Is the server running locally and accepting connections on that socket?
-
-
-
Loading required package: PEcAn.SIPNET
-
-
-
-
-

Run Model Simulations and Fetch Results

-

This section executes the actual model simulations and retrieves the results. The process is managed by PEcAn’s workflow system, which handles the execution of your chosen ecosystem model.

-
    -
  • runModule_start_model_runs(settings): This function initiates the model runs based on your configuration. It manages the execution of your chosen ecosystem model, using the configuration files generated in the previous step.
  • -
-
-
PEcAn.workflow::runModule_start_model_runs(settings)
-
-

-  |                                                                            
-  |                                                                      |   0%
-  |                                                                            
-  |======================================================================| 100%
-
-
-

This step generates raw model outputs in model-specific format (in this case, sipnet.out) as well as log files.

-
-
-

Extract Model Results and Prepare for Analysis

-

After the model simulation completes, we need to extract the results and prepare them for analysis. This involves:

-
    -
  1. Reading the run ID
  2. -
  3. Setting up output paths
  4. -
  5. Defining time period
  6. -
  7. Loading model output
  8. -
  9. Convert to a standard format
  10. -
-
-
runid <- as.character(read.table(paste(settings$outdir, "/run/", "runs.txt", sep = ""))[1, 1]) # Note: if you are using an xml from a run with multiple ensembles this line will provide only the first run id
-outdir <- file.path(settings$outdir, "/out/", runid)
-start.year <- lubridate::year(settings$run$start.date)
-end.year <- lubridate::year(settings$run$end.date)
-model_output <- PEcAn.utils::read.output(
-  runid,
-  outdir,
-  start.year,
-  end.year,
-  variables = NULL,
-  dataframe = TRUE,
-  verbose = FALSE
-)
-available_vars <- names(model_output)[!names(model_output) %in% c("posix", "time_bounds")]
-
-

Running this code will convert model specific output files into a standardized netCDF ([year].nc) that can be downloaded for visualization and analysis (R, Matlab, ncview, panoply, etc). This is a key step, because this standardization enables PEcAn to apply downstream analyses to outputs from different ecosystem models.

-
-
-

Display Available Model Variables

-

This section shows all the variables that are available in the model output. These variables represent different ecosystem processes and states that the model has simulated.

-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Model Output Variables and Descriptions
VariableDescription
GPPGross Primary Productivity
NEENet Ecosystem Exchange
TotalRespTotal Respiration
AutoRespAutotrophic Respiration
HeteroRespHeterotrophic Respiration
SoilRespSoil Respiration
NPPNet Primary Productivity
GWBIGross Woody Biomass Increment
TotLivBiomTotal living biomass
AGBTotal aboveground biomass
LAILeaf Area Index
leaf_carbon_contentLeaf Carbon Content
fine_root_carbon_contentFine Root Carbon Content
coarse_root_carbon_contentCoarse Root Carbon Content
AbvGrndWoodAbove ground woody biomass
TotSoilCarbTotal Soil Carbon
litter_carbon_contentLitter Carbon Content
QleLatent heat
TranspTotal transpiration
SoilMoistAverage Layer Soil Moisture
SoilMoistFracAverage Layer Fraction of Saturation
SWESnow Water Equivalent
litter_mass_content_of_waterAverage layer litter moisture
yearYear
-
-
-
-
-

Visualize Model Results

-

This section provides examples of how to create time series plots of different model variables. The examples cover various ecosystem processes including carbon fluxes, carbon pools, water variables, and structural variables like Leaf Area Index (LAI).

-
-

Plot Carbon Fluxes

-
-
# Plot Gross Primary Productivity (GPP) and Net Primary Productivity (NPP)
-plot(model_output$posix, model_output$GPP,
-  type = "l",
-  col = "green",
-  xlab = "Date",
-  ylab = "Carbon Flux (kg C m-2 s-1)",
-  main = "Carbon Fluxes Over Time"
-)
-lines(model_output$posix, model_output$NPP, col = "blue")
-legend("topright", legend = c("GPP", "NPP"), col = c("green", "blue"), lty = 1)
-
-
-
-

-
-
-
-
-
-
-

Plot Carbon Pools

-
-
# Plot Total Live Biomass and Total Soil Carbon
-plot(model_output$posix, model_output$TotLivBiom,
-  type = "l",
-  col = "darkgreen",
-  xlab = "Date",
-  ylab = "Carbon Pool (kg C m-2)",
-  main = "Carbon Pools Over Time"
-)
-lines(model_output$posix, model_output$TotSoilCarb, col = "brown")
-legend("topright", legend = c("Total Live Biomass", "Total Soil Carbon"), col = c("darkgreen", "brown"), lty = 1)
-
-
-
-

-
-
-
-
-
-
-

Plot Water Variables

-
-
# Plot Soil Moisture and Snow Water Equivalent
-plot(model_output$posix, model_output$SoilMoist,
-  type = "l",
-  col = "blue",
-  xlab = "Date",
-  ylab = "Soil Moisture (kg m-2)",
-  main = "Soil Moisture Over Time"
-)
-lines(model_output$posix, model_output$SWE, col = "lightblue")
-legend("topright", legend = c("Soil Moisture", "Snow Water Equivalent"), col = c("blue", "lightblue"), lty = 1)
-
-
-
-

-
-
-
-
-
-
-

Plot LAI and Biomass

-
-
# Plot Leaf Area Index (LAI) and Above Ground Wood
-plot(model_output$posix, model_output$LAI,
-  type = "l",
-  col = "darkgreen",
-  xlab = "Date",
-  ylab = "LAI (m2 m-2)",
-  main = "Leaf Area Index Over Time"
-)
-lines(model_output$posix, model_output$AbvGrndWood, col = "brown")
-legend("topright", legend = c("LAI", "Above Ground Wood"), col = c("darkgreen", "brown"), lty = 1)
-
-
-
-

-
-
-
-
-
-
-
-

Conclusion

-

This notebook demonstrated how to set up, run, and analyze a PEcAn ecosystem model workflow programmatically. You can now modify parameters, try different models, or extend the analysis as needed.

-

Try editing the pecan.xml file. Give it a new name and update the settings_path variable at the beginning of this Demo to point to the new file. See how the changes affect the model output!

-
-
-

Clean Up Workflow Output (Optional)

-

If you want to remove all files and directories created by this workflow and start fresh, you can run the following code. This will delete the entire output directory specified in your settings. Use with caution!

-
-
# WARNING: This will permanently delete all workflow output files!
-# Uncomment the line below to enable cleanup.
-# fs::dir_delete(settings$outdir)
-
-
-
-

Session Info

-

This section prints your R session information for reproducibility.

-
-
sessionInfo()
-
-
R version 4.4.3 (2025-02-28)
-Platform: x86_64-pc-linux-gnu
-Running under: Ubuntu 24.04.2 LTS
-
-Matrix products: default
-BLAS:   /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3 
-LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.26.so;  LAPACK version 3.12.0
-
-locale:
- [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C              
- [3] LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8    
- [5] LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8   
- [7] LC_PAPER=en_US.UTF-8       LC_NAME=C                 
- [9] LC_ADDRESS=C               LC_TELEPHONE=C            
-[11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       
-
-time zone: Etc/UTC
-tzcode source: system (glibc)
-
-attached base packages:
-[1] stats     graphics  grDevices utils     datasets  methods   base     
-
-other attached packages:
- [1] PEcAn.SIPNET_1.9.1           PEcAn.all_1.9.0.9000        
- [3] PEcAn.workflow_1.9.0.9000    PEcAn.remote_1.9.0.9000     
- [5] PEcAn.benchmark_1.7.4.9000   PEcAn.priors_1.7.4.9000     
- [7] PEcAn.emulator_1.8.1.9000    PEcAn.assim.batch_1.9.0.9000
- [9] PEcAn.data.remote_1.9.1      PEcAn.data.land_1.8.2       
-[11] PEcAn.data.atmosphere_1.9.1  PEcAn.uncertainty_1.8.2     
-[13] PEcAn.utils_1.8.2            PEcAn.logger_1.8.4          
-[15] PEcAn.MA_1.7.4.9000          PEcAn.settings_1.9.1        
-[17] PEcAn.DB_1.8.1.9000         
-
-loaded via a namespace (and not attached):
- [1] PEcAn.qaqc_1.7.4.9000           DBI_1.2.3                      
- [3] PEcAn.allometry_1.7.4.9000      rlang_1.1.5                    
- [5] magrittr_2.0.3                  furrr_0.3.1                    
- [7] e1071_1.7-16                    compiler_4.4.3                 
- [9] vctrs_0.6.5                     stringr_1.5.1                  
-[11] pkgconfig_2.0.3                 PEcAn.MAESPA_1.7.5             
-[13] fastmap_1.2.0                   PEcAn.ED2_1.8.2                
-[15] PEcAn.dvmdostem_1.7.5           PEcAn.ModelName_1.8.1.9000     
-[17] rmarkdown_2.29                  sessioninfo_1.2.3              
-[19] pracma_2.4.4                    purrr_1.0.4                    
-[21] xfun_0.52                       PEcAn.JULES_1.7.5              
-[23] jsonlite_2.0.0                  PEcAn.LINKAGES_1.7.5           
-[25] PEcAn.SIBCASA_0.0.3             parallel_4.4.3                 
-[27] R6_2.6.1                        PEcAn.DALEC_1.7.5              
-[29] stringi_1.8.7                   RPostgreSQL_0.7-8              
-[31] PEcAn.CLM45_1.7.4.9000          parallelly_1.43.0              
-[33] lubridate_1.9.4                 numDeriv_2016.8-1.1            
-[35] Rcpp_1.0.14                     iterators_1.0.14               
-[37] knitr_1.50                      PEcAnAssimSequential_1.9.0.9000
-[39] igraph_2.1.4                    timechange_0.3.0               
-[41] tidyselect_1.2.1                abind_1.4-8                    
-[43] yaml_2.3.10                     PEcAn.LPJGUESS_1.8.1           
-[45] codetools_0.2-20                listenv_0.9.1                  
-[47] lattice_0.22-6                  tibble_3.2.1                   
-[49] withr_3.0.2                     coda_0.19-4.1                  
-[51] evaluate_1.0.3                  future_1.34.0                  
-[53] sf_1.0-20                       units_0.8-7                    
-[55] proxy_0.4-27                    PEcAn.BASGRA_1.8.1.9000        
-[57] pillar_1.10.2                   PEcAn.BIOCRO_1.7.5             
-[59] KernSmooth_2.23-26              foreach_1.5.2                  
-[61] ncdf4_1.24                      generics_0.1.3                 
-[63] nimble_1.3.0                    rprojroot_2.0.4                
-[65] ggplot2_3.5.2                   munsell_0.5.1                  
-[67] scales_1.3.0                    globals_0.16.3                 
-[69] PEcAn.MAAT_1.7.5                PEcAn.STICS_1.8.2              
-[71] class_7.3-23                    glue_1.8.0                     
-[73] tools_4.4.3                     data.table_1.17.0              
-[75] XML_3.99-0.18                   grid_4.4.3                     
-[77] PEcAn.visualization_1.8.1.9000  PEcAn.photosynthesis_1.7.4.9000
-[79] colorspace_2.1-1                cli_3.6.4                      
-[81] PEcAnRTM_1.9.0.9000             dplyr_1.1.4                    
-[83] PEcAn.GDAY_1.7.5                gtable_0.3.6                   
-[85] PEcAn.FATES_1.8.1               digest_0.6.37                  
-[87] classInt_0.4-11                 PEcAn.LDNDC_1.0.2              
-[89] rjson_0.2.23                    htmlwidgets_1.6.4              
-[91] htmltools_0.5.8.1               lifecycle_1.0.4                
-[93] here_1.0.1                     
-
-
-
- -
- - -
- - - - - \ No newline at end of file diff --git a/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/run_pecan_files/figure-html/plot-carbon-fluxes-1.png b/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/run_pecan_files/figure-html/plot-carbon-fluxes-1.png deleted file mode 100644 index 3c6af79af..000000000 Binary files a/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/run_pecan_files/figure-html/plot-carbon-fluxes-1.png and /dev/null differ diff --git a/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/run_pecan_files/figure-html/plot-carbon-pools-1.png b/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/run_pecan_files/figure-html/plot-carbon-pools-1.png deleted file mode 100644 index ae4bbecbf..000000000 Binary files a/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/run_pecan_files/figure-html/plot-carbon-pools-1.png and /dev/null differ diff --git a/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/run_pecan_files/figure-html/plot-lai-biomass-1.png b/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/run_pecan_files/figure-html/plot-lai-biomass-1.png deleted file mode 100644 index 5705e2b3b..000000000 Binary files a/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/run_pecan_files/figure-html/plot-lai-biomass-1.png and /dev/null differ diff --git a/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/run_pecan_files/figure-html/plot-water-variables-1.png b/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/run_pecan_files/figure-html/plot-water-variables-1.png deleted file mode 100644 index b32ff3867..000000000 Binary files a/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/run_pecan_files/figure-html/plot-water-variables-1.png and /dev/null differ diff --git a/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/run_pecan_files/libs/bootstrap/bootstrap-icons.css b/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/run_pecan_files/libs/bootstrap/bootstrap-icons.css deleted file mode 100644 index 285e4448f..000000000 --- a/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/run_pecan_files/libs/bootstrap/bootstrap-icons.css +++ /dev/null @@ -1,2078 +0,0 @@ -/*! - * Bootstrap Icons v1.11.1 (https://icons.getbootstrap.com/) - * Copyright 2019-2023 The Bootstrap Authors - * Licensed under MIT (https://github.com/twbs/icons/blob/main/LICENSE) - */ - -@font-face { - font-display: block; - font-family: "bootstrap-icons"; - src: -url("./bootstrap-icons.woff?2820a3852bdb9a5832199cc61cec4e65") format("woff"); -} - -.bi::before, -[class^="bi-"]::before, -[class*=" bi-"]::before { - display: inline-block; - font-family: bootstrap-icons !important; - font-style: normal; - font-weight: normal !important; - font-variant: normal; - text-transform: none; - line-height: 1; - vertical-align: -.125em; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -.bi-123::before { content: "\f67f"; } -.bi-alarm-fill::before { content: "\f101"; } -.bi-alarm::before { content: "\f102"; } -.bi-align-bottom::before { content: "\f103"; } -.bi-align-center::before { content: "\f104"; } -.bi-align-end::before { content: "\f105"; } -.bi-align-middle::before { content: "\f106"; } -.bi-align-start::before { content: "\f107"; } -.bi-align-top::before { content: "\f108"; } -.bi-alt::before { content: "\f109"; } -.bi-app-indicator::before { content: "\f10a"; } -.bi-app::before { content: "\f10b"; } -.bi-archive-fill::before { content: "\f10c"; } -.bi-archive::before { content: "\f10d"; } -.bi-arrow-90deg-down::before { content: "\f10e"; } -.bi-arrow-90deg-left::before { content: "\f10f"; } -.bi-arrow-90deg-right::before { content: "\f110"; } -.bi-arrow-90deg-up::before { content: "\f111"; } -.bi-arrow-bar-down::before { content: "\f112"; } -.bi-arrow-bar-left::before { content: "\f113"; } -.bi-arrow-bar-right::before { content: "\f114"; } -.bi-arrow-bar-up::before { content: "\f115"; } -.bi-arrow-clockwise::before { content: "\f116"; } -.bi-arrow-counterclockwise::before { content: "\f117"; } -.bi-arrow-down-circle-fill::before { content: "\f118"; } -.bi-arrow-down-circle::before { content: "\f119"; } -.bi-arrow-down-left-circle-fill::before { content: "\f11a"; } -.bi-arrow-down-left-circle::before { content: "\f11b"; } -.bi-arrow-down-left-square-fill::before { content: "\f11c"; } -.bi-arrow-down-left-square::before { content: "\f11d"; } -.bi-arrow-down-left::before { content: "\f11e"; } -.bi-arrow-down-right-circle-fill::before { content: "\f11f"; } -.bi-arrow-down-right-circle::before { content: "\f120"; } -.bi-arrow-down-right-square-fill::before { content: "\f121"; } -.bi-arrow-down-right-square::before { content: "\f122"; } -.bi-arrow-down-right::before { content: "\f123"; } -.bi-arrow-down-short::before { content: "\f124"; } -.bi-arrow-down-square-fill::before { content: "\f125"; } -.bi-arrow-down-square::before { content: "\f126"; } -.bi-arrow-down-up::before { content: "\f127"; } -.bi-arrow-down::before { content: "\f128"; } -.bi-arrow-left-circle-fill::before { content: "\f129"; } -.bi-arrow-left-circle::before { content: "\f12a"; } -.bi-arrow-left-right::before { content: "\f12b"; } -.bi-arrow-left-short::before { content: "\f12c"; } -.bi-arrow-left-square-fill::before { content: "\f12d"; } -.bi-arrow-left-square::before { content: "\f12e"; } -.bi-arrow-left::before { content: "\f12f"; } -.bi-arrow-repeat::before { content: "\f130"; } -.bi-arrow-return-left::before { content: "\f131"; } -.bi-arrow-return-right::before { content: "\f132"; } -.bi-arrow-right-circle-fill::before { content: "\f133"; } -.bi-arrow-right-circle::before { content: "\f134"; } -.bi-arrow-right-short::before { content: "\f135"; } -.bi-arrow-right-square-fill::before { content: "\f136"; } -.bi-arrow-right-square::before { content: "\f137"; } -.bi-arrow-right::before { content: "\f138"; } -.bi-arrow-up-circle-fill::before { content: "\f139"; } -.bi-arrow-up-circle::before { content: "\f13a"; } -.bi-arrow-up-left-circle-fill::before { content: "\f13b"; } -.bi-arrow-up-left-circle::before { content: "\f13c"; } -.bi-arrow-up-left-square-fill::before { content: "\f13d"; } -.bi-arrow-up-left-square::before { content: "\f13e"; } -.bi-arrow-up-left::before { content: "\f13f"; } -.bi-arrow-up-right-circle-fill::before { content: "\f140"; } -.bi-arrow-up-right-circle::before { content: "\f141"; } -.bi-arrow-up-right-square-fill::before { content: "\f142"; } -.bi-arrow-up-right-square::before { content: "\f143"; } -.bi-arrow-up-right::before { content: "\f144"; } -.bi-arrow-up-short::before { content: "\f145"; } -.bi-arrow-up-square-fill::before { content: "\f146"; } -.bi-arrow-up-square::before { content: "\f147"; } -.bi-arrow-up::before { content: "\f148"; } -.bi-arrows-angle-contract::before { content: "\f149"; } -.bi-arrows-angle-expand::before { content: "\f14a"; } -.bi-arrows-collapse::before { content: "\f14b"; } -.bi-arrows-expand::before { content: "\f14c"; } -.bi-arrows-fullscreen::before { content: "\f14d"; } -.bi-arrows-move::before { content: "\f14e"; } -.bi-aspect-ratio-fill::before { content: "\f14f"; } -.bi-aspect-ratio::before { content: "\f150"; } -.bi-asterisk::before { content: "\f151"; } -.bi-at::before { content: "\f152"; } -.bi-award-fill::before { content: "\f153"; } -.bi-award::before { content: "\f154"; } -.bi-back::before { content: "\f155"; } -.bi-backspace-fill::before { content: "\f156"; } -.bi-backspace-reverse-fill::before { content: "\f157"; } -.bi-backspace-reverse::before { content: "\f158"; } -.bi-backspace::before { content: "\f159"; } -.bi-badge-3d-fill::before { content: "\f15a"; } -.bi-badge-3d::before { content: "\f15b"; } -.bi-badge-4k-fill::before { content: "\f15c"; } -.bi-badge-4k::before { content: "\f15d"; } -.bi-badge-8k-fill::before { content: "\f15e"; } -.bi-badge-8k::before { content: "\f15f"; } -.bi-badge-ad-fill::before { content: "\f160"; } -.bi-badge-ad::before { content: "\f161"; } -.bi-badge-ar-fill::before { content: "\f162"; } -.bi-badge-ar::before { content: "\f163"; } -.bi-badge-cc-fill::before { content: "\f164"; } -.bi-badge-cc::before { content: "\f165"; } -.bi-badge-hd-fill::before { content: "\f166"; } -.bi-badge-hd::before { content: "\f167"; } -.bi-badge-tm-fill::before { content: "\f168"; } -.bi-badge-tm::before { content: "\f169"; } -.bi-badge-vo-fill::before { content: "\f16a"; } -.bi-badge-vo::before { content: "\f16b"; } -.bi-badge-vr-fill::before { content: "\f16c"; } -.bi-badge-vr::before { content: "\f16d"; } -.bi-badge-wc-fill::before { content: "\f16e"; } -.bi-badge-wc::before { content: "\f16f"; } -.bi-bag-check-fill::before { content: "\f170"; } -.bi-bag-check::before { content: "\f171"; } -.bi-bag-dash-fill::before { content: "\f172"; } -.bi-bag-dash::before { content: "\f173"; } -.bi-bag-fill::before { content: "\f174"; } -.bi-bag-plus-fill::before { content: "\f175"; } -.bi-bag-plus::before { content: "\f176"; } -.bi-bag-x-fill::before { content: "\f177"; } -.bi-bag-x::before { content: "\f178"; } -.bi-bag::before { content: "\f179"; } -.bi-bar-chart-fill::before { content: "\f17a"; } -.bi-bar-chart-line-fill::before { content: "\f17b"; } -.bi-bar-chart-line::before { content: "\f17c"; } -.bi-bar-chart-steps::before { content: "\f17d"; } -.bi-bar-chart::before { content: "\f17e"; } -.bi-basket-fill::before { content: "\f17f"; } -.bi-basket::before { content: "\f180"; } -.bi-basket2-fill::before { content: "\f181"; } -.bi-basket2::before { content: "\f182"; } -.bi-basket3-fill::before { content: "\f183"; } -.bi-basket3::before { content: "\f184"; } -.bi-battery-charging::before { content: "\f185"; } -.bi-battery-full::before { content: "\f186"; } -.bi-battery-half::before { content: "\f187"; } -.bi-battery::before { content: "\f188"; } -.bi-bell-fill::before { content: "\f189"; } -.bi-bell::before { content: "\f18a"; } -.bi-bezier::before { content: "\f18b"; } -.bi-bezier2::before { content: "\f18c"; } -.bi-bicycle::before { content: "\f18d"; } -.bi-binoculars-fill::before { content: "\f18e"; } -.bi-binoculars::before { content: "\f18f"; } -.bi-blockquote-left::before { content: "\f190"; } -.bi-blockquote-right::before { content: "\f191"; } -.bi-book-fill::before { content: "\f192"; } -.bi-book-half::before { content: "\f193"; } -.bi-book::before { content: "\f194"; } -.bi-bookmark-check-fill::before { content: "\f195"; } -.bi-bookmark-check::before { content: "\f196"; } -.bi-bookmark-dash-fill::before { content: "\f197"; } -.bi-bookmark-dash::before { content: "\f198"; } -.bi-bookmark-fill::before { content: "\f199"; } -.bi-bookmark-heart-fill::before { content: "\f19a"; } -.bi-bookmark-heart::before { content: "\f19b"; } -.bi-bookmark-plus-fill::before { content: "\f19c"; } -.bi-bookmark-plus::before { content: "\f19d"; } -.bi-bookmark-star-fill::before { content: "\f19e"; } -.bi-bookmark-star::before { content: "\f19f"; } -.bi-bookmark-x-fill::before { content: "\f1a0"; } -.bi-bookmark-x::before { content: "\f1a1"; } -.bi-bookmark::before { content: "\f1a2"; } -.bi-bookmarks-fill::before { content: "\f1a3"; } -.bi-bookmarks::before { content: "\f1a4"; } -.bi-bookshelf::before { content: "\f1a5"; } -.bi-bootstrap-fill::before { content: "\f1a6"; } -.bi-bootstrap-reboot::before { content: "\f1a7"; } -.bi-bootstrap::before { content: "\f1a8"; } -.bi-border-all::before { content: "\f1a9"; } -.bi-border-bottom::before { content: "\f1aa"; } -.bi-border-center::before { content: "\f1ab"; } -.bi-border-inner::before { content: "\f1ac"; } -.bi-border-left::before { content: "\f1ad"; } -.bi-border-middle::before { content: "\f1ae"; } -.bi-border-outer::before { content: "\f1af"; } -.bi-border-right::before { content: "\f1b0"; } -.bi-border-style::before { content: "\f1b1"; } -.bi-border-top::before { content: "\f1b2"; } -.bi-border-width::before { content: "\f1b3"; } -.bi-border::before { content: "\f1b4"; } -.bi-bounding-box-circles::before { content: "\f1b5"; } -.bi-bounding-box::before { content: "\f1b6"; } -.bi-box-arrow-down-left::before { content: "\f1b7"; } -.bi-box-arrow-down-right::before { content: "\f1b8"; } -.bi-box-arrow-down::before { content: "\f1b9"; } -.bi-box-arrow-in-down-left::before { content: "\f1ba"; } -.bi-box-arrow-in-down-right::before { content: "\f1bb"; } -.bi-box-arrow-in-down::before { content: "\f1bc"; } -.bi-box-arrow-in-left::before { content: "\f1bd"; } -.bi-box-arrow-in-right::before { content: "\f1be"; } -.bi-box-arrow-in-up-left::before { content: "\f1bf"; } -.bi-box-arrow-in-up-right::before { content: "\f1c0"; } -.bi-box-arrow-in-up::before { content: "\f1c1"; } -.bi-box-arrow-left::before { content: "\f1c2"; } -.bi-box-arrow-right::before { content: "\f1c3"; } -.bi-box-arrow-up-left::before { content: "\f1c4"; } -.bi-box-arrow-up-right::before { content: "\f1c5"; } -.bi-box-arrow-up::before { content: "\f1c6"; } -.bi-box-seam::before { content: "\f1c7"; } -.bi-box::before { content: "\f1c8"; } -.bi-braces::before { content: "\f1c9"; } -.bi-bricks::before { content: "\f1ca"; } -.bi-briefcase-fill::before { content: "\f1cb"; } -.bi-briefcase::before { content: "\f1cc"; } -.bi-brightness-alt-high-fill::before { content: "\f1cd"; } -.bi-brightness-alt-high::before { content: "\f1ce"; } -.bi-brightness-alt-low-fill::before { content: "\f1cf"; } -.bi-brightness-alt-low::before { content: "\f1d0"; } -.bi-brightness-high-fill::before { content: "\f1d1"; } -.bi-brightness-high::before { content: "\f1d2"; } -.bi-brightness-low-fill::before { content: "\f1d3"; } -.bi-brightness-low::before { content: "\f1d4"; } -.bi-broadcast-pin::before { content: "\f1d5"; } -.bi-broadcast::before { content: "\f1d6"; } -.bi-brush-fill::before { content: "\f1d7"; } -.bi-brush::before { content: "\f1d8"; } -.bi-bucket-fill::before { content: "\f1d9"; } -.bi-bucket::before { content: "\f1da"; } -.bi-bug-fill::before { content: "\f1db"; } -.bi-bug::before { content: "\f1dc"; } -.bi-building::before { content: "\f1dd"; } -.bi-bullseye::before { content: "\f1de"; } -.bi-calculator-fill::before { content: "\f1df"; } -.bi-calculator::before { content: "\f1e0"; } -.bi-calendar-check-fill::before { content: "\f1e1"; } -.bi-calendar-check::before { content: "\f1e2"; } -.bi-calendar-date-fill::before { content: "\f1e3"; } -.bi-calendar-date::before { content: "\f1e4"; } -.bi-calendar-day-fill::before { content: "\f1e5"; } -.bi-calendar-day::before { content: "\f1e6"; } -.bi-calendar-event-fill::before { content: "\f1e7"; } -.bi-calendar-event::before { content: "\f1e8"; } -.bi-calendar-fill::before { content: "\f1e9"; } -.bi-calendar-minus-fill::before { content: "\f1ea"; } -.bi-calendar-minus::before { content: "\f1eb"; } -.bi-calendar-month-fill::before { content: "\f1ec"; } -.bi-calendar-month::before { content: "\f1ed"; } -.bi-calendar-plus-fill::before { content: "\f1ee"; } -.bi-calendar-plus::before { content: "\f1ef"; } -.bi-calendar-range-fill::before { content: "\f1f0"; } -.bi-calendar-range::before { content: "\f1f1"; } -.bi-calendar-week-fill::before { content: "\f1f2"; } -.bi-calendar-week::before { content: "\f1f3"; } -.bi-calendar-x-fill::before { content: "\f1f4"; } -.bi-calendar-x::before { content: "\f1f5"; } -.bi-calendar::before { content: "\f1f6"; } -.bi-calendar2-check-fill::before { content: "\f1f7"; } -.bi-calendar2-check::before { content: "\f1f8"; } -.bi-calendar2-date-fill::before { content: "\f1f9"; } -.bi-calendar2-date::before { content: "\f1fa"; } -.bi-calendar2-day-fill::before { content: "\f1fb"; } -.bi-calendar2-day::before { content: "\f1fc"; } -.bi-calendar2-event-fill::before { content: "\f1fd"; } -.bi-calendar2-event::before { content: "\f1fe"; } -.bi-calendar2-fill::before { content: "\f1ff"; } -.bi-calendar2-minus-fill::before { content: "\f200"; } -.bi-calendar2-minus::before { content: "\f201"; } -.bi-calendar2-month-fill::before { content: "\f202"; } -.bi-calendar2-month::before { content: "\f203"; } -.bi-calendar2-plus-fill::before { content: "\f204"; } -.bi-calendar2-plus::before { content: "\f205"; } -.bi-calendar2-range-fill::before { content: "\f206"; } -.bi-calendar2-range::before { content: "\f207"; } -.bi-calendar2-week-fill::before { content: "\f208"; } -.bi-calendar2-week::before { content: "\f209"; } -.bi-calendar2-x-fill::before { content: "\f20a"; } -.bi-calendar2-x::before { content: "\f20b"; } -.bi-calendar2::before { content: "\f20c"; } -.bi-calendar3-event-fill::before { content: "\f20d"; } -.bi-calendar3-event::before { content: "\f20e"; } -.bi-calendar3-fill::before { content: "\f20f"; } -.bi-calendar3-range-fill::before { content: "\f210"; } -.bi-calendar3-range::before { content: "\f211"; } -.bi-calendar3-week-fill::before { content: "\f212"; } -.bi-calendar3-week::before { content: "\f213"; } -.bi-calendar3::before { content: "\f214"; } -.bi-calendar4-event::before { content: "\f215"; } -.bi-calendar4-range::before { content: "\f216"; } -.bi-calendar4-week::before { content: "\f217"; } -.bi-calendar4::before { content: "\f218"; } -.bi-camera-fill::before { content: "\f219"; } -.bi-camera-reels-fill::before { content: "\f21a"; } -.bi-camera-reels::before { content: "\f21b"; } -.bi-camera-video-fill::before { content: "\f21c"; } -.bi-camera-video-off-fill::before { content: "\f21d"; } -.bi-camera-video-off::before { content: "\f21e"; } -.bi-camera-video::before { content: "\f21f"; } -.bi-camera::before { content: "\f220"; } -.bi-camera2::before { content: "\f221"; } -.bi-capslock-fill::before { content: "\f222"; } -.bi-capslock::before { content: "\f223"; } -.bi-card-checklist::before { content: "\f224"; } -.bi-card-heading::before { content: "\f225"; } -.bi-card-image::before { content: "\f226"; } -.bi-card-list::before { content: "\f227"; } -.bi-card-text::before { content: "\f228"; } -.bi-caret-down-fill::before { content: "\f229"; } -.bi-caret-down-square-fill::before { content: "\f22a"; } -.bi-caret-down-square::before { content: "\f22b"; } -.bi-caret-down::before { content: "\f22c"; } -.bi-caret-left-fill::before { content: "\f22d"; } -.bi-caret-left-square-fill::before { content: "\f22e"; } -.bi-caret-left-square::before { content: "\f22f"; } -.bi-caret-left::before { content: "\f230"; } -.bi-caret-right-fill::before { content: "\f231"; } -.bi-caret-right-square-fill::before { content: "\f232"; } -.bi-caret-right-square::before { content: "\f233"; } -.bi-caret-right::before { content: "\f234"; } -.bi-caret-up-fill::before { content: "\f235"; } -.bi-caret-up-square-fill::before { content: "\f236"; } -.bi-caret-up-square::before { content: "\f237"; } -.bi-caret-up::before { content: "\f238"; } -.bi-cart-check-fill::before { content: "\f239"; } -.bi-cart-check::before { content: "\f23a"; } -.bi-cart-dash-fill::before { content: "\f23b"; } -.bi-cart-dash::before { content: "\f23c"; } -.bi-cart-fill::before { content: "\f23d"; } -.bi-cart-plus-fill::before { content: "\f23e"; } -.bi-cart-plus::before { content: "\f23f"; } -.bi-cart-x-fill::before { content: "\f240"; } -.bi-cart-x::before { content: "\f241"; } -.bi-cart::before { content: "\f242"; } -.bi-cart2::before { content: "\f243"; } -.bi-cart3::before { content: "\f244"; } -.bi-cart4::before { content: "\f245"; } -.bi-cash-stack::before { content: "\f246"; } -.bi-cash::before { content: "\f247"; } -.bi-cast::before { content: "\f248"; } -.bi-chat-dots-fill::before { content: "\f249"; } -.bi-chat-dots::before { content: "\f24a"; } -.bi-chat-fill::before { content: "\f24b"; } -.bi-chat-left-dots-fill::before { content: "\f24c"; } -.bi-chat-left-dots::before { content: "\f24d"; } -.bi-chat-left-fill::before { content: "\f24e"; } -.bi-chat-left-quote-fill::before { content: "\f24f"; } -.bi-chat-left-quote::before { content: "\f250"; } -.bi-chat-left-text-fill::before { content: "\f251"; } -.bi-chat-left-text::before { content: "\f252"; } -.bi-chat-left::before { content: "\f253"; } -.bi-chat-quote-fill::before { content: "\f254"; } -.bi-chat-quote::before { content: "\f255"; } -.bi-chat-right-dots-fill::before { content: "\f256"; } -.bi-chat-right-dots::before { content: "\f257"; } -.bi-chat-right-fill::before { content: "\f258"; } -.bi-chat-right-quote-fill::before { content: "\f259"; } -.bi-chat-right-quote::before { content: "\f25a"; } -.bi-chat-right-text-fill::before { content: "\f25b"; } -.bi-chat-right-text::before { content: "\f25c"; } -.bi-chat-right::before { content: "\f25d"; } -.bi-chat-square-dots-fill::before { content: "\f25e"; } -.bi-chat-square-dots::before { content: "\f25f"; } -.bi-chat-square-fill::before { content: "\f260"; } -.bi-chat-square-quote-fill::before { content: "\f261"; } -.bi-chat-square-quote::before { content: "\f262"; } -.bi-chat-square-text-fill::before { content: "\f263"; } -.bi-chat-square-text::before { content: "\f264"; } -.bi-chat-square::before { content: "\f265"; } -.bi-chat-text-fill::before { content: "\f266"; } -.bi-chat-text::before { content: "\f267"; } -.bi-chat::before { content: "\f268"; } -.bi-check-all::before { content: "\f269"; } -.bi-check-circle-fill::before { content: "\f26a"; } -.bi-check-circle::before { content: "\f26b"; } -.bi-check-square-fill::before { content: "\f26c"; } -.bi-check-square::before { content: "\f26d"; } -.bi-check::before { content: "\f26e"; } -.bi-check2-all::before { content: "\f26f"; } -.bi-check2-circle::before { content: "\f270"; } -.bi-check2-square::before { content: "\f271"; } -.bi-check2::before { content: "\f272"; } -.bi-chevron-bar-contract::before { content: "\f273"; } -.bi-chevron-bar-down::before { content: "\f274"; } -.bi-chevron-bar-expand::before { content: "\f275"; } -.bi-chevron-bar-left::before { content: "\f276"; } -.bi-chevron-bar-right::before { content: "\f277"; } -.bi-chevron-bar-up::before { content: "\f278"; } -.bi-chevron-compact-down::before { content: "\f279"; } -.bi-chevron-compact-left::before { content: "\f27a"; } -.bi-chevron-compact-right::before { content: "\f27b"; } -.bi-chevron-compact-up::before { content: "\f27c"; } -.bi-chevron-contract::before { content: "\f27d"; } -.bi-chevron-double-down::before { content: "\f27e"; } -.bi-chevron-double-left::before { content: "\f27f"; } -.bi-chevron-double-right::before { content: "\f280"; } -.bi-chevron-double-up::before { content: "\f281"; } -.bi-chevron-down::before { content: "\f282"; } -.bi-chevron-expand::before { content: "\f283"; } -.bi-chevron-left::before { content: "\f284"; } -.bi-chevron-right::before { content: "\f285"; } -.bi-chevron-up::before { content: "\f286"; } -.bi-circle-fill::before { content: "\f287"; } -.bi-circle-half::before { content: "\f288"; } -.bi-circle-square::before { content: "\f289"; } -.bi-circle::before { content: "\f28a"; } -.bi-clipboard-check::before { content: "\f28b"; } -.bi-clipboard-data::before { content: "\f28c"; } -.bi-clipboard-minus::before { content: "\f28d"; } -.bi-clipboard-plus::before { content: "\f28e"; } -.bi-clipboard-x::before { content: "\f28f"; } -.bi-clipboard::before { content: "\f290"; } -.bi-clock-fill::before { content: "\f291"; } -.bi-clock-history::before { content: "\f292"; } -.bi-clock::before { content: "\f293"; } -.bi-cloud-arrow-down-fill::before { content: "\f294"; } -.bi-cloud-arrow-down::before { content: "\f295"; } -.bi-cloud-arrow-up-fill::before { content: "\f296"; } -.bi-cloud-arrow-up::before { content: "\f297"; } -.bi-cloud-check-fill::before { content: "\f298"; } -.bi-cloud-check::before { content: "\f299"; } -.bi-cloud-download-fill::before { content: "\f29a"; } -.bi-cloud-download::before { content: "\f29b"; } -.bi-cloud-drizzle-fill::before { content: "\f29c"; } -.bi-cloud-drizzle::before { content: "\f29d"; } -.bi-cloud-fill::before { content: "\f29e"; } -.bi-cloud-fog-fill::before { content: "\f29f"; } -.bi-cloud-fog::before { content: "\f2a0"; } -.bi-cloud-fog2-fill::before { content: "\f2a1"; } -.bi-cloud-fog2::before { content: "\f2a2"; } -.bi-cloud-hail-fill::before { content: "\f2a3"; } -.bi-cloud-hail::before { content: "\f2a4"; } -.bi-cloud-haze-fill::before { content: "\f2a6"; } -.bi-cloud-haze::before { content: "\f2a7"; } -.bi-cloud-haze2-fill::before { content: "\f2a8"; } -.bi-cloud-lightning-fill::before { content: "\f2a9"; } -.bi-cloud-lightning-rain-fill::before { content: "\f2aa"; } -.bi-cloud-lightning-rain::before { content: "\f2ab"; } -.bi-cloud-lightning::before { content: "\f2ac"; } -.bi-cloud-minus-fill::before { content: "\f2ad"; } -.bi-cloud-minus::before { content: "\f2ae"; } -.bi-cloud-moon-fill::before { content: "\f2af"; } -.bi-cloud-moon::before { content: "\f2b0"; } -.bi-cloud-plus-fill::before { content: "\f2b1"; } -.bi-cloud-plus::before { content: "\f2b2"; } -.bi-cloud-rain-fill::before { content: "\f2b3"; } -.bi-cloud-rain-heavy-fill::before { content: "\f2b4"; } -.bi-cloud-rain-heavy::before { content: "\f2b5"; } -.bi-cloud-rain::before { content: "\f2b6"; } -.bi-cloud-slash-fill::before { content: "\f2b7"; } -.bi-cloud-slash::before { content: "\f2b8"; } -.bi-cloud-sleet-fill::before { content: "\f2b9"; } -.bi-cloud-sleet::before { content: "\f2ba"; } -.bi-cloud-snow-fill::before { content: "\f2bb"; } -.bi-cloud-snow::before { content: "\f2bc"; } -.bi-cloud-sun-fill::before { content: "\f2bd"; } -.bi-cloud-sun::before { content: "\f2be"; } -.bi-cloud-upload-fill::before { content: "\f2bf"; } -.bi-cloud-upload::before { content: "\f2c0"; } -.bi-cloud::before { content: "\f2c1"; } -.bi-clouds-fill::before { content: "\f2c2"; } -.bi-clouds::before { content: "\f2c3"; } -.bi-cloudy-fill::before { content: "\f2c4"; } -.bi-cloudy::before { content: "\f2c5"; } -.bi-code-slash::before { content: "\f2c6"; } -.bi-code-square::before { content: "\f2c7"; } -.bi-code::before { content: "\f2c8"; } -.bi-collection-fill::before { content: "\f2c9"; } -.bi-collection-play-fill::before { content: "\f2ca"; } -.bi-collection-play::before { content: "\f2cb"; } -.bi-collection::before { content: "\f2cc"; } -.bi-columns-gap::before { content: "\f2cd"; } -.bi-columns::before { content: "\f2ce"; } -.bi-command::before { content: "\f2cf"; } -.bi-compass-fill::before { content: "\f2d0"; } -.bi-compass::before { content: "\f2d1"; } -.bi-cone-striped::before { content: "\f2d2"; } -.bi-cone::before { content: "\f2d3"; } -.bi-controller::before { content: "\f2d4"; } -.bi-cpu-fill::before { content: "\f2d5"; } -.bi-cpu::before { content: "\f2d6"; } -.bi-credit-card-2-back-fill::before { content: "\f2d7"; } -.bi-credit-card-2-back::before { content: "\f2d8"; } -.bi-credit-card-2-front-fill::before { content: "\f2d9"; } -.bi-credit-card-2-front::before { content: "\f2da"; } -.bi-credit-card-fill::before { content: "\f2db"; } -.bi-credit-card::before { content: "\f2dc"; } -.bi-crop::before { content: "\f2dd"; } -.bi-cup-fill::before { content: "\f2de"; } -.bi-cup-straw::before { content: "\f2df"; } -.bi-cup::before { content: "\f2e0"; } -.bi-cursor-fill::before { content: "\f2e1"; } -.bi-cursor-text::before { content: "\f2e2"; } -.bi-cursor::before { content: "\f2e3"; } -.bi-dash-circle-dotted::before { content: "\f2e4"; } -.bi-dash-circle-fill::before { content: "\f2e5"; } -.bi-dash-circle::before { content: "\f2e6"; } -.bi-dash-square-dotted::before { content: "\f2e7"; } -.bi-dash-square-fill::before { content: "\f2e8"; } -.bi-dash-square::before { content: "\f2e9"; } -.bi-dash::before { content: "\f2ea"; } -.bi-diagram-2-fill::before { content: "\f2eb"; } -.bi-diagram-2::before { content: "\f2ec"; } -.bi-diagram-3-fill::before { content: "\f2ed"; } -.bi-diagram-3::before { content: "\f2ee"; } -.bi-diamond-fill::before { content: "\f2ef"; } -.bi-diamond-half::before { content: "\f2f0"; } -.bi-diamond::before { content: "\f2f1"; } -.bi-dice-1-fill::before { content: "\f2f2"; } -.bi-dice-1::before { content: "\f2f3"; } -.bi-dice-2-fill::before { content: "\f2f4"; } -.bi-dice-2::before { content: "\f2f5"; } -.bi-dice-3-fill::before { content: "\f2f6"; } -.bi-dice-3::before { content: "\f2f7"; } -.bi-dice-4-fill::before { content: "\f2f8"; } -.bi-dice-4::before { content: "\f2f9"; } -.bi-dice-5-fill::before { content: "\f2fa"; } -.bi-dice-5::before { content: "\f2fb"; } -.bi-dice-6-fill::before { content: "\f2fc"; } -.bi-dice-6::before { content: "\f2fd"; } -.bi-disc-fill::before { content: "\f2fe"; } -.bi-disc::before { content: "\f2ff"; } -.bi-discord::before { content: "\f300"; } -.bi-display-fill::before { content: "\f301"; } -.bi-display::before { content: "\f302"; } -.bi-distribute-horizontal::before { content: "\f303"; } -.bi-distribute-vertical::before { content: "\f304"; } -.bi-door-closed-fill::before { content: "\f305"; } -.bi-door-closed::before { content: "\f306"; } -.bi-door-open-fill::before { content: "\f307"; } -.bi-door-open::before { content: "\f308"; } -.bi-dot::before { content: "\f309"; } -.bi-download::before { content: "\f30a"; } -.bi-droplet-fill::before { content: "\f30b"; } -.bi-droplet-half::before { content: "\f30c"; } -.bi-droplet::before { content: "\f30d"; } -.bi-earbuds::before { content: "\f30e"; } -.bi-easel-fill::before { content: "\f30f"; } -.bi-easel::before { content: "\f310"; } -.bi-egg-fill::before { content: "\f311"; } -.bi-egg-fried::before { content: "\f312"; } -.bi-egg::before { content: "\f313"; } -.bi-eject-fill::before { content: "\f314"; } -.bi-eject::before { content: "\f315"; } -.bi-emoji-angry-fill::before { content: "\f316"; } -.bi-emoji-angry::before { content: "\f317"; } -.bi-emoji-dizzy-fill::before { content: "\f318"; } -.bi-emoji-dizzy::before { content: "\f319"; } -.bi-emoji-expressionless-fill::before { content: "\f31a"; } -.bi-emoji-expressionless::before { content: "\f31b"; } -.bi-emoji-frown-fill::before { content: "\f31c"; } -.bi-emoji-frown::before { content: "\f31d"; } -.bi-emoji-heart-eyes-fill::before { content: "\f31e"; } -.bi-emoji-heart-eyes::before { content: "\f31f"; } -.bi-emoji-laughing-fill::before { content: "\f320"; } -.bi-emoji-laughing::before { content: "\f321"; } -.bi-emoji-neutral-fill::before { content: "\f322"; } -.bi-emoji-neutral::before { content: "\f323"; } -.bi-emoji-smile-fill::before { content: "\f324"; } -.bi-emoji-smile-upside-down-fill::before { content: "\f325"; } -.bi-emoji-smile-upside-down::before { content: "\f326"; } -.bi-emoji-smile::before { content: "\f327"; } -.bi-emoji-sunglasses-fill::before { content: "\f328"; } -.bi-emoji-sunglasses::before { content: "\f329"; } -.bi-emoji-wink-fill::before { content: "\f32a"; } -.bi-emoji-wink::before { content: "\f32b"; } -.bi-envelope-fill::before { content: "\f32c"; } -.bi-envelope-open-fill::before { content: "\f32d"; } -.bi-envelope-open::before { content: "\f32e"; } -.bi-envelope::before { content: "\f32f"; } -.bi-eraser-fill::before { content: "\f330"; } -.bi-eraser::before { content: "\f331"; } -.bi-exclamation-circle-fill::before { content: "\f332"; } -.bi-exclamation-circle::before { content: "\f333"; } -.bi-exclamation-diamond-fill::before { content: "\f334"; } -.bi-exclamation-diamond::before { content: "\f335"; } -.bi-exclamation-octagon-fill::before { content: "\f336"; } -.bi-exclamation-octagon::before { content: "\f337"; } -.bi-exclamation-square-fill::before { content: "\f338"; } -.bi-exclamation-square::before { content: "\f339"; } -.bi-exclamation-triangle-fill::before { content: "\f33a"; } -.bi-exclamation-triangle::before { content: "\f33b"; } -.bi-exclamation::before { content: "\f33c"; } -.bi-exclude::before { content: "\f33d"; } -.bi-eye-fill::before { content: "\f33e"; } -.bi-eye-slash-fill::before { content: "\f33f"; } -.bi-eye-slash::before { content: "\f340"; } -.bi-eye::before { content: "\f341"; } -.bi-eyedropper::before { content: "\f342"; } -.bi-eyeglasses::before { content: "\f343"; } -.bi-facebook::before { content: "\f344"; } -.bi-file-arrow-down-fill::before { content: "\f345"; } -.bi-file-arrow-down::before { content: "\f346"; } -.bi-file-arrow-up-fill::before { content: "\f347"; } -.bi-file-arrow-up::before { content: "\f348"; } -.bi-file-bar-graph-fill::before { content: "\f349"; } -.bi-file-bar-graph::before { content: "\f34a"; } -.bi-file-binary-fill::before { content: "\f34b"; } -.bi-file-binary::before { content: "\f34c"; } -.bi-file-break-fill::before { content: "\f34d"; } -.bi-file-break::before { content: "\f34e"; } -.bi-file-check-fill::before { content: "\f34f"; } -.bi-file-check::before { content: "\f350"; } -.bi-file-code-fill::before { content: "\f351"; } -.bi-file-code::before { content: "\f352"; } -.bi-file-diff-fill::before { content: "\f353"; } -.bi-file-diff::before { content: "\f354"; } -.bi-file-earmark-arrow-down-fill::before { content: "\f355"; } -.bi-file-earmark-arrow-down::before { content: "\f356"; } -.bi-file-earmark-arrow-up-fill::before { content: "\f357"; } -.bi-file-earmark-arrow-up::before { content: "\f358"; } -.bi-file-earmark-bar-graph-fill::before { content: "\f359"; } -.bi-file-earmark-bar-graph::before { content: "\f35a"; } -.bi-file-earmark-binary-fill::before { content: "\f35b"; } -.bi-file-earmark-binary::before { content: "\f35c"; } -.bi-file-earmark-break-fill::before { content: "\f35d"; } -.bi-file-earmark-break::before { content: "\f35e"; } -.bi-file-earmark-check-fill::before { content: "\f35f"; } -.bi-file-earmark-check::before { content: "\f360"; } -.bi-file-earmark-code-fill::before { content: "\f361"; } -.bi-file-earmark-code::before { content: "\f362"; } -.bi-file-earmark-diff-fill::before { content: "\f363"; } -.bi-file-earmark-diff::before { content: "\f364"; } -.bi-file-earmark-easel-fill::before { content: "\f365"; } -.bi-file-earmark-easel::before { content: "\f366"; } -.bi-file-earmark-excel-fill::before { content: "\f367"; } -.bi-file-earmark-excel::before { content: "\f368"; } -.bi-file-earmark-fill::before { content: "\f369"; } -.bi-file-earmark-font-fill::before { content: "\f36a"; } -.bi-file-earmark-font::before { content: "\f36b"; } -.bi-file-earmark-image-fill::before { content: "\f36c"; } -.bi-file-earmark-image::before { content: "\f36d"; } -.bi-file-earmark-lock-fill::before { content: "\f36e"; } -.bi-file-earmark-lock::before { content: "\f36f"; } -.bi-file-earmark-lock2-fill::before { content: "\f370"; } -.bi-file-earmark-lock2::before { content: "\f371"; } -.bi-file-earmark-medical-fill::before { content: "\f372"; } -.bi-file-earmark-medical::before { content: "\f373"; } -.bi-file-earmark-minus-fill::before { content: "\f374"; } -.bi-file-earmark-minus::before { content: "\f375"; } -.bi-file-earmark-music-fill::before { content: "\f376"; } -.bi-file-earmark-music::before { content: "\f377"; } -.bi-file-earmark-person-fill::before { content: "\f378"; } -.bi-file-earmark-person::before { content: "\f379"; } -.bi-file-earmark-play-fill::before { content: "\f37a"; } -.bi-file-earmark-play::before { content: "\f37b"; } -.bi-file-earmark-plus-fill::before { content: "\f37c"; } -.bi-file-earmark-plus::before { content: "\f37d"; } -.bi-file-earmark-post-fill::before { content: "\f37e"; } -.bi-file-earmark-post::before { content: "\f37f"; } -.bi-file-earmark-ppt-fill::before { content: "\f380"; } -.bi-file-earmark-ppt::before { content: "\f381"; } -.bi-file-earmark-richtext-fill::before { content: "\f382"; } -.bi-file-earmark-richtext::before { content: "\f383"; } -.bi-file-earmark-ruled-fill::before { content: "\f384"; } -.bi-file-earmark-ruled::before { content: "\f385"; } -.bi-file-earmark-slides-fill::before { content: "\f386"; } -.bi-file-earmark-slides::before { content: "\f387"; } -.bi-file-earmark-spreadsheet-fill::before { content: "\f388"; } -.bi-file-earmark-spreadsheet::before { content: "\f389"; } -.bi-file-earmark-text-fill::before { content: "\f38a"; } -.bi-file-earmark-text::before { content: "\f38b"; } -.bi-file-earmark-word-fill::before { content: "\f38c"; } -.bi-file-earmark-word::before { content: "\f38d"; } -.bi-file-earmark-x-fill::before { content: "\f38e"; } -.bi-file-earmark-x::before { content: "\f38f"; } -.bi-file-earmark-zip-fill::before { content: "\f390"; } -.bi-file-earmark-zip::before { content: "\f391"; } -.bi-file-earmark::before { content: "\f392"; } -.bi-file-easel-fill::before { content: "\f393"; } -.bi-file-easel::before { content: "\f394"; } -.bi-file-excel-fill::before { content: "\f395"; } -.bi-file-excel::before { content: "\f396"; } -.bi-file-fill::before { content: "\f397"; } -.bi-file-font-fill::before { content: "\f398"; } -.bi-file-font::before { content: "\f399"; } -.bi-file-image-fill::before { content: "\f39a"; } -.bi-file-image::before { content: "\f39b"; } -.bi-file-lock-fill::before { content: "\f39c"; } -.bi-file-lock::before { content: "\f39d"; } -.bi-file-lock2-fill::before { content: "\f39e"; } -.bi-file-lock2::before { content: "\f39f"; } -.bi-file-medical-fill::before { content: "\f3a0"; } -.bi-file-medical::before { content: "\f3a1"; } -.bi-file-minus-fill::before { content: "\f3a2"; } -.bi-file-minus::before { content: "\f3a3"; } -.bi-file-music-fill::before { content: "\f3a4"; } -.bi-file-music::before { content: "\f3a5"; } -.bi-file-person-fill::before { content: "\f3a6"; } -.bi-file-person::before { content: "\f3a7"; } -.bi-file-play-fill::before { content: "\f3a8"; } -.bi-file-play::before { content: "\f3a9"; } -.bi-file-plus-fill::before { content: "\f3aa"; } -.bi-file-plus::before { content: "\f3ab"; } -.bi-file-post-fill::before { content: "\f3ac"; } -.bi-file-post::before { content: "\f3ad"; } -.bi-file-ppt-fill::before { content: "\f3ae"; } -.bi-file-ppt::before { content: "\f3af"; } -.bi-file-richtext-fill::before { content: "\f3b0"; } -.bi-file-richtext::before { content: "\f3b1"; } -.bi-file-ruled-fill::before { content: "\f3b2"; } -.bi-file-ruled::before { content: "\f3b3"; } -.bi-file-slides-fill::before { content: "\f3b4"; } -.bi-file-slides::before { content: "\f3b5"; } -.bi-file-spreadsheet-fill::before { content: "\f3b6"; } -.bi-file-spreadsheet::before { content: "\f3b7"; } -.bi-file-text-fill::before { content: "\f3b8"; } -.bi-file-text::before { content: "\f3b9"; } -.bi-file-word-fill::before { content: "\f3ba"; } -.bi-file-word::before { content: "\f3bb"; } -.bi-file-x-fill::before { content: "\f3bc"; } -.bi-file-x::before { content: "\f3bd"; } -.bi-file-zip-fill::before { content: "\f3be"; } -.bi-file-zip::before { content: "\f3bf"; } -.bi-file::before { content: "\f3c0"; } -.bi-files-alt::before { content: "\f3c1"; } -.bi-files::before { content: "\f3c2"; } -.bi-film::before { content: "\f3c3"; } -.bi-filter-circle-fill::before { content: "\f3c4"; } -.bi-filter-circle::before { content: "\f3c5"; } -.bi-filter-left::before { content: "\f3c6"; } -.bi-filter-right::before { content: "\f3c7"; } -.bi-filter-square-fill::before { content: "\f3c8"; } -.bi-filter-square::before { content: "\f3c9"; } -.bi-filter::before { content: "\f3ca"; } -.bi-flag-fill::before { content: "\f3cb"; } -.bi-flag::before { content: "\f3cc"; } -.bi-flower1::before { content: "\f3cd"; } -.bi-flower2::before { content: "\f3ce"; } -.bi-flower3::before { content: "\f3cf"; } -.bi-folder-check::before { content: "\f3d0"; } -.bi-folder-fill::before { content: "\f3d1"; } -.bi-folder-minus::before { content: "\f3d2"; } -.bi-folder-plus::before { content: "\f3d3"; } -.bi-folder-symlink-fill::before { content: "\f3d4"; } -.bi-folder-symlink::before { content: "\f3d5"; } -.bi-folder-x::before { content: "\f3d6"; } -.bi-folder::before { content: "\f3d7"; } -.bi-folder2-open::before { content: "\f3d8"; } -.bi-folder2::before { content: "\f3d9"; } -.bi-fonts::before { content: "\f3da"; } -.bi-forward-fill::before { content: "\f3db"; } -.bi-forward::before { content: "\f3dc"; } -.bi-front::before { content: "\f3dd"; } -.bi-fullscreen-exit::before { content: "\f3de"; } -.bi-fullscreen::before { content: "\f3df"; } -.bi-funnel-fill::before { content: "\f3e0"; } -.bi-funnel::before { content: "\f3e1"; } -.bi-gear-fill::before { content: "\f3e2"; } -.bi-gear-wide-connected::before { content: "\f3e3"; } -.bi-gear-wide::before { content: "\f3e4"; } -.bi-gear::before { content: "\f3e5"; } -.bi-gem::before { content: "\f3e6"; } -.bi-geo-alt-fill::before { content: "\f3e7"; } -.bi-geo-alt::before { content: "\f3e8"; } -.bi-geo-fill::before { content: "\f3e9"; } -.bi-geo::before { content: "\f3ea"; } -.bi-gift-fill::before { content: "\f3eb"; } -.bi-gift::before { content: "\f3ec"; } -.bi-github::before { content: "\f3ed"; } -.bi-globe::before { content: "\f3ee"; } -.bi-globe2::before { content: "\f3ef"; } -.bi-google::before { content: "\f3f0"; } -.bi-graph-down::before { content: "\f3f1"; } -.bi-graph-up::before { content: "\f3f2"; } -.bi-grid-1x2-fill::before { content: "\f3f3"; } -.bi-grid-1x2::before { content: "\f3f4"; } -.bi-grid-3x2-gap-fill::before { content: "\f3f5"; } -.bi-grid-3x2-gap::before { content: "\f3f6"; } -.bi-grid-3x2::before { content: "\f3f7"; } -.bi-grid-3x3-gap-fill::before { content: "\f3f8"; } -.bi-grid-3x3-gap::before { content: "\f3f9"; } -.bi-grid-3x3::before { content: "\f3fa"; } -.bi-grid-fill::before { content: "\f3fb"; } -.bi-grid::before { content: "\f3fc"; } -.bi-grip-horizontal::before { content: "\f3fd"; } -.bi-grip-vertical::before { content: "\f3fe"; } -.bi-hammer::before { content: "\f3ff"; } -.bi-hand-index-fill::before { content: "\f400"; } -.bi-hand-index-thumb-fill::before { content: "\f401"; } -.bi-hand-index-thumb::before { content: "\f402"; } -.bi-hand-index::before { content: "\f403"; } -.bi-hand-thumbs-down-fill::before { content: "\f404"; } -.bi-hand-thumbs-down::before { content: "\f405"; } -.bi-hand-thumbs-up-fill::before { content: "\f406"; } -.bi-hand-thumbs-up::before { content: "\f407"; } -.bi-handbag-fill::before { content: "\f408"; } -.bi-handbag::before { content: "\f409"; } -.bi-hash::before { content: "\f40a"; } -.bi-hdd-fill::before { content: "\f40b"; } -.bi-hdd-network-fill::before { content: "\f40c"; } -.bi-hdd-network::before { content: "\f40d"; } -.bi-hdd-rack-fill::before { content: "\f40e"; } -.bi-hdd-rack::before { content: "\f40f"; } -.bi-hdd-stack-fill::before { content: "\f410"; } -.bi-hdd-stack::before { content: "\f411"; } -.bi-hdd::before { content: "\f412"; } -.bi-headphones::before { content: "\f413"; } -.bi-headset::before { content: "\f414"; } -.bi-heart-fill::before { content: "\f415"; } -.bi-heart-half::before { content: "\f416"; } -.bi-heart::before { content: "\f417"; } -.bi-heptagon-fill::before { content: "\f418"; } -.bi-heptagon-half::before { content: "\f419"; } -.bi-heptagon::before { content: "\f41a"; } -.bi-hexagon-fill::before { content: "\f41b"; } -.bi-hexagon-half::before { content: "\f41c"; } -.bi-hexagon::before { content: "\f41d"; } -.bi-hourglass-bottom::before { content: "\f41e"; } -.bi-hourglass-split::before { content: "\f41f"; } -.bi-hourglass-top::before { content: "\f420"; } -.bi-hourglass::before { content: "\f421"; } -.bi-house-door-fill::before { content: "\f422"; } -.bi-house-door::before { content: "\f423"; } -.bi-house-fill::before { content: "\f424"; } -.bi-house::before { content: "\f425"; } -.bi-hr::before { content: "\f426"; } -.bi-hurricane::before { content: "\f427"; } -.bi-image-alt::before { content: "\f428"; } -.bi-image-fill::before { content: "\f429"; } -.bi-image::before { content: "\f42a"; } -.bi-images::before { content: "\f42b"; } -.bi-inbox-fill::before { content: "\f42c"; } -.bi-inbox::before { content: "\f42d"; } -.bi-inboxes-fill::before { content: "\f42e"; } -.bi-inboxes::before { content: "\f42f"; } -.bi-info-circle-fill::before { content: "\f430"; } -.bi-info-circle::before { content: "\f431"; } -.bi-info-square-fill::before { content: "\f432"; } -.bi-info-square::before { content: "\f433"; } -.bi-info::before { content: "\f434"; } -.bi-input-cursor-text::before { content: "\f435"; } -.bi-input-cursor::before { content: "\f436"; } -.bi-instagram::before { content: "\f437"; } -.bi-intersect::before { content: "\f438"; } -.bi-journal-album::before { content: "\f439"; } -.bi-journal-arrow-down::before { content: "\f43a"; } -.bi-journal-arrow-up::before { content: "\f43b"; } -.bi-journal-bookmark-fill::before { content: "\f43c"; } -.bi-journal-bookmark::before { content: "\f43d"; } -.bi-journal-check::before { content: "\f43e"; } -.bi-journal-code::before { content: "\f43f"; } -.bi-journal-medical::before { content: "\f440"; } -.bi-journal-minus::before { content: "\f441"; } -.bi-journal-plus::before { content: "\f442"; } -.bi-journal-richtext::before { content: "\f443"; } -.bi-journal-text::before { content: "\f444"; } -.bi-journal-x::before { content: "\f445"; } -.bi-journal::before { content: "\f446"; } -.bi-journals::before { content: "\f447"; } -.bi-joystick::before { content: "\f448"; } -.bi-justify-left::before { content: "\f449"; } -.bi-justify-right::before { content: "\f44a"; } -.bi-justify::before { content: "\f44b"; } -.bi-kanban-fill::before { content: "\f44c"; } -.bi-kanban::before { content: "\f44d"; } -.bi-key-fill::before { content: "\f44e"; } -.bi-key::before { content: "\f44f"; } -.bi-keyboard-fill::before { content: "\f450"; } -.bi-keyboard::before { content: "\f451"; } -.bi-ladder::before { content: "\f452"; } -.bi-lamp-fill::before { content: "\f453"; } -.bi-lamp::before { content: "\f454"; } -.bi-laptop-fill::before { content: "\f455"; } -.bi-laptop::before { content: "\f456"; } -.bi-layer-backward::before { content: "\f457"; } -.bi-layer-forward::before { content: "\f458"; } -.bi-layers-fill::before { content: "\f459"; } -.bi-layers-half::before { content: "\f45a"; } -.bi-layers::before { content: "\f45b"; } -.bi-layout-sidebar-inset-reverse::before { content: "\f45c"; } -.bi-layout-sidebar-inset::before { content: "\f45d"; } -.bi-layout-sidebar-reverse::before { content: "\f45e"; } -.bi-layout-sidebar::before { content: "\f45f"; } -.bi-layout-split::before { content: "\f460"; } -.bi-layout-text-sidebar-reverse::before { content: "\f461"; } -.bi-layout-text-sidebar::before { content: "\f462"; } -.bi-layout-text-window-reverse::before { content: "\f463"; } -.bi-layout-text-window::before { content: "\f464"; } -.bi-layout-three-columns::before { content: "\f465"; } -.bi-layout-wtf::before { content: "\f466"; } -.bi-life-preserver::before { content: "\f467"; } -.bi-lightbulb-fill::before { content: "\f468"; } -.bi-lightbulb-off-fill::before { content: "\f469"; } -.bi-lightbulb-off::before { content: "\f46a"; } -.bi-lightbulb::before { content: "\f46b"; } -.bi-lightning-charge-fill::before { content: "\f46c"; } -.bi-lightning-charge::before { content: "\f46d"; } -.bi-lightning-fill::before { content: "\f46e"; } -.bi-lightning::before { content: "\f46f"; } -.bi-link-45deg::before { content: "\f470"; } -.bi-link::before { content: "\f471"; } -.bi-linkedin::before { content: "\f472"; } -.bi-list-check::before { content: "\f473"; } -.bi-list-nested::before { content: "\f474"; } -.bi-list-ol::before { content: "\f475"; } -.bi-list-stars::before { content: "\f476"; } -.bi-list-task::before { content: "\f477"; } -.bi-list-ul::before { content: "\f478"; } -.bi-list::before { content: "\f479"; } -.bi-lock-fill::before { content: "\f47a"; } -.bi-lock::before { content: "\f47b"; } -.bi-mailbox::before { content: "\f47c"; } -.bi-mailbox2::before { content: "\f47d"; } -.bi-map-fill::before { content: "\f47e"; } -.bi-map::before { content: "\f47f"; } -.bi-markdown-fill::before { content: "\f480"; } -.bi-markdown::before { content: "\f481"; } -.bi-mask::before { content: "\f482"; } -.bi-megaphone-fill::before { content: "\f483"; } -.bi-megaphone::before { content: "\f484"; } -.bi-menu-app-fill::before { content: "\f485"; } -.bi-menu-app::before { content: "\f486"; } -.bi-menu-button-fill::before { content: "\f487"; } -.bi-menu-button-wide-fill::before { content: "\f488"; } -.bi-menu-button-wide::before { content: "\f489"; } -.bi-menu-button::before { content: "\f48a"; } -.bi-menu-down::before { content: "\f48b"; } -.bi-menu-up::before { content: "\f48c"; } -.bi-mic-fill::before { content: "\f48d"; } -.bi-mic-mute-fill::before { content: "\f48e"; } -.bi-mic-mute::before { content: "\f48f"; } -.bi-mic::before { content: "\f490"; } -.bi-minecart-loaded::before { content: "\f491"; } -.bi-minecart::before { content: "\f492"; } -.bi-moisture::before { content: "\f493"; } -.bi-moon-fill::before { content: "\f494"; } -.bi-moon-stars-fill::before { content: "\f495"; } -.bi-moon-stars::before { content: "\f496"; } -.bi-moon::before { content: "\f497"; } -.bi-mouse-fill::before { content: "\f498"; } -.bi-mouse::before { content: "\f499"; } -.bi-mouse2-fill::before { content: "\f49a"; } -.bi-mouse2::before { content: "\f49b"; } -.bi-mouse3-fill::before { content: "\f49c"; } -.bi-mouse3::before { content: "\f49d"; } -.bi-music-note-beamed::before { content: "\f49e"; } -.bi-music-note-list::before { content: "\f49f"; } -.bi-music-note::before { content: "\f4a0"; } -.bi-music-player-fill::before { content: "\f4a1"; } -.bi-music-player::before { content: "\f4a2"; } -.bi-newspaper::before { content: "\f4a3"; } -.bi-node-minus-fill::before { content: "\f4a4"; } -.bi-node-minus::before { content: "\f4a5"; } -.bi-node-plus-fill::before { content: "\f4a6"; } -.bi-node-plus::before { content: "\f4a7"; } -.bi-nut-fill::before { content: "\f4a8"; } -.bi-nut::before { content: "\f4a9"; } -.bi-octagon-fill::before { content: "\f4aa"; } -.bi-octagon-half::before { content: "\f4ab"; } -.bi-octagon::before { content: "\f4ac"; } -.bi-option::before { content: "\f4ad"; } -.bi-outlet::before { content: "\f4ae"; } -.bi-paint-bucket::before { content: "\f4af"; } -.bi-palette-fill::before { content: "\f4b0"; } -.bi-palette::before { content: "\f4b1"; } -.bi-palette2::before { content: "\f4b2"; } -.bi-paperclip::before { content: "\f4b3"; } -.bi-paragraph::before { content: "\f4b4"; } -.bi-patch-check-fill::before { content: "\f4b5"; } -.bi-patch-check::before { content: "\f4b6"; } -.bi-patch-exclamation-fill::before { content: "\f4b7"; } -.bi-patch-exclamation::before { content: "\f4b8"; } -.bi-patch-minus-fill::before { content: "\f4b9"; } -.bi-patch-minus::before { content: "\f4ba"; } -.bi-patch-plus-fill::before { content: "\f4bb"; } -.bi-patch-plus::before { content: "\f4bc"; } -.bi-patch-question-fill::before { content: "\f4bd"; } -.bi-patch-question::before { content: "\f4be"; } -.bi-pause-btn-fill::before { content: "\f4bf"; } -.bi-pause-btn::before { content: "\f4c0"; } -.bi-pause-circle-fill::before { content: "\f4c1"; } -.bi-pause-circle::before { content: "\f4c2"; } -.bi-pause-fill::before { content: "\f4c3"; } -.bi-pause::before { content: "\f4c4"; } -.bi-peace-fill::before { content: "\f4c5"; } -.bi-peace::before { content: "\f4c6"; } -.bi-pen-fill::before { content: "\f4c7"; } -.bi-pen::before { content: "\f4c8"; } -.bi-pencil-fill::before { content: "\f4c9"; } -.bi-pencil-square::before { content: "\f4ca"; } -.bi-pencil::before { content: "\f4cb"; } -.bi-pentagon-fill::before { content: "\f4cc"; } -.bi-pentagon-half::before { content: "\f4cd"; } -.bi-pentagon::before { content: "\f4ce"; } -.bi-people-fill::before { content: "\f4cf"; } -.bi-people::before { content: "\f4d0"; } -.bi-percent::before { content: "\f4d1"; } -.bi-person-badge-fill::before { content: "\f4d2"; } -.bi-person-badge::before { content: "\f4d3"; } -.bi-person-bounding-box::before { content: "\f4d4"; } -.bi-person-check-fill::before { content: "\f4d5"; } -.bi-person-check::before { content: "\f4d6"; } -.bi-person-circle::before { content: "\f4d7"; } -.bi-person-dash-fill::before { content: "\f4d8"; } -.bi-person-dash::before { content: "\f4d9"; } -.bi-person-fill::before { content: "\f4da"; } -.bi-person-lines-fill::before { content: "\f4db"; } -.bi-person-plus-fill::before { content: "\f4dc"; } -.bi-person-plus::before { content: "\f4dd"; } -.bi-person-square::before { content: "\f4de"; } -.bi-person-x-fill::before { content: "\f4df"; } -.bi-person-x::before { content: "\f4e0"; } -.bi-person::before { content: "\f4e1"; } -.bi-phone-fill::before { content: "\f4e2"; } -.bi-phone-landscape-fill::before { content: "\f4e3"; } -.bi-phone-landscape::before { content: "\f4e4"; } -.bi-phone-vibrate-fill::before { content: "\f4e5"; } -.bi-phone-vibrate::before { content: "\f4e6"; } -.bi-phone::before { content: "\f4e7"; } -.bi-pie-chart-fill::before { content: "\f4e8"; } -.bi-pie-chart::before { content: "\f4e9"; } -.bi-pin-angle-fill::before { content: "\f4ea"; } -.bi-pin-angle::before { content: "\f4eb"; } -.bi-pin-fill::before { content: "\f4ec"; } -.bi-pin::before { content: "\f4ed"; } -.bi-pip-fill::before { content: "\f4ee"; } -.bi-pip::before { content: "\f4ef"; } -.bi-play-btn-fill::before { content: "\f4f0"; } -.bi-play-btn::before { content: "\f4f1"; } -.bi-play-circle-fill::before { content: "\f4f2"; } -.bi-play-circle::before { content: "\f4f3"; } -.bi-play-fill::before { content: "\f4f4"; } -.bi-play::before { content: "\f4f5"; } -.bi-plug-fill::before { content: "\f4f6"; } -.bi-plug::before { content: "\f4f7"; } -.bi-plus-circle-dotted::before { content: "\f4f8"; } -.bi-plus-circle-fill::before { content: "\f4f9"; } -.bi-plus-circle::before { content: "\f4fa"; } -.bi-plus-square-dotted::before { content: "\f4fb"; } -.bi-plus-square-fill::before { content: "\f4fc"; } -.bi-plus-square::before { content: "\f4fd"; } -.bi-plus::before { content: "\f4fe"; } -.bi-power::before { content: "\f4ff"; } -.bi-printer-fill::before { content: "\f500"; } -.bi-printer::before { content: "\f501"; } -.bi-puzzle-fill::before { content: "\f502"; } -.bi-puzzle::before { content: "\f503"; } -.bi-question-circle-fill::before { content: "\f504"; } -.bi-question-circle::before { content: "\f505"; } -.bi-question-diamond-fill::before { content: "\f506"; } -.bi-question-diamond::before { content: "\f507"; } -.bi-question-octagon-fill::before { content: "\f508"; } -.bi-question-octagon::before { content: "\f509"; } -.bi-question-square-fill::before { content: "\f50a"; } -.bi-question-square::before { content: "\f50b"; } -.bi-question::before { content: "\f50c"; } -.bi-rainbow::before { content: "\f50d"; } -.bi-receipt-cutoff::before { content: "\f50e"; } -.bi-receipt::before { content: "\f50f"; } -.bi-reception-0::before { content: "\f510"; } -.bi-reception-1::before { content: "\f511"; } -.bi-reception-2::before { content: "\f512"; } -.bi-reception-3::before { content: "\f513"; } -.bi-reception-4::before { content: "\f514"; } -.bi-record-btn-fill::before { content: "\f515"; } -.bi-record-btn::before { content: "\f516"; } -.bi-record-circle-fill::before { content: "\f517"; } -.bi-record-circle::before { content: "\f518"; } -.bi-record-fill::before { content: "\f519"; } -.bi-record::before { content: "\f51a"; } -.bi-record2-fill::before { content: "\f51b"; } -.bi-record2::before { content: "\f51c"; } -.bi-reply-all-fill::before { content: "\f51d"; } -.bi-reply-all::before { content: "\f51e"; } -.bi-reply-fill::before { content: "\f51f"; } -.bi-reply::before { content: "\f520"; } -.bi-rss-fill::before { content: "\f521"; } -.bi-rss::before { content: "\f522"; } -.bi-rulers::before { content: "\f523"; } -.bi-save-fill::before { content: "\f524"; } -.bi-save::before { content: "\f525"; } -.bi-save2-fill::before { content: "\f526"; } -.bi-save2::before { content: "\f527"; } -.bi-scissors::before { content: "\f528"; } -.bi-screwdriver::before { content: "\f529"; } -.bi-search::before { content: "\f52a"; } -.bi-segmented-nav::before { content: "\f52b"; } -.bi-server::before { content: "\f52c"; } -.bi-share-fill::before { content: "\f52d"; } -.bi-share::before { content: "\f52e"; } -.bi-shield-check::before { content: "\f52f"; } -.bi-shield-exclamation::before { content: "\f530"; } -.bi-shield-fill-check::before { content: "\f531"; } -.bi-shield-fill-exclamation::before { content: "\f532"; } -.bi-shield-fill-minus::before { content: "\f533"; } -.bi-shield-fill-plus::before { content: "\f534"; } -.bi-shield-fill-x::before { content: "\f535"; } -.bi-shield-fill::before { content: "\f536"; } -.bi-shield-lock-fill::before { content: "\f537"; } -.bi-shield-lock::before { content: "\f538"; } -.bi-shield-minus::before { content: "\f539"; } -.bi-shield-plus::before { content: "\f53a"; } -.bi-shield-shaded::before { content: "\f53b"; } -.bi-shield-slash-fill::before { content: "\f53c"; } -.bi-shield-slash::before { content: "\f53d"; } -.bi-shield-x::before { content: "\f53e"; } -.bi-shield::before { content: "\f53f"; } -.bi-shift-fill::before { content: "\f540"; } -.bi-shift::before { content: "\f541"; } -.bi-shop-window::before { content: "\f542"; } -.bi-shop::before { content: "\f543"; } -.bi-shuffle::before { content: "\f544"; } -.bi-signpost-2-fill::before { content: "\f545"; } -.bi-signpost-2::before { content: "\f546"; } -.bi-signpost-fill::before { content: "\f547"; } -.bi-signpost-split-fill::before { content: "\f548"; } -.bi-signpost-split::before { content: "\f549"; } -.bi-signpost::before { content: "\f54a"; } -.bi-sim-fill::before { content: "\f54b"; } -.bi-sim::before { content: "\f54c"; } -.bi-skip-backward-btn-fill::before { content: "\f54d"; } -.bi-skip-backward-btn::before { content: "\f54e"; } -.bi-skip-backward-circle-fill::before { content: "\f54f"; } -.bi-skip-backward-circle::before { content: "\f550"; } -.bi-skip-backward-fill::before { content: "\f551"; } -.bi-skip-backward::before { content: "\f552"; } -.bi-skip-end-btn-fill::before { content: "\f553"; } -.bi-skip-end-btn::before { content: "\f554"; } -.bi-skip-end-circle-fill::before { content: "\f555"; } -.bi-skip-end-circle::before { content: "\f556"; } -.bi-skip-end-fill::before { content: "\f557"; } -.bi-skip-end::before { content: "\f558"; } -.bi-skip-forward-btn-fill::before { content: "\f559"; } -.bi-skip-forward-btn::before { content: "\f55a"; } -.bi-skip-forward-circle-fill::before { content: "\f55b"; } -.bi-skip-forward-circle::before { content: "\f55c"; } -.bi-skip-forward-fill::before { content: "\f55d"; } -.bi-skip-forward::before { content: "\f55e"; } -.bi-skip-start-btn-fill::before { content: "\f55f"; } -.bi-skip-start-btn::before { content: "\f560"; } -.bi-skip-start-circle-fill::before { content: "\f561"; } -.bi-skip-start-circle::before { content: "\f562"; } -.bi-skip-start-fill::before { content: "\f563"; } -.bi-skip-start::before { content: "\f564"; } -.bi-slack::before { content: "\f565"; } -.bi-slash-circle-fill::before { content: "\f566"; } -.bi-slash-circle::before { content: "\f567"; } -.bi-slash-square-fill::before { content: "\f568"; } -.bi-slash-square::before { content: "\f569"; } -.bi-slash::before { content: "\f56a"; } -.bi-sliders::before { content: "\f56b"; } -.bi-smartwatch::before { content: "\f56c"; } -.bi-snow::before { content: "\f56d"; } -.bi-snow2::before { content: "\f56e"; } -.bi-snow3::before { content: "\f56f"; } -.bi-sort-alpha-down-alt::before { content: "\f570"; } -.bi-sort-alpha-down::before { content: "\f571"; } -.bi-sort-alpha-up-alt::before { content: "\f572"; } -.bi-sort-alpha-up::before { content: "\f573"; } -.bi-sort-down-alt::before { content: "\f574"; } -.bi-sort-down::before { content: "\f575"; } -.bi-sort-numeric-down-alt::before { content: "\f576"; } -.bi-sort-numeric-down::before { content: "\f577"; } -.bi-sort-numeric-up-alt::before { content: "\f578"; } -.bi-sort-numeric-up::before { content: "\f579"; } -.bi-sort-up-alt::before { content: "\f57a"; } -.bi-sort-up::before { content: "\f57b"; } -.bi-soundwave::before { content: "\f57c"; } -.bi-speaker-fill::before { content: "\f57d"; } -.bi-speaker::before { content: "\f57e"; } -.bi-speedometer::before { content: "\f57f"; } -.bi-speedometer2::before { content: "\f580"; } -.bi-spellcheck::before { content: "\f581"; } -.bi-square-fill::before { content: "\f582"; } -.bi-square-half::before { content: "\f583"; } -.bi-square::before { content: "\f584"; } -.bi-stack::before { content: "\f585"; } -.bi-star-fill::before { content: "\f586"; } -.bi-star-half::before { content: "\f587"; } -.bi-star::before { content: "\f588"; } -.bi-stars::before { content: "\f589"; } -.bi-stickies-fill::before { content: "\f58a"; } -.bi-stickies::before { content: "\f58b"; } -.bi-sticky-fill::before { content: "\f58c"; } -.bi-sticky::before { content: "\f58d"; } -.bi-stop-btn-fill::before { content: "\f58e"; } -.bi-stop-btn::before { content: "\f58f"; } -.bi-stop-circle-fill::before { content: "\f590"; } -.bi-stop-circle::before { content: "\f591"; } -.bi-stop-fill::before { content: "\f592"; } -.bi-stop::before { content: "\f593"; } -.bi-stoplights-fill::before { content: "\f594"; } -.bi-stoplights::before { content: "\f595"; } -.bi-stopwatch-fill::before { content: "\f596"; } -.bi-stopwatch::before { content: "\f597"; } -.bi-subtract::before { content: "\f598"; } -.bi-suit-club-fill::before { content: "\f599"; } -.bi-suit-club::before { content: "\f59a"; } -.bi-suit-diamond-fill::before { content: "\f59b"; } -.bi-suit-diamond::before { content: "\f59c"; } -.bi-suit-heart-fill::before { content: "\f59d"; } -.bi-suit-heart::before { content: "\f59e"; } -.bi-suit-spade-fill::before { content: "\f59f"; } -.bi-suit-spade::before { content: "\f5a0"; } -.bi-sun-fill::before { content: "\f5a1"; } -.bi-sun::before { content: "\f5a2"; } -.bi-sunglasses::before { content: "\f5a3"; } -.bi-sunrise-fill::before { content: "\f5a4"; } -.bi-sunrise::before { content: "\f5a5"; } -.bi-sunset-fill::before { content: "\f5a6"; } -.bi-sunset::before { content: "\f5a7"; } -.bi-symmetry-horizontal::before { content: "\f5a8"; } -.bi-symmetry-vertical::before { content: "\f5a9"; } -.bi-table::before { content: "\f5aa"; } -.bi-tablet-fill::before { content: "\f5ab"; } -.bi-tablet-landscape-fill::before { content: "\f5ac"; } -.bi-tablet-landscape::before { content: "\f5ad"; } -.bi-tablet::before { content: "\f5ae"; } -.bi-tag-fill::before { content: "\f5af"; } -.bi-tag::before { content: "\f5b0"; } -.bi-tags-fill::before { content: "\f5b1"; } -.bi-tags::before { content: "\f5b2"; } -.bi-telegram::before { content: "\f5b3"; } -.bi-telephone-fill::before { content: "\f5b4"; } -.bi-telephone-forward-fill::before { content: "\f5b5"; } -.bi-telephone-forward::before { content: "\f5b6"; } -.bi-telephone-inbound-fill::before { content: "\f5b7"; } -.bi-telephone-inbound::before { content: "\f5b8"; } -.bi-telephone-minus-fill::before { content: "\f5b9"; } -.bi-telephone-minus::before { content: "\f5ba"; } -.bi-telephone-outbound-fill::before { content: "\f5bb"; } -.bi-telephone-outbound::before { content: "\f5bc"; } -.bi-telephone-plus-fill::before { content: "\f5bd"; } -.bi-telephone-plus::before { content: "\f5be"; } -.bi-telephone-x-fill::before { content: "\f5bf"; } -.bi-telephone-x::before { content: "\f5c0"; } -.bi-telephone::before { content: "\f5c1"; } -.bi-terminal-fill::before { content: "\f5c2"; } -.bi-terminal::before { content: "\f5c3"; } -.bi-text-center::before { content: "\f5c4"; } -.bi-text-indent-left::before { content: "\f5c5"; } -.bi-text-indent-right::before { content: "\f5c6"; } -.bi-text-left::before { content: "\f5c7"; } -.bi-text-paragraph::before { content: "\f5c8"; } -.bi-text-right::before { content: "\f5c9"; } -.bi-textarea-resize::before { content: "\f5ca"; } -.bi-textarea-t::before { content: "\f5cb"; } -.bi-textarea::before { content: "\f5cc"; } -.bi-thermometer-half::before { content: "\f5cd"; } -.bi-thermometer-high::before { content: "\f5ce"; } -.bi-thermometer-low::before { content: "\f5cf"; } -.bi-thermometer-snow::before { content: "\f5d0"; } -.bi-thermometer-sun::before { content: "\f5d1"; } -.bi-thermometer::before { content: "\f5d2"; } -.bi-three-dots-vertical::before { content: "\f5d3"; } -.bi-three-dots::before { content: "\f5d4"; } -.bi-toggle-off::before { content: "\f5d5"; } -.bi-toggle-on::before { content: "\f5d6"; } -.bi-toggle2-off::before { content: "\f5d7"; } -.bi-toggle2-on::before { content: "\f5d8"; } -.bi-toggles::before { content: "\f5d9"; } -.bi-toggles2::before { content: "\f5da"; } -.bi-tools::before { content: "\f5db"; } -.bi-tornado::before { content: "\f5dc"; } -.bi-trash-fill::before { content: "\f5dd"; } -.bi-trash::before { content: "\f5de"; } -.bi-trash2-fill::before { content: "\f5df"; } -.bi-trash2::before { content: "\f5e0"; } -.bi-tree-fill::before { content: "\f5e1"; } -.bi-tree::before { content: "\f5e2"; } -.bi-triangle-fill::before { content: "\f5e3"; } -.bi-triangle-half::before { content: "\f5e4"; } -.bi-triangle::before { content: "\f5e5"; } -.bi-trophy-fill::before { content: "\f5e6"; } -.bi-trophy::before { content: "\f5e7"; } -.bi-tropical-storm::before { content: "\f5e8"; } -.bi-truck-flatbed::before { content: "\f5e9"; } -.bi-truck::before { content: "\f5ea"; } -.bi-tsunami::before { content: "\f5eb"; } -.bi-tv-fill::before { content: "\f5ec"; } -.bi-tv::before { content: "\f5ed"; } -.bi-twitch::before { content: "\f5ee"; } -.bi-twitter::before { content: "\f5ef"; } -.bi-type-bold::before { content: "\f5f0"; } -.bi-type-h1::before { content: "\f5f1"; } -.bi-type-h2::before { content: "\f5f2"; } -.bi-type-h3::before { content: "\f5f3"; } -.bi-type-italic::before { content: "\f5f4"; } -.bi-type-strikethrough::before { content: "\f5f5"; } -.bi-type-underline::before { content: "\f5f6"; } -.bi-type::before { content: "\f5f7"; } -.bi-ui-checks-grid::before { content: "\f5f8"; } -.bi-ui-checks::before { content: "\f5f9"; } -.bi-ui-radios-grid::before { content: "\f5fa"; } -.bi-ui-radios::before { content: "\f5fb"; } -.bi-umbrella-fill::before { content: "\f5fc"; } -.bi-umbrella::before { content: "\f5fd"; } -.bi-union::before { content: "\f5fe"; } -.bi-unlock-fill::before { content: "\f5ff"; } -.bi-unlock::before { content: "\f600"; } -.bi-upc-scan::before { content: "\f601"; } -.bi-upc::before { content: "\f602"; } -.bi-upload::before { content: "\f603"; } -.bi-vector-pen::before { content: "\f604"; } -.bi-view-list::before { content: "\f605"; } -.bi-view-stacked::before { content: "\f606"; } -.bi-vinyl-fill::before { content: "\f607"; } -.bi-vinyl::before { content: "\f608"; } -.bi-voicemail::before { content: "\f609"; } -.bi-volume-down-fill::before { content: "\f60a"; } -.bi-volume-down::before { content: "\f60b"; } -.bi-volume-mute-fill::before { content: "\f60c"; } -.bi-volume-mute::before { content: "\f60d"; } -.bi-volume-off-fill::before { content: "\f60e"; } -.bi-volume-off::before { content: "\f60f"; } -.bi-volume-up-fill::before { content: "\f610"; } -.bi-volume-up::before { content: "\f611"; } -.bi-vr::before { content: "\f612"; } -.bi-wallet-fill::before { content: "\f613"; } -.bi-wallet::before { content: "\f614"; } -.bi-wallet2::before { content: "\f615"; } -.bi-watch::before { content: "\f616"; } -.bi-water::before { content: "\f617"; } -.bi-whatsapp::before { content: "\f618"; } -.bi-wifi-1::before { content: "\f619"; } -.bi-wifi-2::before { content: "\f61a"; } -.bi-wifi-off::before { content: "\f61b"; } -.bi-wifi::before { content: "\f61c"; } -.bi-wind::before { content: "\f61d"; } -.bi-window-dock::before { content: "\f61e"; } -.bi-window-sidebar::before { content: "\f61f"; } -.bi-window::before { content: "\f620"; } -.bi-wrench::before { content: "\f621"; } -.bi-x-circle-fill::before { content: "\f622"; } -.bi-x-circle::before { content: "\f623"; } -.bi-x-diamond-fill::before { content: "\f624"; } -.bi-x-diamond::before { content: "\f625"; } -.bi-x-octagon-fill::before { content: "\f626"; } -.bi-x-octagon::before { content: "\f627"; } -.bi-x-square-fill::before { content: "\f628"; } -.bi-x-square::before { content: "\f629"; } -.bi-x::before { content: "\f62a"; } -.bi-youtube::before { content: "\f62b"; } -.bi-zoom-in::before { content: "\f62c"; } -.bi-zoom-out::before { content: "\f62d"; } -.bi-bank::before { content: "\f62e"; } -.bi-bank2::before { content: "\f62f"; } -.bi-bell-slash-fill::before { content: "\f630"; } -.bi-bell-slash::before { content: "\f631"; } -.bi-cash-coin::before { content: "\f632"; } -.bi-check-lg::before { content: "\f633"; } -.bi-coin::before { content: "\f634"; } -.bi-currency-bitcoin::before { content: "\f635"; } -.bi-currency-dollar::before { content: "\f636"; } -.bi-currency-euro::before { content: "\f637"; } -.bi-currency-exchange::before { content: "\f638"; } -.bi-currency-pound::before { content: "\f639"; } -.bi-currency-yen::before { content: "\f63a"; } -.bi-dash-lg::before { content: "\f63b"; } -.bi-exclamation-lg::before { content: "\f63c"; } -.bi-file-earmark-pdf-fill::before { content: "\f63d"; } -.bi-file-earmark-pdf::before { content: "\f63e"; } -.bi-file-pdf-fill::before { content: "\f63f"; } -.bi-file-pdf::before { content: "\f640"; } -.bi-gender-ambiguous::before { content: "\f641"; } -.bi-gender-female::before { content: "\f642"; } -.bi-gender-male::before { content: "\f643"; } -.bi-gender-trans::before { content: "\f644"; } -.bi-headset-vr::before { content: "\f645"; } -.bi-info-lg::before { content: "\f646"; } -.bi-mastodon::before { content: "\f647"; } -.bi-messenger::before { content: "\f648"; } -.bi-piggy-bank-fill::before { content: "\f649"; } -.bi-piggy-bank::before { content: "\f64a"; } -.bi-pin-map-fill::before { content: "\f64b"; } -.bi-pin-map::before { content: "\f64c"; } -.bi-plus-lg::before { content: "\f64d"; } -.bi-question-lg::before { content: "\f64e"; } -.bi-recycle::before { content: "\f64f"; } -.bi-reddit::before { content: "\f650"; } -.bi-safe-fill::before { content: "\f651"; } -.bi-safe2-fill::before { content: "\f652"; } -.bi-safe2::before { content: "\f653"; } -.bi-sd-card-fill::before { content: "\f654"; } -.bi-sd-card::before { content: "\f655"; } -.bi-skype::before { content: "\f656"; } -.bi-slash-lg::before { content: "\f657"; } -.bi-translate::before { content: "\f658"; } -.bi-x-lg::before { content: "\f659"; } -.bi-safe::before { content: "\f65a"; } -.bi-apple::before { content: "\f65b"; } -.bi-microsoft::before { content: "\f65d"; } -.bi-windows::before { content: "\f65e"; } -.bi-behance::before { content: "\f65c"; } -.bi-dribbble::before { content: "\f65f"; } -.bi-line::before { content: "\f660"; } -.bi-medium::before { content: "\f661"; } -.bi-paypal::before { content: "\f662"; } -.bi-pinterest::before { content: "\f663"; } -.bi-signal::before { content: "\f664"; } -.bi-snapchat::before { content: "\f665"; } -.bi-spotify::before { content: "\f666"; } -.bi-stack-overflow::before { content: "\f667"; } -.bi-strava::before { content: "\f668"; } -.bi-wordpress::before { content: "\f669"; } -.bi-vimeo::before { content: "\f66a"; } -.bi-activity::before { content: "\f66b"; } -.bi-easel2-fill::before { content: "\f66c"; } -.bi-easel2::before { content: "\f66d"; } -.bi-easel3-fill::before { content: "\f66e"; } -.bi-easel3::before { content: "\f66f"; } -.bi-fan::before { content: "\f670"; } -.bi-fingerprint::before { content: "\f671"; } -.bi-graph-down-arrow::before { content: "\f672"; } -.bi-graph-up-arrow::before { content: "\f673"; } -.bi-hypnotize::before { content: "\f674"; } -.bi-magic::before { content: "\f675"; } -.bi-person-rolodex::before { content: "\f676"; } -.bi-person-video::before { content: "\f677"; } -.bi-person-video2::before { content: "\f678"; } -.bi-person-video3::before { content: "\f679"; } -.bi-person-workspace::before { content: "\f67a"; } -.bi-radioactive::before { content: "\f67b"; } -.bi-webcam-fill::before { content: "\f67c"; } -.bi-webcam::before { content: "\f67d"; } -.bi-yin-yang::before { content: "\f67e"; } -.bi-bandaid-fill::before { content: "\f680"; } -.bi-bandaid::before { content: "\f681"; } -.bi-bluetooth::before { content: "\f682"; } -.bi-body-text::before { content: "\f683"; } -.bi-boombox::before { content: "\f684"; } -.bi-boxes::before { content: "\f685"; } -.bi-dpad-fill::before { content: "\f686"; } -.bi-dpad::before { content: "\f687"; } -.bi-ear-fill::before { content: "\f688"; } -.bi-ear::before { content: "\f689"; } -.bi-envelope-check-fill::before { content: "\f68b"; } -.bi-envelope-check::before { content: "\f68c"; } -.bi-envelope-dash-fill::before { content: "\f68e"; } -.bi-envelope-dash::before { content: "\f68f"; } -.bi-envelope-exclamation-fill::before { content: "\f691"; } -.bi-envelope-exclamation::before { content: "\f692"; } -.bi-envelope-plus-fill::before { content: "\f693"; } -.bi-envelope-plus::before { content: "\f694"; } -.bi-envelope-slash-fill::before { content: "\f696"; } -.bi-envelope-slash::before { content: "\f697"; } -.bi-envelope-x-fill::before { content: "\f699"; } -.bi-envelope-x::before { content: "\f69a"; } -.bi-explicit-fill::before { content: "\f69b"; } -.bi-explicit::before { content: "\f69c"; } -.bi-git::before { content: "\f69d"; } -.bi-infinity::before { content: "\f69e"; } -.bi-list-columns-reverse::before { content: "\f69f"; } -.bi-list-columns::before { content: "\f6a0"; } -.bi-meta::before { content: "\f6a1"; } -.bi-nintendo-switch::before { content: "\f6a4"; } -.bi-pc-display-horizontal::before { content: "\f6a5"; } -.bi-pc-display::before { content: "\f6a6"; } -.bi-pc-horizontal::before { content: "\f6a7"; } -.bi-pc::before { content: "\f6a8"; } -.bi-playstation::before { content: "\f6a9"; } -.bi-plus-slash-minus::before { content: "\f6aa"; } -.bi-projector-fill::before { content: "\f6ab"; } -.bi-projector::before { content: "\f6ac"; } -.bi-qr-code-scan::before { content: "\f6ad"; } -.bi-qr-code::before { content: "\f6ae"; } -.bi-quora::before { content: "\f6af"; } -.bi-quote::before { content: "\f6b0"; } -.bi-robot::before { content: "\f6b1"; } -.bi-send-check-fill::before { content: "\f6b2"; } -.bi-send-check::before { content: "\f6b3"; } -.bi-send-dash-fill::before { content: "\f6b4"; } -.bi-send-dash::before { content: "\f6b5"; } -.bi-send-exclamation-fill::before { content: "\f6b7"; } -.bi-send-exclamation::before { content: "\f6b8"; } -.bi-send-fill::before { content: "\f6b9"; } -.bi-send-plus-fill::before { content: "\f6ba"; } -.bi-send-plus::before { content: "\f6bb"; } -.bi-send-slash-fill::before { content: "\f6bc"; } -.bi-send-slash::before { content: "\f6bd"; } -.bi-send-x-fill::before { content: "\f6be"; } -.bi-send-x::before { content: "\f6bf"; } -.bi-send::before { content: "\f6c0"; } -.bi-steam::before { content: "\f6c1"; } -.bi-terminal-dash::before { content: "\f6c3"; } -.bi-terminal-plus::before { content: "\f6c4"; } -.bi-terminal-split::before { content: "\f6c5"; } -.bi-ticket-detailed-fill::before { content: "\f6c6"; } -.bi-ticket-detailed::before { content: "\f6c7"; } -.bi-ticket-fill::before { content: "\f6c8"; } -.bi-ticket-perforated-fill::before { content: "\f6c9"; } -.bi-ticket-perforated::before { content: "\f6ca"; } -.bi-ticket::before { content: "\f6cb"; } -.bi-tiktok::before { content: "\f6cc"; } -.bi-window-dash::before { content: "\f6cd"; } -.bi-window-desktop::before { content: "\f6ce"; } -.bi-window-fullscreen::before { content: "\f6cf"; } -.bi-window-plus::before { content: "\f6d0"; } -.bi-window-split::before { content: "\f6d1"; } -.bi-window-stack::before { content: "\f6d2"; } -.bi-window-x::before { content: "\f6d3"; } -.bi-xbox::before { content: "\f6d4"; } -.bi-ethernet::before { content: "\f6d5"; } -.bi-hdmi-fill::before { content: "\f6d6"; } -.bi-hdmi::before { content: "\f6d7"; } -.bi-usb-c-fill::before { content: "\f6d8"; } -.bi-usb-c::before { content: "\f6d9"; } -.bi-usb-fill::before { content: "\f6da"; } -.bi-usb-plug-fill::before { content: "\f6db"; } -.bi-usb-plug::before { content: "\f6dc"; } -.bi-usb-symbol::before { content: "\f6dd"; } -.bi-usb::before { content: "\f6de"; } -.bi-boombox-fill::before { content: "\f6df"; } -.bi-displayport::before { content: "\f6e1"; } -.bi-gpu-card::before { content: "\f6e2"; } -.bi-memory::before { content: "\f6e3"; } -.bi-modem-fill::before { content: "\f6e4"; } -.bi-modem::before { content: "\f6e5"; } -.bi-motherboard-fill::before { content: "\f6e6"; } -.bi-motherboard::before { content: "\f6e7"; } -.bi-optical-audio-fill::before { content: "\f6e8"; } -.bi-optical-audio::before { content: "\f6e9"; } -.bi-pci-card::before { content: "\f6ea"; } -.bi-router-fill::before { content: "\f6eb"; } -.bi-router::before { content: "\f6ec"; } -.bi-thunderbolt-fill::before { content: "\f6ef"; } -.bi-thunderbolt::before { content: "\f6f0"; } -.bi-usb-drive-fill::before { content: "\f6f1"; } -.bi-usb-drive::before { content: "\f6f2"; } -.bi-usb-micro-fill::before { content: "\f6f3"; } -.bi-usb-micro::before { content: "\f6f4"; } -.bi-usb-mini-fill::before { content: "\f6f5"; } -.bi-usb-mini::before { content: "\f6f6"; } -.bi-cloud-haze2::before { content: "\f6f7"; } -.bi-device-hdd-fill::before { content: "\f6f8"; } -.bi-device-hdd::before { content: "\f6f9"; } -.bi-device-ssd-fill::before { content: "\f6fa"; } -.bi-device-ssd::before { content: "\f6fb"; } -.bi-displayport-fill::before { content: "\f6fc"; } -.bi-mortarboard-fill::before { content: "\f6fd"; } -.bi-mortarboard::before { content: "\f6fe"; } -.bi-terminal-x::before { content: "\f6ff"; } -.bi-arrow-through-heart-fill::before { content: "\f700"; } -.bi-arrow-through-heart::before { content: "\f701"; } -.bi-badge-sd-fill::before { content: "\f702"; } -.bi-badge-sd::before { content: "\f703"; } -.bi-bag-heart-fill::before { content: "\f704"; } -.bi-bag-heart::before { content: "\f705"; } -.bi-balloon-fill::before { content: "\f706"; } -.bi-balloon-heart-fill::before { content: "\f707"; } -.bi-balloon-heart::before { content: "\f708"; } -.bi-balloon::before { content: "\f709"; } -.bi-box2-fill::before { content: "\f70a"; } -.bi-box2-heart-fill::before { content: "\f70b"; } -.bi-box2-heart::before { content: "\f70c"; } -.bi-box2::before { content: "\f70d"; } -.bi-braces-asterisk::before { content: "\f70e"; } -.bi-calendar-heart-fill::before { content: "\f70f"; } -.bi-calendar-heart::before { content: "\f710"; } -.bi-calendar2-heart-fill::before { content: "\f711"; } -.bi-calendar2-heart::before { content: "\f712"; } -.bi-chat-heart-fill::before { content: "\f713"; } -.bi-chat-heart::before { content: "\f714"; } -.bi-chat-left-heart-fill::before { content: "\f715"; } -.bi-chat-left-heart::before { content: "\f716"; } -.bi-chat-right-heart-fill::before { content: "\f717"; } -.bi-chat-right-heart::before { content: "\f718"; } -.bi-chat-square-heart-fill::before { content: "\f719"; } -.bi-chat-square-heart::before { content: "\f71a"; } -.bi-clipboard-check-fill::before { content: "\f71b"; } -.bi-clipboard-data-fill::before { content: "\f71c"; } -.bi-clipboard-fill::before { content: "\f71d"; } -.bi-clipboard-heart-fill::before { content: "\f71e"; } -.bi-clipboard-heart::before { content: "\f71f"; } -.bi-clipboard-minus-fill::before { content: "\f720"; } -.bi-clipboard-plus-fill::before { content: "\f721"; } -.bi-clipboard-pulse::before { content: "\f722"; } -.bi-clipboard-x-fill::before { content: "\f723"; } -.bi-clipboard2-check-fill::before { content: "\f724"; } -.bi-clipboard2-check::before { content: "\f725"; } -.bi-clipboard2-data-fill::before { content: "\f726"; } -.bi-clipboard2-data::before { content: "\f727"; } -.bi-clipboard2-fill::before { content: "\f728"; } -.bi-clipboard2-heart-fill::before { content: "\f729"; } -.bi-clipboard2-heart::before { content: "\f72a"; } -.bi-clipboard2-minus-fill::before { content: "\f72b"; } -.bi-clipboard2-minus::before { content: "\f72c"; } -.bi-clipboard2-plus-fill::before { content: "\f72d"; } -.bi-clipboard2-plus::before { content: "\f72e"; } -.bi-clipboard2-pulse-fill::before { content: "\f72f"; } -.bi-clipboard2-pulse::before { content: "\f730"; } -.bi-clipboard2-x-fill::before { content: "\f731"; } -.bi-clipboard2-x::before { content: "\f732"; } -.bi-clipboard2::before { content: "\f733"; } -.bi-emoji-kiss-fill::before { content: "\f734"; } -.bi-emoji-kiss::before { content: "\f735"; } -.bi-envelope-heart-fill::before { content: "\f736"; } -.bi-envelope-heart::before { content: "\f737"; } -.bi-envelope-open-heart-fill::before { content: "\f738"; } -.bi-envelope-open-heart::before { content: "\f739"; } -.bi-envelope-paper-fill::before { content: "\f73a"; } -.bi-envelope-paper-heart-fill::before { content: "\f73b"; } -.bi-envelope-paper-heart::before { content: "\f73c"; } -.bi-envelope-paper::before { content: "\f73d"; } -.bi-filetype-aac::before { content: "\f73e"; } -.bi-filetype-ai::before { content: "\f73f"; } -.bi-filetype-bmp::before { content: "\f740"; } -.bi-filetype-cs::before { content: "\f741"; } -.bi-filetype-css::before { content: "\f742"; } -.bi-filetype-csv::before { content: "\f743"; } -.bi-filetype-doc::before { content: "\f744"; } -.bi-filetype-docx::before { content: "\f745"; } -.bi-filetype-exe::before { content: "\f746"; } -.bi-filetype-gif::before { content: "\f747"; } -.bi-filetype-heic::before { content: "\f748"; } -.bi-filetype-html::before { content: "\f749"; } -.bi-filetype-java::before { content: "\f74a"; } -.bi-filetype-jpg::before { content: "\f74b"; } -.bi-filetype-js::before { content: "\f74c"; } -.bi-filetype-jsx::before { content: "\f74d"; } -.bi-filetype-key::before { content: "\f74e"; } -.bi-filetype-m4p::before { content: "\f74f"; } -.bi-filetype-md::before { content: "\f750"; } -.bi-filetype-mdx::before { content: "\f751"; } -.bi-filetype-mov::before { content: "\f752"; } -.bi-filetype-mp3::before { content: "\f753"; } -.bi-filetype-mp4::before { content: "\f754"; } -.bi-filetype-otf::before { content: "\f755"; } -.bi-filetype-pdf::before { content: "\f756"; } -.bi-filetype-php::before { content: "\f757"; } -.bi-filetype-png::before { content: "\f758"; } -.bi-filetype-ppt::before { content: "\f75a"; } -.bi-filetype-psd::before { content: "\f75b"; } -.bi-filetype-py::before { content: "\f75c"; } -.bi-filetype-raw::before { content: "\f75d"; } -.bi-filetype-rb::before { content: "\f75e"; } -.bi-filetype-sass::before { content: "\f75f"; } -.bi-filetype-scss::before { content: "\f760"; } -.bi-filetype-sh::before { content: "\f761"; } -.bi-filetype-svg::before { content: "\f762"; } -.bi-filetype-tiff::before { content: "\f763"; } -.bi-filetype-tsx::before { content: "\f764"; } -.bi-filetype-ttf::before { content: "\f765"; } -.bi-filetype-txt::before { content: "\f766"; } -.bi-filetype-wav::before { content: "\f767"; } -.bi-filetype-woff::before { content: "\f768"; } -.bi-filetype-xls::before { content: "\f76a"; } -.bi-filetype-xml::before { content: "\f76b"; } -.bi-filetype-yml::before { content: "\f76c"; } -.bi-heart-arrow::before { content: "\f76d"; } -.bi-heart-pulse-fill::before { content: "\f76e"; } -.bi-heart-pulse::before { content: "\f76f"; } -.bi-heartbreak-fill::before { content: "\f770"; } -.bi-heartbreak::before { content: "\f771"; } -.bi-hearts::before { content: "\f772"; } -.bi-hospital-fill::before { content: "\f773"; } -.bi-hospital::before { content: "\f774"; } -.bi-house-heart-fill::before { content: "\f775"; } -.bi-house-heart::before { content: "\f776"; } -.bi-incognito::before { content: "\f777"; } -.bi-magnet-fill::before { content: "\f778"; } -.bi-magnet::before { content: "\f779"; } -.bi-person-heart::before { content: "\f77a"; } -.bi-person-hearts::before { content: "\f77b"; } -.bi-phone-flip::before { content: "\f77c"; } -.bi-plugin::before { content: "\f77d"; } -.bi-postage-fill::before { content: "\f77e"; } -.bi-postage-heart-fill::before { content: "\f77f"; } -.bi-postage-heart::before { content: "\f780"; } -.bi-postage::before { content: "\f781"; } -.bi-postcard-fill::before { content: "\f782"; } -.bi-postcard-heart-fill::before { content: "\f783"; } -.bi-postcard-heart::before { content: "\f784"; } -.bi-postcard::before { content: "\f785"; } -.bi-search-heart-fill::before { content: "\f786"; } -.bi-search-heart::before { content: "\f787"; } -.bi-sliders2-vertical::before { content: "\f788"; } -.bi-sliders2::before { content: "\f789"; } -.bi-trash3-fill::before { content: "\f78a"; } -.bi-trash3::before { content: "\f78b"; } -.bi-valentine::before { content: "\f78c"; } -.bi-valentine2::before { content: "\f78d"; } -.bi-wrench-adjustable-circle-fill::before { content: "\f78e"; } -.bi-wrench-adjustable-circle::before { content: "\f78f"; } -.bi-wrench-adjustable::before { content: "\f790"; } -.bi-filetype-json::before { content: "\f791"; } -.bi-filetype-pptx::before { content: "\f792"; } -.bi-filetype-xlsx::before { content: "\f793"; } -.bi-1-circle-fill::before { content: "\f796"; } -.bi-1-circle::before { content: "\f797"; } -.bi-1-square-fill::before { content: "\f798"; } -.bi-1-square::before { content: "\f799"; } -.bi-2-circle-fill::before { content: "\f79c"; } -.bi-2-circle::before { content: "\f79d"; } -.bi-2-square-fill::before { content: "\f79e"; } -.bi-2-square::before { content: "\f79f"; } -.bi-3-circle-fill::before { content: "\f7a2"; } -.bi-3-circle::before { content: "\f7a3"; } -.bi-3-square-fill::before { content: "\f7a4"; } -.bi-3-square::before { content: "\f7a5"; } -.bi-4-circle-fill::before { content: "\f7a8"; } -.bi-4-circle::before { content: "\f7a9"; } -.bi-4-square-fill::before { content: "\f7aa"; } -.bi-4-square::before { content: "\f7ab"; } -.bi-5-circle-fill::before { content: "\f7ae"; } -.bi-5-circle::before { content: "\f7af"; } -.bi-5-square-fill::before { content: "\f7b0"; } -.bi-5-square::before { content: "\f7b1"; } -.bi-6-circle-fill::before { content: "\f7b4"; } -.bi-6-circle::before { content: "\f7b5"; } -.bi-6-square-fill::before { content: "\f7b6"; } -.bi-6-square::before { content: "\f7b7"; } -.bi-7-circle-fill::before { content: "\f7ba"; } -.bi-7-circle::before { content: "\f7bb"; } -.bi-7-square-fill::before { content: "\f7bc"; } -.bi-7-square::before { content: "\f7bd"; } -.bi-8-circle-fill::before { content: "\f7c0"; } -.bi-8-circle::before { content: "\f7c1"; } -.bi-8-square-fill::before { content: "\f7c2"; } -.bi-8-square::before { content: "\f7c3"; } -.bi-9-circle-fill::before { content: "\f7c6"; } -.bi-9-circle::before { content: "\f7c7"; } -.bi-9-square-fill::before { content: "\f7c8"; } -.bi-9-square::before { content: "\f7c9"; } -.bi-airplane-engines-fill::before { content: "\f7ca"; } -.bi-airplane-engines::before { content: "\f7cb"; } -.bi-airplane-fill::before { content: "\f7cc"; } -.bi-airplane::before { content: "\f7cd"; } -.bi-alexa::before { content: "\f7ce"; } -.bi-alipay::before { content: "\f7cf"; } -.bi-android::before { content: "\f7d0"; } -.bi-android2::before { content: "\f7d1"; } -.bi-box-fill::before { content: "\f7d2"; } -.bi-box-seam-fill::before { content: "\f7d3"; } -.bi-browser-chrome::before { content: "\f7d4"; } -.bi-browser-edge::before { content: "\f7d5"; } -.bi-browser-firefox::before { content: "\f7d6"; } -.bi-browser-safari::before { content: "\f7d7"; } -.bi-c-circle-fill::before { content: "\f7da"; } -.bi-c-circle::before { content: "\f7db"; } -.bi-c-square-fill::before { content: "\f7dc"; } -.bi-c-square::before { content: "\f7dd"; } -.bi-capsule-pill::before { content: "\f7de"; } -.bi-capsule::before { content: "\f7df"; } -.bi-car-front-fill::before { content: "\f7e0"; } -.bi-car-front::before { content: "\f7e1"; } -.bi-cassette-fill::before { content: "\f7e2"; } -.bi-cassette::before { content: "\f7e3"; } -.bi-cc-circle-fill::before { content: "\f7e6"; } -.bi-cc-circle::before { content: "\f7e7"; } -.bi-cc-square-fill::before { content: "\f7e8"; } -.bi-cc-square::before { content: "\f7e9"; } -.bi-cup-hot-fill::before { content: "\f7ea"; } -.bi-cup-hot::before { content: "\f7eb"; } -.bi-currency-rupee::before { content: "\f7ec"; } -.bi-dropbox::before { content: "\f7ed"; } -.bi-escape::before { content: "\f7ee"; } -.bi-fast-forward-btn-fill::before { content: "\f7ef"; } -.bi-fast-forward-btn::before { content: "\f7f0"; } -.bi-fast-forward-circle-fill::before { content: "\f7f1"; } -.bi-fast-forward-circle::before { content: "\f7f2"; } -.bi-fast-forward-fill::before { content: "\f7f3"; } -.bi-fast-forward::before { content: "\f7f4"; } -.bi-filetype-sql::before { content: "\f7f5"; } -.bi-fire::before { content: "\f7f6"; } -.bi-google-play::before { content: "\f7f7"; } -.bi-h-circle-fill::before { content: "\f7fa"; } -.bi-h-circle::before { content: "\f7fb"; } -.bi-h-square-fill::before { content: "\f7fc"; } -.bi-h-square::before { content: "\f7fd"; } -.bi-indent::before { content: "\f7fe"; } -.bi-lungs-fill::before { content: "\f7ff"; } -.bi-lungs::before { content: "\f800"; } -.bi-microsoft-teams::before { content: "\f801"; } -.bi-p-circle-fill::before { content: "\f804"; } -.bi-p-circle::before { content: "\f805"; } -.bi-p-square-fill::before { content: "\f806"; } -.bi-p-square::before { content: "\f807"; } -.bi-pass-fill::before { content: "\f808"; } -.bi-pass::before { content: "\f809"; } -.bi-prescription::before { content: "\f80a"; } -.bi-prescription2::before { content: "\f80b"; } -.bi-r-circle-fill::before { content: "\f80e"; } -.bi-r-circle::before { content: "\f80f"; } -.bi-r-square-fill::before { content: "\f810"; } -.bi-r-square::before { content: "\f811"; } -.bi-repeat-1::before { content: "\f812"; } -.bi-repeat::before { content: "\f813"; } -.bi-rewind-btn-fill::before { content: "\f814"; } -.bi-rewind-btn::before { content: "\f815"; } -.bi-rewind-circle-fill::before { content: "\f816"; } -.bi-rewind-circle::before { content: "\f817"; } -.bi-rewind-fill::before { content: "\f818"; } -.bi-rewind::before { content: "\f819"; } -.bi-train-freight-front-fill::before { content: "\f81a"; } -.bi-train-freight-front::before { content: "\f81b"; } -.bi-train-front-fill::before { content: "\f81c"; } -.bi-train-front::before { content: "\f81d"; } -.bi-train-lightrail-front-fill::before { content: "\f81e"; } -.bi-train-lightrail-front::before { content: "\f81f"; } -.bi-truck-front-fill::before { content: "\f820"; } -.bi-truck-front::before { content: "\f821"; } -.bi-ubuntu::before { content: "\f822"; } -.bi-unindent::before { content: "\f823"; } -.bi-unity::before { content: "\f824"; } -.bi-universal-access-circle::before { content: "\f825"; } -.bi-universal-access::before { content: "\f826"; } -.bi-virus::before { content: "\f827"; } -.bi-virus2::before { content: "\f828"; } -.bi-wechat::before { content: "\f829"; } -.bi-yelp::before { content: "\f82a"; } -.bi-sign-stop-fill::before { content: "\f82b"; } -.bi-sign-stop-lights-fill::before { content: "\f82c"; } -.bi-sign-stop-lights::before { content: "\f82d"; } -.bi-sign-stop::before { content: "\f82e"; } -.bi-sign-turn-left-fill::before { content: "\f82f"; } -.bi-sign-turn-left::before { content: "\f830"; } -.bi-sign-turn-right-fill::before { content: "\f831"; } -.bi-sign-turn-right::before { content: "\f832"; } -.bi-sign-turn-slight-left-fill::before { content: "\f833"; } -.bi-sign-turn-slight-left::before { content: "\f834"; } -.bi-sign-turn-slight-right-fill::before { content: "\f835"; } -.bi-sign-turn-slight-right::before { content: "\f836"; } -.bi-sign-yield-fill::before { content: "\f837"; } -.bi-sign-yield::before { content: "\f838"; } -.bi-ev-station-fill::before { content: "\f839"; } -.bi-ev-station::before { content: "\f83a"; } -.bi-fuel-pump-diesel-fill::before { content: "\f83b"; } -.bi-fuel-pump-diesel::before { content: "\f83c"; } -.bi-fuel-pump-fill::before { content: "\f83d"; } -.bi-fuel-pump::before { content: "\f83e"; } -.bi-0-circle-fill::before { content: "\f83f"; } -.bi-0-circle::before { content: "\f840"; } -.bi-0-square-fill::before { content: "\f841"; } -.bi-0-square::before { content: "\f842"; } -.bi-rocket-fill::before { content: "\f843"; } -.bi-rocket-takeoff-fill::before { content: "\f844"; } -.bi-rocket-takeoff::before { content: "\f845"; } -.bi-rocket::before { content: "\f846"; } -.bi-stripe::before { content: "\f847"; } -.bi-subscript::before { content: "\f848"; } -.bi-superscript::before { content: "\f849"; } -.bi-trello::before { content: "\f84a"; } -.bi-envelope-at-fill::before { content: "\f84b"; } -.bi-envelope-at::before { content: "\f84c"; } -.bi-regex::before { content: "\f84d"; } -.bi-text-wrap::before { content: "\f84e"; } -.bi-sign-dead-end-fill::before { content: "\f84f"; } -.bi-sign-dead-end::before { content: "\f850"; } -.bi-sign-do-not-enter-fill::before { content: "\f851"; } -.bi-sign-do-not-enter::before { content: "\f852"; } -.bi-sign-intersection-fill::before { content: "\f853"; } -.bi-sign-intersection-side-fill::before { content: "\f854"; } -.bi-sign-intersection-side::before { content: "\f855"; } -.bi-sign-intersection-t-fill::before { content: "\f856"; } -.bi-sign-intersection-t::before { content: "\f857"; } -.bi-sign-intersection-y-fill::before { content: "\f858"; } -.bi-sign-intersection-y::before { content: "\f859"; } -.bi-sign-intersection::before { content: "\f85a"; } -.bi-sign-merge-left-fill::before { content: "\f85b"; } -.bi-sign-merge-left::before { content: "\f85c"; } -.bi-sign-merge-right-fill::before { content: "\f85d"; } -.bi-sign-merge-right::before { content: "\f85e"; } -.bi-sign-no-left-turn-fill::before { content: "\f85f"; } -.bi-sign-no-left-turn::before { content: "\f860"; } -.bi-sign-no-parking-fill::before { content: "\f861"; } -.bi-sign-no-parking::before { content: "\f862"; } -.bi-sign-no-right-turn-fill::before { content: "\f863"; } -.bi-sign-no-right-turn::before { content: "\f864"; } -.bi-sign-railroad-fill::before { content: "\f865"; } -.bi-sign-railroad::before { content: "\f866"; } -.bi-building-add::before { content: "\f867"; } -.bi-building-check::before { content: "\f868"; } -.bi-building-dash::before { content: "\f869"; } -.bi-building-down::before { content: "\f86a"; } -.bi-building-exclamation::before { content: "\f86b"; } -.bi-building-fill-add::before { content: "\f86c"; } -.bi-building-fill-check::before { content: "\f86d"; } -.bi-building-fill-dash::before { content: "\f86e"; } -.bi-building-fill-down::before { content: "\f86f"; } -.bi-building-fill-exclamation::before { content: "\f870"; } -.bi-building-fill-gear::before { content: "\f871"; } -.bi-building-fill-lock::before { content: "\f872"; } -.bi-building-fill-slash::before { content: "\f873"; } -.bi-building-fill-up::before { content: "\f874"; } -.bi-building-fill-x::before { content: "\f875"; } -.bi-building-fill::before { content: "\f876"; } -.bi-building-gear::before { content: "\f877"; } -.bi-building-lock::before { content: "\f878"; } -.bi-building-slash::before { content: "\f879"; } -.bi-building-up::before { content: "\f87a"; } -.bi-building-x::before { content: "\f87b"; } -.bi-buildings-fill::before { content: "\f87c"; } -.bi-buildings::before { content: "\f87d"; } -.bi-bus-front-fill::before { content: "\f87e"; } -.bi-bus-front::before { content: "\f87f"; } -.bi-ev-front-fill::before { content: "\f880"; } -.bi-ev-front::before { content: "\f881"; } -.bi-globe-americas::before { content: "\f882"; } -.bi-globe-asia-australia::before { content: "\f883"; } -.bi-globe-central-south-asia::before { content: "\f884"; } -.bi-globe-europe-africa::before { content: "\f885"; } -.bi-house-add-fill::before { content: "\f886"; } -.bi-house-add::before { content: "\f887"; } -.bi-house-check-fill::before { content: "\f888"; } -.bi-house-check::before { content: "\f889"; } -.bi-house-dash-fill::before { content: "\f88a"; } -.bi-house-dash::before { content: "\f88b"; } -.bi-house-down-fill::before { content: "\f88c"; } -.bi-house-down::before { content: "\f88d"; } -.bi-house-exclamation-fill::before { content: "\f88e"; } -.bi-house-exclamation::before { content: "\f88f"; } -.bi-house-gear-fill::before { content: "\f890"; } -.bi-house-gear::before { content: "\f891"; } -.bi-house-lock-fill::before { content: "\f892"; } -.bi-house-lock::before { content: "\f893"; } -.bi-house-slash-fill::before { content: "\f894"; } -.bi-house-slash::before { content: "\f895"; } -.bi-house-up-fill::before { content: "\f896"; } -.bi-house-up::before { content: "\f897"; } -.bi-house-x-fill::before { content: "\f898"; } -.bi-house-x::before { content: "\f899"; } -.bi-person-add::before { content: "\f89a"; } -.bi-person-down::before { content: "\f89b"; } -.bi-person-exclamation::before { content: "\f89c"; } -.bi-person-fill-add::before { content: "\f89d"; } -.bi-person-fill-check::before { content: "\f89e"; } -.bi-person-fill-dash::before { content: "\f89f"; } -.bi-person-fill-down::before { content: "\f8a0"; } -.bi-person-fill-exclamation::before { content: "\f8a1"; } -.bi-person-fill-gear::before { content: "\f8a2"; } -.bi-person-fill-lock::before { content: "\f8a3"; } -.bi-person-fill-slash::before { content: "\f8a4"; } -.bi-person-fill-up::before { content: "\f8a5"; } -.bi-person-fill-x::before { content: "\f8a6"; } -.bi-person-gear::before { content: "\f8a7"; } -.bi-person-lock::before { content: "\f8a8"; } -.bi-person-slash::before { content: "\f8a9"; } -.bi-person-up::before { content: "\f8aa"; } -.bi-scooter::before { content: "\f8ab"; } -.bi-taxi-front-fill::before { content: "\f8ac"; } -.bi-taxi-front::before { content: "\f8ad"; } -.bi-amd::before { content: "\f8ae"; } -.bi-database-add::before { content: "\f8af"; } -.bi-database-check::before { content: "\f8b0"; } -.bi-database-dash::before { content: "\f8b1"; } -.bi-database-down::before { content: "\f8b2"; } -.bi-database-exclamation::before { content: "\f8b3"; } -.bi-database-fill-add::before { content: "\f8b4"; } -.bi-database-fill-check::before { content: "\f8b5"; } -.bi-database-fill-dash::before { content: "\f8b6"; } -.bi-database-fill-down::before { content: "\f8b7"; } -.bi-database-fill-exclamation::before { content: "\f8b8"; } -.bi-database-fill-gear::before { content: "\f8b9"; } -.bi-database-fill-lock::before { content: "\f8ba"; } -.bi-database-fill-slash::before { content: "\f8bb"; } -.bi-database-fill-up::before { content: "\f8bc"; } -.bi-database-fill-x::before { content: "\f8bd"; } -.bi-database-fill::before { content: "\f8be"; } -.bi-database-gear::before { content: "\f8bf"; } -.bi-database-lock::before { content: "\f8c0"; } -.bi-database-slash::before { content: "\f8c1"; } -.bi-database-up::before { content: "\f8c2"; } -.bi-database-x::before { content: "\f8c3"; } -.bi-database::before { content: "\f8c4"; } -.bi-houses-fill::before { content: "\f8c5"; } -.bi-houses::before { content: "\f8c6"; } -.bi-nvidia::before { content: "\f8c7"; } -.bi-person-vcard-fill::before { content: "\f8c8"; } -.bi-person-vcard::before { content: "\f8c9"; } -.bi-sina-weibo::before { content: "\f8ca"; } -.bi-tencent-qq::before { content: "\f8cb"; } -.bi-wikipedia::before { content: "\f8cc"; } -.bi-alphabet-uppercase::before { content: "\f2a5"; } -.bi-alphabet::before { content: "\f68a"; } -.bi-amazon::before { content: "\f68d"; } -.bi-arrows-collapse-vertical::before { content: "\f690"; } -.bi-arrows-expand-vertical::before { content: "\f695"; } -.bi-arrows-vertical::before { content: "\f698"; } -.bi-arrows::before { content: "\f6a2"; } -.bi-ban-fill::before { content: "\f6a3"; } -.bi-ban::before { content: "\f6b6"; } -.bi-bing::before { content: "\f6c2"; } -.bi-cake::before { content: "\f6e0"; } -.bi-cake2::before { content: "\f6ed"; } -.bi-cookie::before { content: "\f6ee"; } -.bi-copy::before { content: "\f759"; } -.bi-crosshair::before { content: "\f769"; } -.bi-crosshair2::before { content: "\f794"; } -.bi-emoji-astonished-fill::before { content: "\f795"; } -.bi-emoji-astonished::before { content: "\f79a"; } -.bi-emoji-grimace-fill::before { content: "\f79b"; } -.bi-emoji-grimace::before { content: "\f7a0"; } -.bi-emoji-grin-fill::before { content: "\f7a1"; } -.bi-emoji-grin::before { content: "\f7a6"; } -.bi-emoji-surprise-fill::before { content: "\f7a7"; } -.bi-emoji-surprise::before { content: "\f7ac"; } -.bi-emoji-tear-fill::before { content: "\f7ad"; } -.bi-emoji-tear::before { content: "\f7b2"; } -.bi-envelope-arrow-down-fill::before { content: "\f7b3"; } -.bi-envelope-arrow-down::before { content: "\f7b8"; } -.bi-envelope-arrow-up-fill::before { content: "\f7b9"; } -.bi-envelope-arrow-up::before { content: "\f7be"; } -.bi-feather::before { content: "\f7bf"; } -.bi-feather2::before { content: "\f7c4"; } -.bi-floppy-fill::before { content: "\f7c5"; } -.bi-floppy::before { content: "\f7d8"; } -.bi-floppy2-fill::before { content: "\f7d9"; } -.bi-floppy2::before { content: "\f7e4"; } -.bi-gitlab::before { content: "\f7e5"; } -.bi-highlighter::before { content: "\f7f8"; } -.bi-marker-tip::before { content: "\f802"; } -.bi-nvme-fill::before { content: "\f803"; } -.bi-nvme::before { content: "\f80c"; } -.bi-opencollective::before { content: "\f80d"; } -.bi-pci-card-network::before { content: "\f8cd"; } -.bi-pci-card-sound::before { content: "\f8ce"; } -.bi-radar::before { content: "\f8cf"; } -.bi-send-arrow-down-fill::before { content: "\f8d0"; } -.bi-send-arrow-down::before { content: "\f8d1"; } -.bi-send-arrow-up-fill::before { content: "\f8d2"; } -.bi-send-arrow-up::before { content: "\f8d3"; } -.bi-sim-slash-fill::before { content: "\f8d4"; } -.bi-sim-slash::before { content: "\f8d5"; } -.bi-sourceforge::before { content: "\f8d6"; } -.bi-substack::before { content: "\f8d7"; } -.bi-threads-fill::before { content: "\f8d8"; } -.bi-threads::before { content: "\f8d9"; } -.bi-transparency::before { content: "\f8da"; } -.bi-twitter-x::before { content: "\f8db"; } -.bi-type-h4::before { content: "\f8dc"; } -.bi-type-h5::before { content: "\f8dd"; } -.bi-type-h6::before { content: "\f8de"; } -.bi-backpack-fill::before { content: "\f8df"; } -.bi-backpack::before { content: "\f8e0"; } -.bi-backpack2-fill::before { content: "\f8e1"; } -.bi-backpack2::before { content: "\f8e2"; } -.bi-backpack3-fill::before { content: "\f8e3"; } -.bi-backpack3::before { content: "\f8e4"; } -.bi-backpack4-fill::before { content: "\f8e5"; } -.bi-backpack4::before { content: "\f8e6"; } -.bi-brilliance::before { content: "\f8e7"; } -.bi-cake-fill::before { content: "\f8e8"; } -.bi-cake2-fill::before { content: "\f8e9"; } -.bi-duffle-fill::before { content: "\f8ea"; } -.bi-duffle::before { content: "\f8eb"; } -.bi-exposure::before { content: "\f8ec"; } -.bi-gender-neuter::before { content: "\f8ed"; } -.bi-highlights::before { content: "\f8ee"; } -.bi-luggage-fill::before { content: "\f8ef"; } -.bi-luggage::before { content: "\f8f0"; } -.bi-mailbox-flag::before { content: "\f8f1"; } -.bi-mailbox2-flag::before { content: "\f8f2"; } -.bi-noise-reduction::before { content: "\f8f3"; } -.bi-passport-fill::before { content: "\f8f4"; } -.bi-passport::before { content: "\f8f5"; } -.bi-person-arms-up::before { content: "\f8f6"; } -.bi-person-raised-hand::before { content: "\f8f7"; } -.bi-person-standing-dress::before { content: "\f8f8"; } -.bi-person-standing::before { content: "\f8f9"; } -.bi-person-walking::before { content: "\f8fa"; } -.bi-person-wheelchair::before { content: "\f8fb"; } -.bi-shadows::before { content: "\f8fc"; } -.bi-suitcase-fill::before { content: "\f8fd"; } -.bi-suitcase-lg-fill::before { content: "\f8fe"; } -.bi-suitcase-lg::before { content: "\f8ff"; } -.bi-suitcase::before { content: "\f900"; } -.bi-suitcase2-fill::before { content: "\f901"; } -.bi-suitcase2::before { content: "\f902"; } -.bi-vignette::before { content: "\f903"; } diff --git a/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/run_pecan_files/libs/bootstrap/bootstrap-icons.woff b/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/run_pecan_files/libs/bootstrap/bootstrap-icons.woff deleted file mode 100644 index dbeeb0556..000000000 Binary files a/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/run_pecan_files/libs/bootstrap/bootstrap-icons.woff and /dev/null differ diff --git a/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/run_pecan_files/libs/bootstrap/bootstrap.min.css b/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/run_pecan_files/libs/bootstrap/bootstrap.min.css deleted file mode 100644 index d6947f2ce..000000000 --- a/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/run_pecan_files/libs/bootstrap/bootstrap.min.css +++ /dev/null @@ -1,12 +0,0 @@ -/*! - * Bootstrap v5.3.1 (https://getbootstrap.com/) - * Copyright 2011-2023 The Bootstrap Authors - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) - */:root,[data-bs-theme=light]{--bs-blue: #0d6efd;--bs-indigo: #6610f2;--bs-purple: #6f42c1;--bs-pink: #d63384;--bs-red: #dc3545;--bs-orange: #fd7e14;--bs-yellow: #ffc107;--bs-green: #198754;--bs-teal: #20c997;--bs-cyan: #0dcaf0;--bs-black: #000;--bs-white: #ffffff;--bs-gray: #6c757d;--bs-gray-dark: #343a40;--bs-gray-100: #f8f9fa;--bs-gray-200: #e9ecef;--bs-gray-300: #dee2e6;--bs-gray-400: #ced4da;--bs-gray-500: #adb5bd;--bs-gray-600: #6c757d;--bs-gray-700: #495057;--bs-gray-800: #343a40;--bs-gray-900: #212529;--bs-default: #dee2e6;--bs-primary: #0d6efd;--bs-secondary: #6c757d;--bs-success: #198754;--bs-info: #0dcaf0;--bs-warning: #ffc107;--bs-danger: #dc3545;--bs-light: #f8f9fa;--bs-dark: #212529;--bs-default-rgb: 222, 226, 230;--bs-primary-rgb: 13, 110, 253;--bs-secondary-rgb: 108, 117, 125;--bs-success-rgb: 25, 135, 84;--bs-info-rgb: 13, 202, 240;--bs-warning-rgb: 255, 193, 7;--bs-danger-rgb: 220, 53, 69;--bs-light-rgb: 248, 249, 250;--bs-dark-rgb: 33, 37, 41;--bs-primary-text-emphasis: #052c65;--bs-secondary-text-emphasis: #2b2f32;--bs-success-text-emphasis: #0a3622;--bs-info-text-emphasis: #055160;--bs-warning-text-emphasis: #664d03;--bs-danger-text-emphasis: #58151c;--bs-light-text-emphasis: #495057;--bs-dark-text-emphasis: #495057;--bs-primary-bg-subtle: #cfe2ff;--bs-secondary-bg-subtle: #e2e3e5;--bs-success-bg-subtle: #d1e7dd;--bs-info-bg-subtle: #cff4fc;--bs-warning-bg-subtle: #fff3cd;--bs-danger-bg-subtle: #f8d7da;--bs-light-bg-subtle: #fcfcfd;--bs-dark-bg-subtle: #ced4da;--bs-primary-border-subtle: #9ec5fe;--bs-secondary-border-subtle: #c4c8cb;--bs-success-border-subtle: #a3cfbb;--bs-info-border-subtle: #9eeaf9;--bs-warning-border-subtle: #ffe69c;--bs-danger-border-subtle: #f1aeb5;--bs-light-border-subtle: #e9ecef;--bs-dark-border-subtle: #adb5bd;--bs-white-rgb: 255, 255, 255;--bs-black-rgb: 0, 0, 0;--bs-font-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));--bs-root-font-size: 17px;--bs-body-font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--bs-body-font-size:1rem;--bs-body-font-weight: 400;--bs-body-line-height: 1.5;--bs-body-color: #212529;--bs-body-color-rgb: 33, 37, 41;--bs-body-bg: #ffffff;--bs-body-bg-rgb: 255, 255, 255;--bs-emphasis-color: #000;--bs-emphasis-color-rgb: 0, 0, 0;--bs-secondary-color: rgba(33, 37, 41, 0.75);--bs-secondary-color-rgb: 33, 37, 41;--bs-secondary-bg: #e9ecef;--bs-secondary-bg-rgb: 233, 236, 239;--bs-tertiary-color: rgba(33, 37, 41, 0.5);--bs-tertiary-color-rgb: 33, 37, 41;--bs-tertiary-bg: #f8f9fa;--bs-tertiary-bg-rgb: 248, 249, 250;--bs-heading-color: inherit;--bs-link-color: #0d6efd;--bs-link-color-rgb: 13, 110, 253;--bs-link-decoration: underline;--bs-link-hover-color: #0a58ca;--bs-link-hover-color-rgb: 10, 88, 202;--bs-code-color: #7d12ba;--bs-highlight-bg: #fff3cd;--bs-border-width: 1px;--bs-border-style: solid;--bs-border-color: #dee2e6;--bs-border-color-translucent: rgba(0, 0, 0, 0.175);--bs-border-radius: 0.375rem;--bs-border-radius-sm: 0.25rem;--bs-border-radius-lg: 0.5rem;--bs-border-radius-xl: 1rem;--bs-border-radius-xxl: 2rem;--bs-border-radius-2xl: var(--bs-border-radius-xxl);--bs-border-radius-pill: 50rem;--bs-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);--bs-box-shadow-sm: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);--bs-box-shadow-lg: 0 1rem 3rem rgba(0, 0, 0, 0.175);--bs-box-shadow-inset: inset 0 1px 2px rgba(0, 0, 0, 0.075);--bs-focus-ring-width: 0.25rem;--bs-focus-ring-opacity: 0.25;--bs-focus-ring-color: rgba(13, 110, 253, 0.25);--bs-form-valid-color: #198754;--bs-form-valid-border-color: #198754;--bs-form-invalid-color: #dc3545;--bs-form-invalid-border-color: #dc3545}[data-bs-theme=dark]{color-scheme:dark;--bs-body-color: #dee2e6;--bs-body-color-rgb: 222, 226, 230;--bs-body-bg: #212529;--bs-body-bg-rgb: 33, 37, 41;--bs-emphasis-color: #ffffff;--bs-emphasis-color-rgb: 255, 255, 255;--bs-secondary-color: rgba(222, 226, 230, 0.75);--bs-secondary-color-rgb: 222, 226, 230;--bs-secondary-bg: #343a40;--bs-secondary-bg-rgb: 52, 58, 64;--bs-tertiary-color: rgba(222, 226, 230, 0.5);--bs-tertiary-color-rgb: 222, 226, 230;--bs-tertiary-bg: #2b3035;--bs-tertiary-bg-rgb: 43, 48, 53;--bs-primary-text-emphasis: #6ea8fe;--bs-secondary-text-emphasis: #a7acb1;--bs-success-text-emphasis: #75b798;--bs-info-text-emphasis: #6edff6;--bs-warning-text-emphasis: #ffda6a;--bs-danger-text-emphasis: #ea868f;--bs-light-text-emphasis: #f8f9fa;--bs-dark-text-emphasis: #dee2e6;--bs-primary-bg-subtle: #031633;--bs-secondary-bg-subtle: #161719;--bs-success-bg-subtle: #051b11;--bs-info-bg-subtle: #032830;--bs-warning-bg-subtle: #332701;--bs-danger-bg-subtle: #2c0b0e;--bs-light-bg-subtle: #343a40;--bs-dark-bg-subtle: #1a1d20;--bs-primary-border-subtle: #084298;--bs-secondary-border-subtle: #41464b;--bs-success-border-subtle: #0f5132;--bs-info-border-subtle: #087990;--bs-warning-border-subtle: #997404;--bs-danger-border-subtle: #842029;--bs-light-border-subtle: #495057;--bs-dark-border-subtle: #343a40;--bs-heading-color: inherit;--bs-link-color: #6ea8fe;--bs-link-hover-color: #8bb9fe;--bs-link-color-rgb: 110, 168, 254;--bs-link-hover-color-rgb: 139, 185, 254;--bs-code-color: white;--bs-border-color: #495057;--bs-border-color-translucent: rgba(255, 255, 255, 0.15);--bs-form-valid-color: #75b798;--bs-form-valid-border-color: #75b798;--bs-form-invalid-color: #ea868f;--bs-form-invalid-border-color: #ea868f}*,*::before,*::after{box-sizing:border-box}:root{font-size:var(--bs-root-font-size)}body{margin:0;font-family:var(--bs-body-font-family);font-size:var(--bs-body-font-size);font-weight:var(--bs-body-font-weight);line-height:var(--bs-body-line-height);color:var(--bs-body-color);text-align:var(--bs-body-text-align);background-color:var(--bs-body-bg);-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:rgba(0,0,0,0)}hr{margin:1rem 0;color:inherit;border:0;border-top:1px solid;opacity:.25}h6,.h6,h5,.h5,h4,.h4,h3,.h3,h2,.h2,h1,.h1{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2;color:var(--bs-heading-color)}h1,.h1{font-size:calc(1.325rem + 0.9vw)}@media(min-width: 1200px){h1,.h1{font-size:2rem}}h2,.h2{font-size:calc(1.29rem + 0.48vw)}@media(min-width: 1200px){h2,.h2{font-size:1.65rem}}h3,.h3{font-size:calc(1.27rem + 0.24vw)}@media(min-width: 1200px){h3,.h3{font-size:1.45rem}}h4,.h4{font-size:1.25rem}h5,.h5{font-size:1.1rem}h6,.h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[title]{text-decoration:underline dotted;-webkit-text-decoration:underline dotted;-moz-text-decoration:underline dotted;-ms-text-decoration:underline dotted;-o-text-decoration:underline dotted;cursor:help;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}ol,ul,dl{margin-top:0;margin-bottom:1rem}ol ol,ul ul,ol ul,ul ol{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem;padding:.625rem 1.25rem;border-left:.25rem solid #e9ecef}blockquote p:last-child,blockquote ul:last-child,blockquote ol:last-child{margin-bottom:0}b,strong{font-weight:bolder}small,.small{font-size:0.875em}mark,.mark{padding:.1875em;background-color:var(--bs-highlight-bg)}sub,sup{position:relative;font-size:0.75em;line-height:0;vertical-align:baseline}sub{bottom:-0.25em}sup{top:-0.5em}a{color:rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 1));text-decoration:underline;-webkit-text-decoration:underline;-moz-text-decoration:underline;-ms-text-decoration:underline;-o-text-decoration:underline}a:hover{--bs-link-color-rgb: var(--bs-link-hover-color-rgb)}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}pre,code,kbd,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:0.875em;color:#000;background-color:#f8f9fa;padding:.5rem;border:1px solid var(--bs-border-color, #dee2e6);border-radius:.375rem}pre code{background-color:rgba(0,0,0,0);font-size:inherit;color:inherit;word-break:normal}code{font-size:0.875em;color:var(--bs-code-color);background-color:#f8f9fa;border-radius:.375rem;padding:.125rem .25rem;word-wrap:break-word}a>code{color:inherit}kbd{padding:.4rem .4rem;font-size:0.875em;color:#fff;background-color:#212529;border-radius:.25rem}kbd kbd{padding:0;font-size:1em}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:rgba(33,37,41,.75);text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}thead,tbody,tfoot,tr,td,th{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}input,button,select,optgroup,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]:not([type=date]):not([type=datetime-local]):not([type=month]):not([type=week]):not([type=time])::-webkit-calendar-picker-indicator{display:none !important}button,[type=button],[type=reset],[type=submit]{-webkit-appearance:button}button:not(:disabled),[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:left;width:100%;padding:0;margin-bottom:.5rem;font-size:calc(1.275rem + 0.3vw);line-height:inherit}@media(min-width: 1200px){legend{font-size:1.5rem}}legend+*{clear:left}::-webkit-datetime-edit-fields-wrapper,::-webkit-datetime-edit-text,::-webkit-datetime-edit-minute,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-year-field{padding:0}::-webkit-inner-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::file-selector-button{font:inherit;-webkit-appearance:button}output{display:inline-block}iframe{border:0}summary{display:list-item;cursor:pointer}progress{vertical-align:baseline}[hidden]{display:none !important}.lead{font-size:1.25rem;font-weight:300}.display-1{font-size:calc(1.625rem + 4.5vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-1{font-size:5rem}}.display-2{font-size:calc(1.575rem + 3.9vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-2{font-size:4.5rem}}.display-3{font-size:calc(1.525rem + 3.3vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-3{font-size:4rem}}.display-4{font-size:calc(1.475rem + 2.7vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-4{font-size:3.5rem}}.display-5{font-size:calc(1.425rem + 2.1vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-5{font-size:3rem}}.display-6{font-size:calc(1.375rem + 1.5vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-6{font-size:2.5rem}}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:.5rem}.initialism{font-size:0.875em;text-transform:uppercase}.blockquote{margin-bottom:1rem;font-size:1.25rem}.blockquote>:last-child{margin-bottom:0}.blockquote-footer{margin-top:-1rem;margin-bottom:1rem;font-size:0.875em;color:#6c757d}.blockquote-footer::before{content:"— "}.img-fluid{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:#fff;border:1px solid #dee2e6;border-radius:.375rem;max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:0.875em;color:rgba(33,37,41,.75)}.container,.container-fluid,.container-xxl,.container-xl,.container-lg,.container-md,.container-sm{--bs-gutter-x: 1.5rem;--bs-gutter-y: 0;width:100%;padding-right:calc(var(--bs-gutter-x)*.5);padding-left:calc(var(--bs-gutter-x)*.5);margin-right:auto;margin-left:auto}@media(min-width: 576px){.container-sm,.container{max-width:540px}}@media(min-width: 768px){.container-md,.container-sm,.container{max-width:720px}}@media(min-width: 992px){.container-lg,.container-md,.container-sm,.container{max-width:960px}}@media(min-width: 1200px){.container-xl,.container-lg,.container-md,.container-sm,.container{max-width:1140px}}@media(min-width: 1400px){.container-xxl,.container-xl,.container-lg,.container-md,.container-sm,.container{max-width:1320px}}:root{--bs-breakpoint-xs: 0;--bs-breakpoint-sm: 576px;--bs-breakpoint-md: 768px;--bs-breakpoint-lg: 992px;--bs-breakpoint-xl: 1200px;--bs-breakpoint-xxl: 1400px}.grid{display:grid;grid-template-rows:repeat(var(--bs-rows, 1), 1fr);grid-template-columns:repeat(var(--bs-columns, 12), 1fr);gap:var(--bs-gap, 1.5rem)}.grid .g-col-1{grid-column:auto/span 1}.grid .g-col-2{grid-column:auto/span 2}.grid .g-col-3{grid-column:auto/span 3}.grid .g-col-4{grid-column:auto/span 4}.grid .g-col-5{grid-column:auto/span 5}.grid .g-col-6{grid-column:auto/span 6}.grid .g-col-7{grid-column:auto/span 7}.grid .g-col-8{grid-column:auto/span 8}.grid .g-col-9{grid-column:auto/span 9}.grid .g-col-10{grid-column:auto/span 10}.grid .g-col-11{grid-column:auto/span 11}.grid .g-col-12{grid-column:auto/span 12}.grid .g-start-1{grid-column-start:1}.grid .g-start-2{grid-column-start:2}.grid .g-start-3{grid-column-start:3}.grid .g-start-4{grid-column-start:4}.grid .g-start-5{grid-column-start:5}.grid .g-start-6{grid-column-start:6}.grid .g-start-7{grid-column-start:7}.grid .g-start-8{grid-column-start:8}.grid .g-start-9{grid-column-start:9}.grid .g-start-10{grid-column-start:10}.grid .g-start-11{grid-column-start:11}@media(min-width: 576px){.grid .g-col-sm-1{grid-column:auto/span 1}.grid .g-col-sm-2{grid-column:auto/span 2}.grid .g-col-sm-3{grid-column:auto/span 3}.grid .g-col-sm-4{grid-column:auto/span 4}.grid .g-col-sm-5{grid-column:auto/span 5}.grid .g-col-sm-6{grid-column:auto/span 6}.grid .g-col-sm-7{grid-column:auto/span 7}.grid .g-col-sm-8{grid-column:auto/span 8}.grid .g-col-sm-9{grid-column:auto/span 9}.grid .g-col-sm-10{grid-column:auto/span 10}.grid .g-col-sm-11{grid-column:auto/span 11}.grid .g-col-sm-12{grid-column:auto/span 12}.grid .g-start-sm-1{grid-column-start:1}.grid .g-start-sm-2{grid-column-start:2}.grid .g-start-sm-3{grid-column-start:3}.grid .g-start-sm-4{grid-column-start:4}.grid .g-start-sm-5{grid-column-start:5}.grid .g-start-sm-6{grid-column-start:6}.grid .g-start-sm-7{grid-column-start:7}.grid .g-start-sm-8{grid-column-start:8}.grid .g-start-sm-9{grid-column-start:9}.grid .g-start-sm-10{grid-column-start:10}.grid .g-start-sm-11{grid-column-start:11}}@media(min-width: 768px){.grid .g-col-md-1{grid-column:auto/span 1}.grid .g-col-md-2{grid-column:auto/span 2}.grid .g-col-md-3{grid-column:auto/span 3}.grid .g-col-md-4{grid-column:auto/span 4}.grid .g-col-md-5{grid-column:auto/span 5}.grid .g-col-md-6{grid-column:auto/span 6}.grid .g-col-md-7{grid-column:auto/span 7}.grid .g-col-md-8{grid-column:auto/span 8}.grid .g-col-md-9{grid-column:auto/span 9}.grid .g-col-md-10{grid-column:auto/span 10}.grid .g-col-md-11{grid-column:auto/span 11}.grid .g-col-md-12{grid-column:auto/span 12}.grid .g-start-md-1{grid-column-start:1}.grid .g-start-md-2{grid-column-start:2}.grid .g-start-md-3{grid-column-start:3}.grid .g-start-md-4{grid-column-start:4}.grid .g-start-md-5{grid-column-start:5}.grid .g-start-md-6{grid-column-start:6}.grid .g-start-md-7{grid-column-start:7}.grid .g-start-md-8{grid-column-start:8}.grid .g-start-md-9{grid-column-start:9}.grid .g-start-md-10{grid-column-start:10}.grid .g-start-md-11{grid-column-start:11}}@media(min-width: 992px){.grid .g-col-lg-1{grid-column:auto/span 1}.grid .g-col-lg-2{grid-column:auto/span 2}.grid .g-col-lg-3{grid-column:auto/span 3}.grid .g-col-lg-4{grid-column:auto/span 4}.grid .g-col-lg-5{grid-column:auto/span 5}.grid .g-col-lg-6{grid-column:auto/span 6}.grid .g-col-lg-7{grid-column:auto/span 7}.grid .g-col-lg-8{grid-column:auto/span 8}.grid .g-col-lg-9{grid-column:auto/span 9}.grid .g-col-lg-10{grid-column:auto/span 10}.grid .g-col-lg-11{grid-column:auto/span 11}.grid .g-col-lg-12{grid-column:auto/span 12}.grid .g-start-lg-1{grid-column-start:1}.grid .g-start-lg-2{grid-column-start:2}.grid .g-start-lg-3{grid-column-start:3}.grid .g-start-lg-4{grid-column-start:4}.grid .g-start-lg-5{grid-column-start:5}.grid .g-start-lg-6{grid-column-start:6}.grid .g-start-lg-7{grid-column-start:7}.grid .g-start-lg-8{grid-column-start:8}.grid .g-start-lg-9{grid-column-start:9}.grid .g-start-lg-10{grid-column-start:10}.grid .g-start-lg-11{grid-column-start:11}}@media(min-width: 1200px){.grid .g-col-xl-1{grid-column:auto/span 1}.grid .g-col-xl-2{grid-column:auto/span 2}.grid .g-col-xl-3{grid-column:auto/span 3}.grid .g-col-xl-4{grid-column:auto/span 4}.grid .g-col-xl-5{grid-column:auto/span 5}.grid .g-col-xl-6{grid-column:auto/span 6}.grid .g-col-xl-7{grid-column:auto/span 7}.grid .g-col-xl-8{grid-column:auto/span 8}.grid .g-col-xl-9{grid-column:auto/span 9}.grid .g-col-xl-10{grid-column:auto/span 10}.grid .g-col-xl-11{grid-column:auto/span 11}.grid .g-col-xl-12{grid-column:auto/span 12}.grid .g-start-xl-1{grid-column-start:1}.grid .g-start-xl-2{grid-column-start:2}.grid .g-start-xl-3{grid-column-start:3}.grid .g-start-xl-4{grid-column-start:4}.grid .g-start-xl-5{grid-column-start:5}.grid .g-start-xl-6{grid-column-start:6}.grid .g-start-xl-7{grid-column-start:7}.grid .g-start-xl-8{grid-column-start:8}.grid .g-start-xl-9{grid-column-start:9}.grid .g-start-xl-10{grid-column-start:10}.grid .g-start-xl-11{grid-column-start:11}}@media(min-width: 1400px){.grid .g-col-xxl-1{grid-column:auto/span 1}.grid .g-col-xxl-2{grid-column:auto/span 2}.grid .g-col-xxl-3{grid-column:auto/span 3}.grid .g-col-xxl-4{grid-column:auto/span 4}.grid .g-col-xxl-5{grid-column:auto/span 5}.grid .g-col-xxl-6{grid-column:auto/span 6}.grid .g-col-xxl-7{grid-column:auto/span 7}.grid .g-col-xxl-8{grid-column:auto/span 8}.grid .g-col-xxl-9{grid-column:auto/span 9}.grid .g-col-xxl-10{grid-column:auto/span 10}.grid .g-col-xxl-11{grid-column:auto/span 11}.grid .g-col-xxl-12{grid-column:auto/span 12}.grid .g-start-xxl-1{grid-column-start:1}.grid .g-start-xxl-2{grid-column-start:2}.grid .g-start-xxl-3{grid-column-start:3}.grid .g-start-xxl-4{grid-column-start:4}.grid .g-start-xxl-5{grid-column-start:5}.grid .g-start-xxl-6{grid-column-start:6}.grid .g-start-xxl-7{grid-column-start:7}.grid .g-start-xxl-8{grid-column-start:8}.grid .g-start-xxl-9{grid-column-start:9}.grid .g-start-xxl-10{grid-column-start:10}.grid .g-start-xxl-11{grid-column-start:11}}.table{--bs-table-color-type: initial;--bs-table-bg-type: initial;--bs-table-color-state: initial;--bs-table-bg-state: initial;--bs-table-color: #212529;--bs-table-bg: #ffffff;--bs-table-border-color: #dee2e6;--bs-table-accent-bg: transparent;--bs-table-striped-color: #212529;--bs-table-striped-bg: rgba(0, 0, 0, 0.05);--bs-table-active-color: #212529;--bs-table-active-bg: rgba(0, 0, 0, 0.1);--bs-table-hover-color: #212529;--bs-table-hover-bg: rgba(0, 0, 0, 0.075);width:100%;margin-bottom:1rem;vertical-align:top;border-color:var(--bs-table-border-color)}.table>:not(caption)>*>*{padding:.5rem .5rem;color:var(--bs-table-color-state, var(--bs-table-color-type, var(--bs-table-color)));background-color:var(--bs-table-bg);border-bottom-width:1px;box-shadow:inset 0 0 0 9999px var(--bs-table-bg-state, var(--bs-table-bg-type, var(--bs-table-accent-bg)))}.table>tbody{vertical-align:inherit}.table>thead{vertical-align:bottom}.table-group-divider{border-top:calc(1px*2) solid #9ba5ae}.caption-top{caption-side:top}.table-sm>:not(caption)>*>*{padding:.25rem .25rem}.table-bordered>:not(caption)>*{border-width:1px 0}.table-bordered>:not(caption)>*>*{border-width:0 1px}.table-borderless>:not(caption)>*>*{border-bottom-width:0}.table-borderless>:not(:first-child){border-top-width:0}.table-striped>tbody>tr:nth-of-type(odd)>*{--bs-table-color-type: var(--bs-table-striped-color);--bs-table-bg-type: var(--bs-table-striped-bg)}.table-striped-columns>:not(caption)>tr>:nth-child(even){--bs-table-color-type: var(--bs-table-striped-color);--bs-table-bg-type: var(--bs-table-striped-bg)}.table-active{--bs-table-color-state: var(--bs-table-active-color);--bs-table-bg-state: var(--bs-table-active-bg)}.table-hover>tbody>tr:hover>*{--bs-table-color-state: var(--bs-table-hover-color);--bs-table-bg-state: var(--bs-table-hover-bg)}.table-primary{--bs-table-color: #000;--bs-table-bg: #cfe2ff;--bs-table-border-color: #bacbe6;--bs-table-striped-bg: #c5d7f2;--bs-table-striped-color: #000;--bs-table-active-bg: #bacbe6;--bs-table-active-color: #000;--bs-table-hover-bg: #bfd1ec;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-secondary{--bs-table-color: #000;--bs-table-bg: #e2e3e5;--bs-table-border-color: #cbccce;--bs-table-striped-bg: #d7d8da;--bs-table-striped-color: #000;--bs-table-active-bg: #cbccce;--bs-table-active-color: #000;--bs-table-hover-bg: #d1d2d4;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-success{--bs-table-color: #000;--bs-table-bg: #d1e7dd;--bs-table-border-color: #bcd0c7;--bs-table-striped-bg: #c7dbd2;--bs-table-striped-color: #000;--bs-table-active-bg: #bcd0c7;--bs-table-active-color: #000;--bs-table-hover-bg: #c1d6cc;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-info{--bs-table-color: #000;--bs-table-bg: #cff4fc;--bs-table-border-color: #badce3;--bs-table-striped-bg: #c5e8ef;--bs-table-striped-color: #000;--bs-table-active-bg: #badce3;--bs-table-active-color: #000;--bs-table-hover-bg: #bfe2e9;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-warning{--bs-table-color: #000;--bs-table-bg: #fff3cd;--bs-table-border-color: #e6dbb9;--bs-table-striped-bg: #f2e7c3;--bs-table-striped-color: #000;--bs-table-active-bg: #e6dbb9;--bs-table-active-color: #000;--bs-table-hover-bg: #ece1be;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-danger{--bs-table-color: #000;--bs-table-bg: #f8d7da;--bs-table-border-color: #dfc2c4;--bs-table-striped-bg: #eccccf;--bs-table-striped-color: #000;--bs-table-active-bg: #dfc2c4;--bs-table-active-color: #000;--bs-table-hover-bg: #e5c7ca;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-light{--bs-table-color: #000;--bs-table-bg: #f8f9fa;--bs-table-border-color: #dfe0e1;--bs-table-striped-bg: #ecedee;--bs-table-striped-color: #000;--bs-table-active-bg: #dfe0e1;--bs-table-active-color: #000;--bs-table-hover-bg: #e5e6e7;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-dark{--bs-table-color: #ffffff;--bs-table-bg: #212529;--bs-table-border-color: #373b3e;--bs-table-striped-bg: #2c3034;--bs-table-striped-color: #ffffff;--bs-table-active-bg: #373b3e;--bs-table-active-color: #ffffff;--bs-table-hover-bg: #323539;--bs-table-hover-color: #ffffff;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-responsive{overflow-x:auto;-webkit-overflow-scrolling:touch}@media(max-width: 575.98px){.table-responsive-sm{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media(max-width: 767.98px){.table-responsive-md{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media(max-width: 991.98px){.table-responsive-lg{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media(max-width: 1199.98px){.table-responsive-xl{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media(max-width: 1399.98px){.table-responsive-xxl{overflow-x:auto;-webkit-overflow-scrolling:touch}}.form-label,.shiny-input-container .control-label{margin-bottom:.5rem}.col-form-label{padding-top:calc(0.375rem + 1px);padding-bottom:calc(0.375rem + 1px);margin-bottom:0;font-size:inherit;line-height:1.5}.col-form-label-lg{padding-top:calc(0.5rem + 1px);padding-bottom:calc(0.5rem + 1px);font-size:1.25rem}.col-form-label-sm{padding-top:calc(0.25rem + 1px);padding-bottom:calc(0.25rem + 1px);font-size:0.875rem}.form-text{margin-top:.25rem;font-size:0.875em;color:rgba(33,37,41,.75)}.form-control{display:block;width:100%;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#212529;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none;background-color:#fff;background-clip:padding-box;border:1px solid #dee2e6;border-radius:.375rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.form-control{transition:none}}.form-control[type=file]{overflow:hidden}.form-control[type=file]:not(:disabled):not([readonly]){cursor:pointer}.form-control:focus{color:#212529;background-color:#fff;border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-control::-webkit-date-and-time-value{min-width:85px;height:1.5em;margin:0}.form-control::-webkit-datetime-edit{display:block;padding:0}.form-control::placeholder{color:rgba(33,37,41,.75);opacity:1}.form-control:disabled{background-color:#e9ecef;opacity:1}.form-control::file-selector-button{padding:.375rem .75rem;margin:-0.375rem -0.75rem;margin-inline-end:.75rem;color:#212529;background-color:#f8f9fa;pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:1px;border-radius:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.form-control::file-selector-button{transition:none}}.form-control:hover:not(:disabled):not([readonly])::file-selector-button{background-color:#e9ecef}.form-control-plaintext{display:block;width:100%;padding:.375rem 0;margin-bottom:0;line-height:1.5;color:#212529;background-color:rgba(0,0,0,0);border:solid rgba(0,0,0,0);border-width:1px 0}.form-control-plaintext:focus{outline:0}.form-control-plaintext.form-control-sm,.form-control-plaintext.form-control-lg{padding-right:0;padding-left:0}.form-control-sm{min-height:calc(1.5em + 0.5rem + calc(1px * 2));padding:.25rem .5rem;font-size:0.875rem;border-radius:.25rem}.form-control-sm::file-selector-button{padding:.25rem .5rem;margin:-0.25rem -0.5rem;margin-inline-end:.5rem}.form-control-lg{min-height:calc(1.5em + 1rem + calc(1px * 2));padding:.5rem 1rem;font-size:1.25rem;border-radius:.5rem}.form-control-lg::file-selector-button{padding:.5rem 1rem;margin:-0.5rem -1rem;margin-inline-end:1rem}textarea.form-control{min-height:calc(1.5em + 0.75rem + calc(1px * 2))}textarea.form-control-sm{min-height:calc(1.5em + 0.5rem + calc(1px * 2))}textarea.form-control-lg{min-height:calc(1.5em + 1rem + calc(1px * 2))}.form-control-color{width:3rem;height:calc(1.5em + 0.75rem + calc(1px * 2));padding:.375rem}.form-control-color:not(:disabled):not([readonly]){cursor:pointer}.form-control-color::-moz-color-swatch{border:0 !important;border-radius:.375rem}.form-control-color::-webkit-color-swatch{border:0 !important;border-radius:.375rem}.form-control-color.form-control-sm{height:calc(1.5em + 0.5rem + calc(1px * 2))}.form-control-color.form-control-lg{height:calc(1.5em + 1rem + calc(1px * 2))}.form-select{--bs-form-select-bg-img: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e");display:block;width:100%;padding:.375rem 2.25rem .375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#212529;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none;background-color:#fff;background-image:var(--bs-form-select-bg-img),var(--bs-form-select-bg-icon, none);background-repeat:no-repeat;background-position:right .75rem center;background-size:16px 12px;border:1px solid #dee2e6;border-radius:.375rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.form-select{transition:none}}.form-select:focus{border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-select[multiple],.form-select[size]:not([size="1"]){padding-right:.75rem;background-image:none}.form-select:disabled{background-color:#e9ecef}.form-select:-moz-focusring{color:rgba(0,0,0,0);text-shadow:0 0 0 #212529}.form-select-sm{padding-top:.25rem;padding-bottom:.25rem;padding-left:.5rem;font-size:0.875rem;border-radius:.25rem}.form-select-lg{padding-top:.5rem;padding-bottom:.5rem;padding-left:1rem;font-size:1.25rem;border-radius:.5rem}[data-bs-theme=dark] .form-select{--bs-form-select-bg-img: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23dee2e6' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e")}.form-check,.shiny-input-container .checkbox,.shiny-input-container .radio{display:block;min-height:1.5rem;padding-left:0;margin-bottom:.125rem}.form-check .form-check-input,.form-check .shiny-input-container .checkbox input,.form-check .shiny-input-container .radio input,.shiny-input-container .checkbox .form-check-input,.shiny-input-container .checkbox .shiny-input-container .checkbox input,.shiny-input-container .checkbox .shiny-input-container .radio input,.shiny-input-container .radio .form-check-input,.shiny-input-container .radio .shiny-input-container .checkbox input,.shiny-input-container .radio .shiny-input-container .radio input{float:left;margin-left:0}.form-check-reverse{padding-right:0;padding-left:0;text-align:right}.form-check-reverse .form-check-input{float:right;margin-right:0;margin-left:0}.form-check-input,.shiny-input-container .checkbox input,.shiny-input-container .checkbox-inline input,.shiny-input-container .radio input,.shiny-input-container .radio-inline input{--bs-form-check-bg: #ffffff;width:1em;height:1em;margin-top:.25em;vertical-align:top;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none;background-color:var(--bs-form-check-bg);background-image:var(--bs-form-check-bg-image);background-repeat:no-repeat;background-position:center;background-size:contain;border:1px solid #dee2e6;print-color-adjust:exact}.form-check-input[type=checkbox],.shiny-input-container .checkbox input[type=checkbox],.shiny-input-container .checkbox-inline input[type=checkbox],.shiny-input-container .radio input[type=checkbox],.shiny-input-container .radio-inline input[type=checkbox]{border-radius:.25em}.form-check-input[type=radio],.shiny-input-container .checkbox input[type=radio],.shiny-input-container .checkbox-inline input[type=radio],.shiny-input-container .radio input[type=radio],.shiny-input-container .radio-inline input[type=radio]{border-radius:50%}.form-check-input:active,.shiny-input-container .checkbox input:active,.shiny-input-container .checkbox-inline input:active,.shiny-input-container .radio input:active,.shiny-input-container .radio-inline input:active{filter:brightness(90%)}.form-check-input:focus,.shiny-input-container .checkbox input:focus,.shiny-input-container .checkbox-inline input:focus,.shiny-input-container .radio input:focus,.shiny-input-container .radio-inline input:focus{border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-check-input:checked,.shiny-input-container .checkbox input:checked,.shiny-input-container .checkbox-inline input:checked,.shiny-input-container .radio input:checked,.shiny-input-container .radio-inline input:checked{background-color:#0d6efd;border-color:#0d6efd}.form-check-input:checked[type=checkbox],.shiny-input-container .checkbox input:checked[type=checkbox],.shiny-input-container .checkbox-inline input:checked[type=checkbox],.shiny-input-container .radio input:checked[type=checkbox],.shiny-input-container .radio-inline input:checked[type=checkbox]{--bs-form-check-bg-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23ffffff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='m6 10 3 3 6-6'/%3e%3c/svg%3e")}.form-check-input:checked[type=radio],.shiny-input-container .checkbox input:checked[type=radio],.shiny-input-container .checkbox-inline input:checked[type=radio],.shiny-input-container .radio input:checked[type=radio],.shiny-input-container .radio-inline input:checked[type=radio]{--bs-form-check-bg-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='2' fill='%23ffffff'/%3e%3c/svg%3e")}.form-check-input[type=checkbox]:indeterminate,.shiny-input-container .checkbox input[type=checkbox]:indeterminate,.shiny-input-container .checkbox-inline input[type=checkbox]:indeterminate,.shiny-input-container .radio input[type=checkbox]:indeterminate,.shiny-input-container .radio-inline input[type=checkbox]:indeterminate{background-color:#0d6efd;border-color:#0d6efd;--bs-form-check-bg-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23ffffff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10h8'/%3e%3c/svg%3e")}.form-check-input:disabled,.shiny-input-container .checkbox input:disabled,.shiny-input-container .checkbox-inline input:disabled,.shiny-input-container .radio input:disabled,.shiny-input-container .radio-inline input:disabled{pointer-events:none;filter:none;opacity:.5}.form-check-input[disabled]~.form-check-label,.form-check-input[disabled]~span,.form-check-input:disabled~.form-check-label,.form-check-input:disabled~span,.shiny-input-container .checkbox input[disabled]~.form-check-label,.shiny-input-container .checkbox input[disabled]~span,.shiny-input-container .checkbox input:disabled~.form-check-label,.shiny-input-container .checkbox input:disabled~span,.shiny-input-container .checkbox-inline input[disabled]~.form-check-label,.shiny-input-container .checkbox-inline input[disabled]~span,.shiny-input-container .checkbox-inline input:disabled~.form-check-label,.shiny-input-container .checkbox-inline input:disabled~span,.shiny-input-container .radio input[disabled]~.form-check-label,.shiny-input-container .radio input[disabled]~span,.shiny-input-container .radio input:disabled~.form-check-label,.shiny-input-container .radio input:disabled~span,.shiny-input-container .radio-inline input[disabled]~.form-check-label,.shiny-input-container .radio-inline input[disabled]~span,.shiny-input-container .radio-inline input:disabled~.form-check-label,.shiny-input-container .radio-inline input:disabled~span{cursor:default;opacity:.5}.form-check-label,.shiny-input-container .checkbox label,.shiny-input-container .checkbox-inline label,.shiny-input-container .radio label,.shiny-input-container .radio-inline label{cursor:pointer}.form-switch{padding-left:2.5em}.form-switch .form-check-input{--bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%280, 0, 0, 0.25%29'/%3e%3c/svg%3e");width:2em;margin-left:-2.5em;background-image:var(--bs-form-switch-bg);background-position:left center;border-radius:2em;transition:background-position .15s ease-in-out}@media(prefers-reduced-motion: reduce){.form-switch .form-check-input{transition:none}}.form-switch .form-check-input:focus{--bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%2386b7fe'/%3e%3c/svg%3e")}.form-switch .form-check-input:checked{background-position:right center;--bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23ffffff'/%3e%3c/svg%3e")}.form-switch.form-check-reverse{padding-right:2.5em;padding-left:0}.form-switch.form-check-reverse .form-check-input{margin-right:-2.5em;margin-left:0}.form-check-inline{display:inline-block;margin-right:1rem}.btn-check{position:absolute;clip:rect(0, 0, 0, 0);pointer-events:none}.btn-check[disabled]+.btn,.btn-check:disabled+.btn{pointer-events:none;filter:none;opacity:.65}[data-bs-theme=dark] .form-switch .form-check-input:not(:checked):not(:focus){--bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%28255, 255, 255, 0.25%29'/%3e%3c/svg%3e")}.form-range{width:100%;height:1.5rem;padding:0;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none;background-color:rgba(0,0,0,0)}.form-range:focus{outline:0}.form-range:focus::-webkit-slider-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(13,110,253,.25)}.form-range:focus::-moz-range-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(13,110,253,.25)}.form-range::-moz-focus-outer{border:0}.form-range::-webkit-slider-thumb{width:1rem;height:1rem;margin-top:-0.25rem;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none;background-color:#0d6efd;border:0;border-radius:1rem;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.form-range::-webkit-slider-thumb{transition:none}}.form-range::-webkit-slider-thumb:active{background-color:#b6d4fe}.form-range::-webkit-slider-runnable-track{width:100%;height:.5rem;color:rgba(0,0,0,0);cursor:pointer;background-color:#f8f9fa;border-color:rgba(0,0,0,0);border-radius:1rem}.form-range::-moz-range-thumb{width:1rem;height:1rem;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none;background-color:#0d6efd;border:0;border-radius:1rem;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.form-range::-moz-range-thumb{transition:none}}.form-range::-moz-range-thumb:active{background-color:#b6d4fe}.form-range::-moz-range-track{width:100%;height:.5rem;color:rgba(0,0,0,0);cursor:pointer;background-color:#f8f9fa;border-color:rgba(0,0,0,0);border-radius:1rem}.form-range:disabled{pointer-events:none}.form-range:disabled::-webkit-slider-thumb{background-color:rgba(33,37,41,.75)}.form-range:disabled::-moz-range-thumb{background-color:rgba(33,37,41,.75)}.form-floating{position:relative}.form-floating>.form-control,.form-floating>.form-control-plaintext,.form-floating>.form-select{height:calc(3.5rem + calc(1px * 2));min-height:calc(3.5rem + calc(1px * 2));line-height:1.25}.form-floating>label{position:absolute;top:0;left:0;z-index:2;height:100%;padding:1rem .75rem;overflow:hidden;text-align:start;text-overflow:ellipsis;white-space:nowrap;pointer-events:none;border:1px solid rgba(0,0,0,0);transform-origin:0 0;transition:opacity .1s ease-in-out,transform .1s ease-in-out}@media(prefers-reduced-motion: reduce){.form-floating>label{transition:none}}.form-floating>.form-control,.form-floating>.form-control-plaintext{padding:1rem .75rem}.form-floating>.form-control::placeholder,.form-floating>.form-control-plaintext::placeholder{color:rgba(0,0,0,0)}.form-floating>.form-control:focus,.form-floating>.form-control:not(:placeholder-shown),.form-floating>.form-control-plaintext:focus,.form-floating>.form-control-plaintext:not(:placeholder-shown){padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:-webkit-autofill,.form-floating>.form-control-plaintext:-webkit-autofill{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-select{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:focus~label,.form-floating>.form-control:not(:placeholder-shown)~label,.form-floating>.form-control-plaintext~label,.form-floating>.form-select~label{color:rgba(var(--bs-body-color-rgb), 0.65);transform:scale(0.85) translateY(-0.5rem) translateX(0.15rem)}.form-floating>.form-control:focus~label::after,.form-floating>.form-control:not(:placeholder-shown)~label::after,.form-floating>.form-control-plaintext~label::after,.form-floating>.form-select~label::after{position:absolute;inset:1rem .375rem;z-index:-1;height:1.5em;content:"";background-color:#fff;border-radius:.375rem}.form-floating>.form-control:-webkit-autofill~label{color:rgba(var(--bs-body-color-rgb), 0.65);transform:scale(0.85) translateY(-0.5rem) translateX(0.15rem)}.form-floating>.form-control-plaintext~label{border-width:1px 0}.form-floating>:disabled~label,.form-floating>.form-control:disabled~label{color:#6c757d}.form-floating>:disabled~label::after,.form-floating>.form-control:disabled~label::after{background-color:#e9ecef}.input-group{position:relative;display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;align-items:stretch;-webkit-align-items:stretch;width:100%}.input-group>.form-control,.input-group>.form-select,.input-group>.form-floating{position:relative;flex:1 1 auto;-webkit-flex:1 1 auto;width:1%;min-width:0}.input-group>.form-control:focus,.input-group>.form-select:focus,.input-group>.form-floating:focus-within{z-index:5}.input-group .btn{position:relative;z-index:2}.input-group .btn:focus{z-index:5}.input-group-text{display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:center;white-space:nowrap;background-color:#f8f9fa;border:1px solid #dee2e6;border-radius:.375rem}.input-group-lg>.form-control,.input-group-lg>.form-select,.input-group-lg>.input-group-text,.input-group-lg>.btn{padding:.5rem 1rem;font-size:1.25rem;border-radius:.5rem}.input-group-sm>.form-control,.input-group-sm>.form-select,.input-group-sm>.input-group-text,.input-group-sm>.btn{padding:.25rem .5rem;font-size:0.875rem;border-radius:.25rem}.input-group-lg>.form-select,.input-group-sm>.form-select{padding-right:3rem}.input-group:not(.has-validation)>:not(:last-child):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating),.input-group:not(.has-validation)>.dropdown-toggle:nth-last-child(n+3),.input-group:not(.has-validation)>.form-floating:not(:last-child)>.form-control,.input-group:not(.has-validation)>.form-floating:not(:last-child)>.form-select{border-top-right-radius:0;border-bottom-right-radius:0}.input-group.has-validation>:nth-last-child(n+3):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating),.input-group.has-validation>.dropdown-toggle:nth-last-child(n+4),.input-group.has-validation>.form-floating:nth-last-child(n+3)>.form-control,.input-group.has-validation>.form-floating:nth-last-child(n+3)>.form-select{border-top-right-radius:0;border-bottom-right-radius:0}.input-group>:not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback){margin-left:calc(1px*-1);border-top-left-radius:0;border-bottom-left-radius:0}.input-group>.form-floating:not(:first-child)>.form-control,.input-group>.form-floating:not(:first-child)>.form-select{border-top-left-radius:0;border-bottom-left-radius:0}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:0.875em;color:#198754}.valid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:0.875rem;color:#fff;background-color:#198754;border-radius:.375rem}.was-validated :valid~.valid-feedback,.was-validated :valid~.valid-tooltip,.is-valid~.valid-feedback,.is-valid~.valid-tooltip{display:block}.was-validated .form-control:valid,.form-control.is-valid{border-color:#198754;padding-right:calc(1.5em + 0.75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(0.375em + 0.1875rem) center;background-size:calc(0.75em + 0.375rem) calc(0.75em + 0.375rem)}.was-validated .form-control:valid:focus,.form-control.is-valid:focus{border-color:#198754;box-shadow:0 0 0 .25rem rgba(25,135,84,.25)}.was-validated textarea.form-control:valid,textarea.form-control.is-valid{padding-right:calc(1.5em + 0.75rem);background-position:top calc(0.375em + 0.1875rem) right calc(0.375em + 0.1875rem)}.was-validated .form-select:valid,.form-select.is-valid{border-color:#198754}.was-validated .form-select:valid:not([multiple]):not([size]),.was-validated .form-select:valid:not([multiple])[size="1"],.form-select.is-valid:not([multiple]):not([size]),.form-select.is-valid:not([multiple])[size="1"]{--bs-form-select-bg-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");padding-right:4.125rem;background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(0.75em + 0.375rem) calc(0.75em + 0.375rem)}.was-validated .form-select:valid:focus,.form-select.is-valid:focus{border-color:#198754;box-shadow:0 0 0 .25rem rgba(25,135,84,.25)}.was-validated .form-control-color:valid,.form-control-color.is-valid{width:calc(3rem + calc(1.5em + 0.75rem))}.was-validated .form-check-input:valid,.form-check-input.is-valid{border-color:#198754}.was-validated .form-check-input:valid:checked,.form-check-input.is-valid:checked{background-color:#198754}.was-validated .form-check-input:valid:focus,.form-check-input.is-valid:focus{box-shadow:0 0 0 .25rem rgba(25,135,84,.25)}.was-validated .form-check-input:valid~.form-check-label,.form-check-input.is-valid~.form-check-label{color:#198754}.form-check-inline .form-check-input~.valid-feedback{margin-left:.5em}.was-validated .input-group>.form-control:not(:focus):valid,.input-group>.form-control:not(:focus).is-valid,.was-validated .input-group>.form-select:not(:focus):valid,.input-group>.form-select:not(:focus).is-valid,.was-validated .input-group>.form-floating:not(:focus-within):valid,.input-group>.form-floating:not(:focus-within).is-valid{z-index:3}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:0.875em;color:#dc3545}.invalid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:0.875rem;color:#fff;background-color:#dc3545;border-radius:.375rem}.was-validated :invalid~.invalid-feedback,.was-validated :invalid~.invalid-tooltip,.is-invalid~.invalid-feedback,.is-invalid~.invalid-tooltip{display:block}.was-validated .form-control:invalid,.form-control.is-invalid{border-color:#dc3545;padding-right:calc(1.5em + 0.75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(0.375em + 0.1875rem) center;background-size:calc(0.75em + 0.375rem) calc(0.75em + 0.375rem)}.was-validated .form-control:invalid:focus,.form-control.is-invalid:focus{border-color:#dc3545;box-shadow:0 0 0 .25rem rgba(220,53,69,.25)}.was-validated textarea.form-control:invalid,textarea.form-control.is-invalid{padding-right:calc(1.5em + 0.75rem);background-position:top calc(0.375em + 0.1875rem) right calc(0.375em + 0.1875rem)}.was-validated .form-select:invalid,.form-select.is-invalid{border-color:#dc3545}.was-validated .form-select:invalid:not([multiple]):not([size]),.was-validated .form-select:invalid:not([multiple])[size="1"],.form-select.is-invalid:not([multiple]):not([size]),.form-select.is-invalid:not([multiple])[size="1"]{--bs-form-select-bg-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");padding-right:4.125rem;background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(0.75em + 0.375rem) calc(0.75em + 0.375rem)}.was-validated .form-select:invalid:focus,.form-select.is-invalid:focus{border-color:#dc3545;box-shadow:0 0 0 .25rem rgba(220,53,69,.25)}.was-validated .form-control-color:invalid,.form-control-color.is-invalid{width:calc(3rem + calc(1.5em + 0.75rem))}.was-validated .form-check-input:invalid,.form-check-input.is-invalid{border-color:#dc3545}.was-validated .form-check-input:invalid:checked,.form-check-input.is-invalid:checked{background-color:#dc3545}.was-validated .form-check-input:invalid:focus,.form-check-input.is-invalid:focus{box-shadow:0 0 0 .25rem rgba(220,53,69,.25)}.was-validated .form-check-input:invalid~.form-check-label,.form-check-input.is-invalid~.form-check-label{color:#dc3545}.form-check-inline .form-check-input~.invalid-feedback{margin-left:.5em}.was-validated .input-group>.form-control:not(:focus):invalid,.input-group>.form-control:not(:focus).is-invalid,.was-validated .input-group>.form-select:not(:focus):invalid,.input-group>.form-select:not(:focus).is-invalid,.was-validated .input-group>.form-floating:not(:focus-within):invalid,.input-group>.form-floating:not(:focus-within).is-invalid{z-index:4}.btn{--bs-btn-padding-x: 0.75rem;--bs-btn-padding-y: 0.375rem;--bs-btn-font-family: ;--bs-btn-font-size:1rem;--bs-btn-font-weight: 400;--bs-btn-line-height: 1.5;--bs-btn-color: #212529;--bs-btn-bg: transparent;--bs-btn-border-width: 1px;--bs-btn-border-color: transparent;--bs-btn-border-radius: 0.375rem;--bs-btn-hover-border-color: transparent;--bs-btn-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075);--bs-btn-disabled-opacity: 0.65;--bs-btn-focus-box-shadow: 0 0 0 0.25rem rgba(var(--bs-btn-focus-shadow-rgb), .5);display:inline-block;padding:var(--bs-btn-padding-y) var(--bs-btn-padding-x);font-family:var(--bs-btn-font-family);font-size:var(--bs-btn-font-size);font-weight:var(--bs-btn-font-weight);line-height:var(--bs-btn-line-height);color:var(--bs-btn-color);text-align:center;text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;vertical-align:middle;cursor:pointer;user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;border:var(--bs-btn-border-width) solid var(--bs-btn-border-color);border-radius:var(--bs-btn-border-radius);background-color:var(--bs-btn-bg);transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.btn{transition:none}}.btn:hover{color:var(--bs-btn-hover-color);background-color:var(--bs-btn-hover-bg);border-color:var(--bs-btn-hover-border-color)}.btn-check+.btn:hover{color:var(--bs-btn-color);background-color:var(--bs-btn-bg);border-color:var(--bs-btn-border-color)}.btn:focus-visible{color:var(--bs-btn-hover-color);background-color:var(--bs-btn-hover-bg);border-color:var(--bs-btn-hover-border-color);outline:0;box-shadow:var(--bs-btn-focus-box-shadow)}.btn-check:focus-visible+.btn{border-color:var(--bs-btn-hover-border-color);outline:0;box-shadow:var(--bs-btn-focus-box-shadow)}.btn-check:checked+.btn,:not(.btn-check)+.btn:active,.btn:first-child:active,.btn.active,.btn.show{color:var(--bs-btn-active-color);background-color:var(--bs-btn-active-bg);border-color:var(--bs-btn-active-border-color)}.btn-check:checked+.btn:focus-visible,:not(.btn-check)+.btn:active:focus-visible,.btn:first-child:active:focus-visible,.btn.active:focus-visible,.btn.show:focus-visible{box-shadow:var(--bs-btn-focus-box-shadow)}.btn:disabled,.btn.disabled,fieldset:disabled .btn{color:var(--bs-btn-disabled-color);pointer-events:none;background-color:var(--bs-btn-disabled-bg);border-color:var(--bs-btn-disabled-border-color);opacity:var(--bs-btn-disabled-opacity)}.btn-default{--bs-btn-color: #000;--bs-btn-bg: #dee2e6;--bs-btn-border-color: #dee2e6;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #e3e6ea;--bs-btn-hover-border-color: #e1e5e9;--bs-btn-focus-shadow-rgb: 189, 192, 196;--bs-btn-active-color: #000;--bs-btn-active-bg: #e5e8eb;--bs-btn-active-border-color: #e1e5e9;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #000;--bs-btn-disabled-bg: #dee2e6;--bs-btn-disabled-border-color: #dee2e6}.btn-primary{--bs-btn-color: #ffffff;--bs-btn-bg: #0d6efd;--bs-btn-border-color: #0d6efd;--bs-btn-hover-color: #ffffff;--bs-btn-hover-bg: #0b5ed7;--bs-btn-hover-border-color: #0a58ca;--bs-btn-focus-shadow-rgb: 49, 132, 253;--bs-btn-active-color: #ffffff;--bs-btn-active-bg: #0a58ca;--bs-btn-active-border-color: #0a53be;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #ffffff;--bs-btn-disabled-bg: #0d6efd;--bs-btn-disabled-border-color: #0d6efd}.btn-secondary{--bs-btn-color: #ffffff;--bs-btn-bg: #6c757d;--bs-btn-border-color: #6c757d;--bs-btn-hover-color: #ffffff;--bs-btn-hover-bg: #5c636a;--bs-btn-hover-border-color: #565e64;--bs-btn-focus-shadow-rgb: 130, 138, 145;--bs-btn-active-color: #ffffff;--bs-btn-active-bg: #565e64;--bs-btn-active-border-color: #51585e;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #ffffff;--bs-btn-disabled-bg: #6c757d;--bs-btn-disabled-border-color: #6c757d}.btn-success{--bs-btn-color: #ffffff;--bs-btn-bg: #198754;--bs-btn-border-color: #198754;--bs-btn-hover-color: #ffffff;--bs-btn-hover-bg: #157347;--bs-btn-hover-border-color: #146c43;--bs-btn-focus-shadow-rgb: 60, 153, 110;--bs-btn-active-color: #ffffff;--bs-btn-active-bg: #146c43;--bs-btn-active-border-color: #13653f;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #ffffff;--bs-btn-disabled-bg: #198754;--bs-btn-disabled-border-color: #198754}.btn-info{--bs-btn-color: #000;--bs-btn-bg: #0dcaf0;--bs-btn-border-color: #0dcaf0;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #31d2f2;--bs-btn-hover-border-color: #25cff2;--bs-btn-focus-shadow-rgb: 11, 172, 204;--bs-btn-active-color: #000;--bs-btn-active-bg: #3dd5f3;--bs-btn-active-border-color: #25cff2;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #000;--bs-btn-disabled-bg: #0dcaf0;--bs-btn-disabled-border-color: #0dcaf0}.btn-warning{--bs-btn-color: #000;--bs-btn-bg: #ffc107;--bs-btn-border-color: #ffc107;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #ffca2c;--bs-btn-hover-border-color: #ffc720;--bs-btn-focus-shadow-rgb: 217, 164, 6;--bs-btn-active-color: #000;--bs-btn-active-bg: #ffcd39;--bs-btn-active-border-color: #ffc720;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #000;--bs-btn-disabled-bg: #ffc107;--bs-btn-disabled-border-color: #ffc107}.btn-danger{--bs-btn-color: #ffffff;--bs-btn-bg: #dc3545;--bs-btn-border-color: #dc3545;--bs-btn-hover-color: #ffffff;--bs-btn-hover-bg: #bb2d3b;--bs-btn-hover-border-color: #b02a37;--bs-btn-focus-shadow-rgb: 225, 83, 97;--bs-btn-active-color: #ffffff;--bs-btn-active-bg: #b02a37;--bs-btn-active-border-color: #a52834;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #ffffff;--bs-btn-disabled-bg: #dc3545;--bs-btn-disabled-border-color: #dc3545}.btn-light{--bs-btn-color: #000;--bs-btn-bg: #f8f9fa;--bs-btn-border-color: #f8f9fa;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #d3d4d5;--bs-btn-hover-border-color: #c6c7c8;--bs-btn-focus-shadow-rgb: 211, 212, 213;--bs-btn-active-color: #000;--bs-btn-active-bg: #c6c7c8;--bs-btn-active-border-color: #babbbc;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #000;--bs-btn-disabled-bg: #f8f9fa;--bs-btn-disabled-border-color: #f8f9fa}.btn-dark{--bs-btn-color: #ffffff;--bs-btn-bg: #212529;--bs-btn-border-color: #212529;--bs-btn-hover-color: #ffffff;--bs-btn-hover-bg: #424649;--bs-btn-hover-border-color: #373b3e;--bs-btn-focus-shadow-rgb: 66, 70, 73;--bs-btn-active-color: #ffffff;--bs-btn-active-bg: #4d5154;--bs-btn-active-border-color: #373b3e;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #ffffff;--bs-btn-disabled-bg: #212529;--bs-btn-disabled-border-color: #212529}.btn-outline-default{--bs-btn-color: #dee2e6;--bs-btn-border-color: #dee2e6;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #dee2e6;--bs-btn-hover-border-color: #dee2e6;--bs-btn-focus-shadow-rgb: 222, 226, 230;--bs-btn-active-color: #000;--bs-btn-active-bg: #dee2e6;--bs-btn-active-border-color: #dee2e6;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #dee2e6;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #dee2e6;--bs-btn-bg: transparent;--bs-gradient: none}.btn-outline-primary{--bs-btn-color: #0d6efd;--bs-btn-border-color: #0d6efd;--bs-btn-hover-color: #ffffff;--bs-btn-hover-bg: #0d6efd;--bs-btn-hover-border-color: #0d6efd;--bs-btn-focus-shadow-rgb: 13, 110, 253;--bs-btn-active-color: #ffffff;--bs-btn-active-bg: #0d6efd;--bs-btn-active-border-color: #0d6efd;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #0d6efd;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #0d6efd;--bs-btn-bg: transparent;--bs-gradient: none}.btn-outline-secondary{--bs-btn-color: #6c757d;--bs-btn-border-color: #6c757d;--bs-btn-hover-color: #ffffff;--bs-btn-hover-bg: #6c757d;--bs-btn-hover-border-color: #6c757d;--bs-btn-focus-shadow-rgb: 108, 117, 125;--bs-btn-active-color: #ffffff;--bs-btn-active-bg: #6c757d;--bs-btn-active-border-color: #6c757d;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #6c757d;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #6c757d;--bs-btn-bg: transparent;--bs-gradient: none}.btn-outline-success{--bs-btn-color: #198754;--bs-btn-border-color: #198754;--bs-btn-hover-color: #ffffff;--bs-btn-hover-bg: #198754;--bs-btn-hover-border-color: #198754;--bs-btn-focus-shadow-rgb: 25, 135, 84;--bs-btn-active-color: #ffffff;--bs-btn-active-bg: #198754;--bs-btn-active-border-color: #198754;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #198754;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #198754;--bs-btn-bg: transparent;--bs-gradient: none}.btn-outline-info{--bs-btn-color: #0dcaf0;--bs-btn-border-color: #0dcaf0;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #0dcaf0;--bs-btn-hover-border-color: #0dcaf0;--bs-btn-focus-shadow-rgb: 13, 202, 240;--bs-btn-active-color: #000;--bs-btn-active-bg: #0dcaf0;--bs-btn-active-border-color: #0dcaf0;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #0dcaf0;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #0dcaf0;--bs-btn-bg: transparent;--bs-gradient: none}.btn-outline-warning{--bs-btn-color: #ffc107;--bs-btn-border-color: #ffc107;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #ffc107;--bs-btn-hover-border-color: #ffc107;--bs-btn-focus-shadow-rgb: 255, 193, 7;--bs-btn-active-color: #000;--bs-btn-active-bg: #ffc107;--bs-btn-active-border-color: #ffc107;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #ffc107;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #ffc107;--bs-btn-bg: transparent;--bs-gradient: none}.btn-outline-danger{--bs-btn-color: #dc3545;--bs-btn-border-color: #dc3545;--bs-btn-hover-color: #ffffff;--bs-btn-hover-bg: #dc3545;--bs-btn-hover-border-color: #dc3545;--bs-btn-focus-shadow-rgb: 220, 53, 69;--bs-btn-active-color: #ffffff;--bs-btn-active-bg: #dc3545;--bs-btn-active-border-color: #dc3545;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #dc3545;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #dc3545;--bs-btn-bg: transparent;--bs-gradient: none}.btn-outline-light{--bs-btn-color: #f8f9fa;--bs-btn-border-color: #f8f9fa;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #f8f9fa;--bs-btn-hover-border-color: #f8f9fa;--bs-btn-focus-shadow-rgb: 248, 249, 250;--bs-btn-active-color: #000;--bs-btn-active-bg: #f8f9fa;--bs-btn-active-border-color: #f8f9fa;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #f8f9fa;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #f8f9fa;--bs-btn-bg: transparent;--bs-gradient: none}.btn-outline-dark{--bs-btn-color: #212529;--bs-btn-border-color: #212529;--bs-btn-hover-color: #ffffff;--bs-btn-hover-bg: #212529;--bs-btn-hover-border-color: #212529;--bs-btn-focus-shadow-rgb: 33, 37, 41;--bs-btn-active-color: #ffffff;--bs-btn-active-bg: #212529;--bs-btn-active-border-color: #212529;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #212529;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #212529;--bs-btn-bg: transparent;--bs-gradient: none}.btn-link{--bs-btn-font-weight: 400;--bs-btn-color: #0d6efd;--bs-btn-bg: transparent;--bs-btn-border-color: transparent;--bs-btn-hover-color: #0a58ca;--bs-btn-hover-border-color: transparent;--bs-btn-active-color: #0a58ca;--bs-btn-active-border-color: transparent;--bs-btn-disabled-color: #6c757d;--bs-btn-disabled-border-color: transparent;--bs-btn-box-shadow: 0 0 0 #000;--bs-btn-focus-shadow-rgb: 49, 132, 253;text-decoration:underline;-webkit-text-decoration:underline;-moz-text-decoration:underline;-ms-text-decoration:underline;-o-text-decoration:underline}.btn-link:focus-visible{color:var(--bs-btn-color)}.btn-link:hover{color:var(--bs-btn-hover-color)}.btn-lg,.btn-group-lg>.btn{--bs-btn-padding-y: 0.5rem;--bs-btn-padding-x: 1rem;--bs-btn-font-size:1.25rem;--bs-btn-border-radius: 0.5rem}.btn-sm,.btn-group-sm>.btn{--bs-btn-padding-y: 0.25rem;--bs-btn-padding-x: 0.5rem;--bs-btn-font-size:0.875rem;--bs-btn-border-radius: 0.25rem}.fade{transition:opacity .15s linear}@media(prefers-reduced-motion: reduce){.fade{transition:none}}.fade:not(.show){opacity:0}.collapse:not(.show){display:none}.collapsing{height:0;overflow:hidden;transition:height .2s ease}@media(prefers-reduced-motion: reduce){.collapsing{transition:none}}.collapsing.collapse-horizontal{width:0;height:auto;transition:width .35s ease}@media(prefers-reduced-motion: reduce){.collapsing.collapse-horizontal{transition:none}}.dropup,.dropend,.dropdown,.dropstart,.dropup-center,.dropdown-center{position:relative}.dropdown-toggle{white-space:nowrap}.dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid rgba(0,0,0,0);border-bottom:0;border-left:.3em solid rgba(0,0,0,0)}.dropdown-toggle:empty::after{margin-left:0}.dropdown-menu{--bs-dropdown-zindex: 1000;--bs-dropdown-min-width: 10rem;--bs-dropdown-padding-x: 0;--bs-dropdown-padding-y: 0.5rem;--bs-dropdown-spacer: 0.125rem;--bs-dropdown-font-size:1rem;--bs-dropdown-color: #212529;--bs-dropdown-bg: #ffffff;--bs-dropdown-border-color: rgba(0, 0, 0, 0.175);--bs-dropdown-border-radius: 0.375rem;--bs-dropdown-border-width: 1px;--bs-dropdown-inner-border-radius: calc(0.375rem - 1px);--bs-dropdown-divider-bg: rgba(0, 0, 0, 0.175);--bs-dropdown-divider-margin-y: 0.5rem;--bs-dropdown-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);--bs-dropdown-link-color: #212529;--bs-dropdown-link-hover-color: #212529;--bs-dropdown-link-hover-bg: #f8f9fa;--bs-dropdown-link-active-color: #ffffff;--bs-dropdown-link-active-bg: #0d6efd;--bs-dropdown-link-disabled-color: rgba(33, 37, 41, 0.5);--bs-dropdown-item-padding-x: 1rem;--bs-dropdown-item-padding-y: 0.25rem;--bs-dropdown-header-color: #6c757d;--bs-dropdown-header-padding-x: 1rem;--bs-dropdown-header-padding-y: 0.5rem;position:absolute;z-index:var(--bs-dropdown-zindex);display:none;min-width:var(--bs-dropdown-min-width);padding:var(--bs-dropdown-padding-y) var(--bs-dropdown-padding-x);margin:0;font-size:var(--bs-dropdown-font-size);color:var(--bs-dropdown-color);text-align:left;list-style:none;background-color:var(--bs-dropdown-bg);background-clip:padding-box;border:var(--bs-dropdown-border-width) solid var(--bs-dropdown-border-color);border-radius:var(--bs-dropdown-border-radius)}.dropdown-menu[data-bs-popper]{top:100%;left:0;margin-top:var(--bs-dropdown-spacer)}.dropdown-menu-start{--bs-position: start}.dropdown-menu-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-end{--bs-position: end}.dropdown-menu-end[data-bs-popper]{right:0;left:auto}@media(min-width: 576px){.dropdown-menu-sm-start{--bs-position: start}.dropdown-menu-sm-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-sm-end{--bs-position: end}.dropdown-menu-sm-end[data-bs-popper]{right:0;left:auto}}@media(min-width: 768px){.dropdown-menu-md-start{--bs-position: start}.dropdown-menu-md-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-md-end{--bs-position: end}.dropdown-menu-md-end[data-bs-popper]{right:0;left:auto}}@media(min-width: 992px){.dropdown-menu-lg-start{--bs-position: start}.dropdown-menu-lg-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-lg-end{--bs-position: end}.dropdown-menu-lg-end[data-bs-popper]{right:0;left:auto}}@media(min-width: 1200px){.dropdown-menu-xl-start{--bs-position: start}.dropdown-menu-xl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xl-end{--bs-position: end}.dropdown-menu-xl-end[data-bs-popper]{right:0;left:auto}}@media(min-width: 1400px){.dropdown-menu-xxl-start{--bs-position: start}.dropdown-menu-xxl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xxl-end{--bs-position: end}.dropdown-menu-xxl-end[data-bs-popper]{right:0;left:auto}}.dropup .dropdown-menu[data-bs-popper]{top:auto;bottom:100%;margin-top:0;margin-bottom:var(--bs-dropdown-spacer)}.dropup .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid rgba(0,0,0,0);border-bottom:.3em solid;border-left:.3em solid rgba(0,0,0,0)}.dropup .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-menu[data-bs-popper]{top:0;right:auto;left:100%;margin-top:0;margin-left:var(--bs-dropdown-spacer)}.dropend .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid rgba(0,0,0,0);border-right:0;border-bottom:.3em solid rgba(0,0,0,0);border-left:.3em solid}.dropend .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-toggle::after{vertical-align:0}.dropstart .dropdown-menu[data-bs-popper]{top:0;right:100%;left:auto;margin-top:0;margin-right:var(--bs-dropdown-spacer)}.dropstart .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:""}.dropstart .dropdown-toggle::after{display:none}.dropstart .dropdown-toggle::before{display:inline-block;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid rgba(0,0,0,0);border-right:.3em solid;border-bottom:.3em solid rgba(0,0,0,0)}.dropstart .dropdown-toggle:empty::after{margin-left:0}.dropstart .dropdown-toggle::before{vertical-align:0}.dropdown-divider{height:0;margin:var(--bs-dropdown-divider-margin-y) 0;overflow:hidden;border-top:1px solid var(--bs-dropdown-divider-bg);opacity:1}.dropdown-item{display:block;width:100%;padding:var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x);clear:both;font-weight:400;color:var(--bs-dropdown-link-color);text-align:inherit;text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;white-space:nowrap;background-color:rgba(0,0,0,0);border:0;border-radius:var(--bs-dropdown-item-border-radius, 0)}.dropdown-item:hover,.dropdown-item:focus{color:var(--bs-dropdown-link-hover-color);background-color:var(--bs-dropdown-link-hover-bg)}.dropdown-item.active,.dropdown-item:active{color:var(--bs-dropdown-link-active-color);text-decoration:none;background-color:var(--bs-dropdown-link-active-bg)}.dropdown-item.disabled,.dropdown-item:disabled{color:var(--bs-dropdown-link-disabled-color);pointer-events:none;background-color:rgba(0,0,0,0)}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:var(--bs-dropdown-header-padding-y) var(--bs-dropdown-header-padding-x);margin-bottom:0;font-size:0.875rem;color:var(--bs-dropdown-header-color);white-space:nowrap}.dropdown-item-text{display:block;padding:var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x);color:var(--bs-dropdown-link-color)}.dropdown-menu-dark{--bs-dropdown-color: #dee2e6;--bs-dropdown-bg: #343a40;--bs-dropdown-border-color: rgba(0, 0, 0, 0.175);--bs-dropdown-box-shadow: ;--bs-dropdown-link-color: #dee2e6;--bs-dropdown-link-hover-color: #ffffff;--bs-dropdown-divider-bg: rgba(0, 0, 0, 0.175);--bs-dropdown-link-hover-bg: rgba(255, 255, 255, 0.15);--bs-dropdown-link-active-color: #ffffff;--bs-dropdown-link-active-bg: #0d6efd;--bs-dropdown-link-disabled-color: #adb5bd;--bs-dropdown-header-color: #adb5bd}.btn-group,.btn-group-vertical{position:relative;display:inline-flex;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;flex:1 1 auto;-webkit-flex:1 1 auto}.btn-group>.btn-check:checked+.btn,.btn-group>.btn-check:focus+.btn,.btn-group>.btn:hover,.btn-group>.btn:focus,.btn-group>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn-check:checked+.btn,.btn-group-vertical>.btn-check:focus+.btn,.btn-group-vertical>.btn:hover,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn.active{z-index:1}.btn-toolbar{display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;justify-content:flex-start;-webkit-justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group{border-radius:.375rem}.btn-group>:not(.btn-check:first-child)+.btn,.btn-group>.btn-group:not(:first-child){margin-left:calc(1px*-1)}.btn-group>.btn:not(:last-child):not(.dropdown-toggle),.btn-group>.btn.dropdown-toggle-split:first-child,.btn-group>.btn-group:not(:last-child)>.btn{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:nth-child(n+3),.btn-group>:not(.btn-check)+.btn,.btn-group>.btn-group:not(:first-child)>.btn{border-top-left-radius:0;border-bottom-left-radius:0}.dropdown-toggle-split{padding-right:.5625rem;padding-left:.5625rem}.dropdown-toggle-split::after,.dropup .dropdown-toggle-split::after,.dropend .dropdown-toggle-split::after{margin-left:0}.dropstart .dropdown-toggle-split::before{margin-right:0}.btn-sm+.dropdown-toggle-split,.btn-group-sm>.btn+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-lg+.dropdown-toggle-split,.btn-group-lg>.btn+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.btn-group-vertical{flex-direction:column;-webkit-flex-direction:column;align-items:flex-start;-webkit-align-items:flex-start;justify-content:center;-webkit-justify-content:center}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group{width:100%}.btn-group-vertical>.btn:not(:first-child),.btn-group-vertical>.btn-group:not(:first-child){margin-top:calc(1px*-1)}.btn-group-vertical>.btn:not(:last-child):not(.dropdown-toggle),.btn-group-vertical>.btn-group:not(:last-child)>.btn{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn~.btn,.btn-group-vertical>.btn-group:not(:first-child)>.btn{border-top-left-radius:0;border-top-right-radius:0}.nav{--bs-nav-link-padding-x: 1rem;--bs-nav-link-padding-y: 0.5rem;--bs-nav-link-font-weight: ;--bs-nav-link-color: #0d6efd;--bs-nav-link-hover-color: #0a58ca;--bs-nav-link-disabled-color: rgba(33, 37, 41, 0.75);display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:var(--bs-nav-link-padding-y) var(--bs-nav-link-padding-x);font-size:var(--bs-nav-link-font-size);font-weight:var(--bs-nav-link-font-weight);color:var(--bs-nav-link-color);text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;background:none;border:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out}@media(prefers-reduced-motion: reduce){.nav-link{transition:none}}.nav-link:hover,.nav-link:focus{color:var(--bs-nav-link-hover-color)}.nav-link:focus-visible{outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.nav-link.disabled,.nav-link:disabled{color:var(--bs-nav-link-disabled-color);pointer-events:none;cursor:default}.nav-tabs{--bs-nav-tabs-border-width: 1px;--bs-nav-tabs-border-color: #dee2e6;--bs-nav-tabs-border-radius: 0.375rem;--bs-nav-tabs-link-hover-border-color: #e9ecef #e9ecef #dee2e6;--bs-nav-tabs-link-active-color: #000;--bs-nav-tabs-link-active-bg: #ffffff;--bs-nav-tabs-link-active-border-color: #dee2e6 #dee2e6 #ffffff;border-bottom:var(--bs-nav-tabs-border-width) solid var(--bs-nav-tabs-border-color)}.nav-tabs .nav-link{margin-bottom:calc(-1*var(--bs-nav-tabs-border-width));border:var(--bs-nav-tabs-border-width) solid rgba(0,0,0,0);border-top-left-radius:var(--bs-nav-tabs-border-radius);border-top-right-radius:var(--bs-nav-tabs-border-radius)}.nav-tabs .nav-link:hover,.nav-tabs .nav-link:focus{isolation:isolate;border-color:var(--bs-nav-tabs-link-hover-border-color)}.nav-tabs .nav-link.active,.nav-tabs .nav-item.show .nav-link{color:var(--bs-nav-tabs-link-active-color);background-color:var(--bs-nav-tabs-link-active-bg);border-color:var(--bs-nav-tabs-link-active-border-color)}.nav-tabs .dropdown-menu{margin-top:calc(-1*var(--bs-nav-tabs-border-width));border-top-left-radius:0;border-top-right-radius:0}.nav-pills{--bs-nav-pills-border-radius: 0.375rem;--bs-nav-pills-link-active-color: #ffffff;--bs-nav-pills-link-active-bg: #0d6efd}.nav-pills .nav-link{border-radius:var(--bs-nav-pills-border-radius)}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:var(--bs-nav-pills-link-active-color);background-color:var(--bs-nav-pills-link-active-bg)}.nav-underline{--bs-nav-underline-gap: 1rem;--bs-nav-underline-border-width: 0.125rem;--bs-nav-underline-link-active-color: #000;gap:var(--bs-nav-underline-gap)}.nav-underline .nav-link{padding-right:0;padding-left:0;border-bottom:var(--bs-nav-underline-border-width) solid rgba(0,0,0,0)}.nav-underline .nav-link:hover,.nav-underline .nav-link:focus{border-bottom-color:currentcolor}.nav-underline .nav-link.active,.nav-underline .show>.nav-link{font-weight:700;color:var(--bs-nav-underline-link-active-color);border-bottom-color:currentcolor}.nav-fill>.nav-link,.nav-fill .nav-item{flex:1 1 auto;-webkit-flex:1 1 auto;text-align:center}.nav-justified>.nav-link,.nav-justified .nav-item{flex-basis:0;-webkit-flex-basis:0;flex-grow:1;-webkit-flex-grow:1;text-align:center}.nav-fill .nav-item .nav-link,.nav-justified .nav-item .nav-link{width:100%}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{--bs-navbar-padding-x: 0;--bs-navbar-padding-y: 0.5rem;--bs-navbar-color: #fdfefe;--bs-navbar-hover-color: rgba(253, 254, 255, 0.8);--bs-navbar-disabled-color: rgba(253, 254, 254, 0.75);--bs-navbar-active-color: #fdfeff;--bs-navbar-brand-padding-y: 0.3125rem;--bs-navbar-brand-margin-end: 1rem;--bs-navbar-brand-font-size: 1.25rem;--bs-navbar-brand-color: #fdfefe;--bs-navbar-brand-hover-color: #fdfeff;--bs-navbar-nav-link-padding-x: 0.5rem;--bs-navbar-toggler-padding-y: 0.25;--bs-navbar-toggler-padding-x: 0;--bs-navbar-toggler-font-size: 1.25rem;--bs-navbar-toggler-icon-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='%23fdfefe' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e");--bs-navbar-toggler-border-color: rgba(253, 254, 254, 0);--bs-navbar-toggler-border-radius: 0.375rem;--bs-navbar-toggler-focus-width: 0.25rem;--bs-navbar-toggler-transition: box-shadow 0.15s ease-in-out;position:relative;display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;align-items:center;-webkit-align-items:center;justify-content:space-between;-webkit-justify-content:space-between;padding:var(--bs-navbar-padding-y) var(--bs-navbar-padding-x)}.navbar>.container,.navbar>.container-fluid,.navbar>.container-sm,.navbar>.container-md,.navbar>.container-lg,.navbar>.container-xl,.navbar>.container-xxl{display:flex;display:-webkit-flex;flex-wrap:inherit;-webkit-flex-wrap:inherit;align-items:center;-webkit-align-items:center;justify-content:space-between;-webkit-justify-content:space-between}.navbar-brand{padding-top:var(--bs-navbar-brand-padding-y);padding-bottom:var(--bs-navbar-brand-padding-y);margin-right:var(--bs-navbar-brand-margin-end);font-size:var(--bs-navbar-brand-font-size);color:var(--bs-navbar-brand-color);text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;white-space:nowrap}.navbar-brand:hover,.navbar-brand:focus{color:var(--bs-navbar-brand-hover-color)}.navbar-nav{--bs-nav-link-padding-x: 0;--bs-nav-link-padding-y: 0.5rem;--bs-nav-link-font-weight: ;--bs-nav-link-color: var(--bs-navbar-color);--bs-nav-link-hover-color: var(--bs-navbar-hover-color);--bs-nav-link-disabled-color: var(--bs-navbar-disabled-color);display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link.active,.navbar-nav .nav-link.show{color:var(--bs-navbar-active-color)}.navbar-nav .dropdown-menu{position:static}.navbar-text{padding-top:.5rem;padding-bottom:.5rem;color:var(--bs-navbar-color)}.navbar-text a,.navbar-text a:hover,.navbar-text a:focus{color:var(--bs-navbar-active-color)}.navbar-collapse{flex-basis:100%;-webkit-flex-basis:100%;flex-grow:1;-webkit-flex-grow:1;align-items:center;-webkit-align-items:center}.navbar-toggler{padding:var(--bs-navbar-toggler-padding-y) var(--bs-navbar-toggler-padding-x);font-size:var(--bs-navbar-toggler-font-size);line-height:1;color:var(--bs-navbar-color);background-color:rgba(0,0,0,0);border:var(--bs-border-width) solid var(--bs-navbar-toggler-border-color);border-radius:var(--bs-navbar-toggler-border-radius);transition:var(--bs-navbar-toggler-transition)}@media(prefers-reduced-motion: reduce){.navbar-toggler{transition:none}}.navbar-toggler:hover{text-decoration:none}.navbar-toggler:focus{text-decoration:none;outline:0;box-shadow:0 0 0 var(--bs-navbar-toggler-focus-width)}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;background-image:var(--bs-navbar-toggler-icon-bg);background-repeat:no-repeat;background-position:center;background-size:100%}.navbar-nav-scroll{max-height:var(--bs-scroll-height, 75vh);overflow-y:auto}@media(min-width: 576px){.navbar-expand-sm{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand-sm .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-sm .navbar-nav-scroll{overflow:visible}.navbar-expand-sm .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}.navbar-expand-sm .offcanvas{position:static;z-index:auto;flex-grow:1;-webkit-flex-grow:1;width:auto !important;height:auto !important;visibility:visible !important;background-color:rgba(0,0,0,0) !important;border:0 !important;transform:none !important;transition:none}.navbar-expand-sm .offcanvas .offcanvas-header{display:none}.navbar-expand-sm .offcanvas .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}}@media(min-width: 768px){.navbar-expand-md{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand-md .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-md .navbar-nav-scroll{overflow:visible}.navbar-expand-md .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}.navbar-expand-md .offcanvas{position:static;z-index:auto;flex-grow:1;-webkit-flex-grow:1;width:auto !important;height:auto !important;visibility:visible !important;background-color:rgba(0,0,0,0) !important;border:0 !important;transform:none !important;transition:none}.navbar-expand-md .offcanvas .offcanvas-header{display:none}.navbar-expand-md .offcanvas .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}}@media(min-width: 992px){.navbar-expand-lg{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand-lg .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-lg .navbar-nav-scroll{overflow:visible}.navbar-expand-lg .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}.navbar-expand-lg .offcanvas{position:static;z-index:auto;flex-grow:1;-webkit-flex-grow:1;width:auto !important;height:auto !important;visibility:visible !important;background-color:rgba(0,0,0,0) !important;border:0 !important;transform:none !important;transition:none}.navbar-expand-lg .offcanvas .offcanvas-header{display:none}.navbar-expand-lg .offcanvas .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}}@media(min-width: 1200px){.navbar-expand-xl{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand-xl .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-xl .navbar-nav-scroll{overflow:visible}.navbar-expand-xl .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}.navbar-expand-xl .offcanvas{position:static;z-index:auto;flex-grow:1;-webkit-flex-grow:1;width:auto !important;height:auto !important;visibility:visible !important;background-color:rgba(0,0,0,0) !important;border:0 !important;transform:none !important;transition:none}.navbar-expand-xl .offcanvas .offcanvas-header{display:none}.navbar-expand-xl .offcanvas .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}}@media(min-width: 1400px){.navbar-expand-xxl{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand-xxl .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand-xxl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xxl .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-xxl .navbar-nav-scroll{overflow:visible}.navbar-expand-xxl .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand-xxl .navbar-toggler{display:none}.navbar-expand-xxl .offcanvas{position:static;z-index:auto;flex-grow:1;-webkit-flex-grow:1;width:auto !important;height:auto !important;visibility:visible !important;background-color:rgba(0,0,0,0) !important;border:0 !important;transform:none !important;transition:none}.navbar-expand-xxl .offcanvas .offcanvas-header{display:none}.navbar-expand-xxl .offcanvas .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}}.navbar-expand{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand .navbar-nav-scroll{overflow:visible}.navbar-expand .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-expand .offcanvas{position:static;z-index:auto;flex-grow:1;-webkit-flex-grow:1;width:auto !important;height:auto !important;visibility:visible !important;background-color:rgba(0,0,0,0) !important;border:0 !important;transform:none !important;transition:none}.navbar-expand .offcanvas .offcanvas-header{display:none}.navbar-expand .offcanvas .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}.navbar-dark,.navbar[data-bs-theme=dark]{--bs-navbar-color: #fdfefe;--bs-navbar-hover-color: rgba(253, 254, 255, 0.8);--bs-navbar-disabled-color: rgba(253, 254, 254, 0.75);--bs-navbar-active-color: #fdfeff;--bs-navbar-brand-color: #fdfefe;--bs-navbar-brand-hover-color: #fdfeff;--bs-navbar-toggler-border-color: rgba(253, 254, 254, 0);--bs-navbar-toggler-icon-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='%23fdfefe' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}[data-bs-theme=dark] .navbar-toggler-icon{--bs-navbar-toggler-icon-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='%23fdfefe' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.card{--bs-card-spacer-y: 1rem;--bs-card-spacer-x: 1rem;--bs-card-title-spacer-y: 0.5rem;--bs-card-title-color: ;--bs-card-subtitle-color: ;--bs-card-border-width: 1px;--bs-card-border-color: rgba(0, 0, 0, 0.175);--bs-card-border-radius: 0.375rem;--bs-card-box-shadow: ;--bs-card-inner-border-radius: calc(0.375rem - 1px);--bs-card-cap-padding-y: 0.5rem;--bs-card-cap-padding-x: 1rem;--bs-card-cap-bg: rgba(33, 37, 41, 0.03);--bs-card-cap-color: ;--bs-card-height: ;--bs-card-color: ;--bs-card-bg: #ffffff;--bs-card-img-overlay-padding: 1rem;--bs-card-group-margin: 0.75rem;position:relative;display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;min-width:0;height:var(--bs-card-height);color:var(--bs-body-color);word-wrap:break-word;background-color:var(--bs-card-bg);background-clip:border-box;border:var(--bs-card-border-width) solid var(--bs-card-border-color);border-radius:var(--bs-card-border-radius)}.card>hr{margin-right:0;margin-left:0}.card>.list-group{border-top:inherit;border-bottom:inherit}.card>.list-group:first-child{border-top-width:0;border-top-left-radius:var(--bs-card-inner-border-radius);border-top-right-radius:var(--bs-card-inner-border-radius)}.card>.list-group:last-child{border-bottom-width:0;border-bottom-right-radius:var(--bs-card-inner-border-radius);border-bottom-left-radius:var(--bs-card-inner-border-radius)}.card>.card-header+.list-group,.card>.list-group+.card-footer{border-top:0}.card-body{flex:1 1 auto;-webkit-flex:1 1 auto;padding:var(--bs-card-spacer-y) var(--bs-card-spacer-x);color:var(--bs-card-color)}.card-title{margin-bottom:var(--bs-card-title-spacer-y);color:var(--bs-card-title-color)}.card-subtitle{margin-top:calc(-0.5*var(--bs-card-title-spacer-y));margin-bottom:0;color:var(--bs-card-subtitle-color)}.card-text:last-child{margin-bottom:0}.card-link+.card-link{margin-left:var(--bs-card-spacer-x)}.card-header{padding:var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x);margin-bottom:0;color:var(--bs-card-cap-color);background-color:var(--bs-card-cap-bg);border-bottom:var(--bs-card-border-width) solid var(--bs-card-border-color)}.card-header:first-child{border-radius:var(--bs-card-inner-border-radius) var(--bs-card-inner-border-radius) 0 0}.card-footer{padding:var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x);color:var(--bs-card-cap-color);background-color:var(--bs-card-cap-bg);border-top:var(--bs-card-border-width) solid var(--bs-card-border-color)}.card-footer:last-child{border-radius:0 0 var(--bs-card-inner-border-radius) var(--bs-card-inner-border-radius)}.card-header-tabs{margin-right:calc(-0.5*var(--bs-card-cap-padding-x));margin-bottom:calc(-1*var(--bs-card-cap-padding-y));margin-left:calc(-0.5*var(--bs-card-cap-padding-x));border-bottom:0}.card-header-tabs .nav-link.active{background-color:var(--bs-card-bg);border-bottom-color:var(--bs-card-bg)}.card-header-pills{margin-right:calc(-0.5*var(--bs-card-cap-padding-x));margin-left:calc(-0.5*var(--bs-card-cap-padding-x))}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:var(--bs-card-img-overlay-padding);border-radius:var(--bs-card-inner-border-radius)}.card-img,.card-img-top,.card-img-bottom{width:100%}.card-img,.card-img-top{border-top-left-radius:var(--bs-card-inner-border-radius);border-top-right-radius:var(--bs-card-inner-border-radius)}.card-img,.card-img-bottom{border-bottom-right-radius:var(--bs-card-inner-border-radius);border-bottom-left-radius:var(--bs-card-inner-border-radius)}.card-group>.card{margin-bottom:var(--bs-card-group-margin)}@media(min-width: 576px){.card-group{display:flex;display:-webkit-flex;flex-flow:row wrap;-webkit-flex-flow:row wrap}.card-group>.card{flex:1 0 0%;-webkit-flex:1 0 0%;margin-bottom:0}.card-group>.card+.card{margin-left:0;border-left:0}.card-group>.card:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.card-group>.card:not(:last-child) .card-img-top,.card-group>.card:not(:last-child) .card-header{border-top-right-radius:0}.card-group>.card:not(:last-child) .card-img-bottom,.card-group>.card:not(:last-child) .card-footer{border-bottom-right-radius:0}.card-group>.card:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.card-group>.card:not(:first-child) .card-img-top,.card-group>.card:not(:first-child) .card-header{border-top-left-radius:0}.card-group>.card:not(:first-child) .card-img-bottom,.card-group>.card:not(:first-child) .card-footer{border-bottom-left-radius:0}}.accordion{--bs-accordion-color: #212529;--bs-accordion-bg: #ffffff;--bs-accordion-transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out, border-radius 0.15s ease;--bs-accordion-border-color: #dee2e6;--bs-accordion-border-width: 1px;--bs-accordion-border-radius: 0.375rem;--bs-accordion-inner-border-radius: calc(0.375rem - 1px);--bs-accordion-btn-padding-x: 1.25rem;--bs-accordion-btn-padding-y: 1rem;--bs-accordion-btn-color: #212529;--bs-accordion-btn-bg: #ffffff;--bs-accordion-btn-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23212529'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");--bs-accordion-btn-icon-width: 1.25rem;--bs-accordion-btn-icon-transform: rotate(-180deg);--bs-accordion-btn-icon-transition: transform 0.2s ease-in-out;--bs-accordion-btn-active-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23052c65'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");--bs-accordion-btn-focus-border-color: #86b7fe;--bs-accordion-btn-focus-box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);--bs-accordion-body-padding-x: 1.25rem;--bs-accordion-body-padding-y: 1rem;--bs-accordion-active-color: #052c65;--bs-accordion-active-bg: #cfe2ff}.accordion-button{position:relative;display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;width:100%;padding:var(--bs-accordion-btn-padding-y) var(--bs-accordion-btn-padding-x);font-size:1rem;color:var(--bs-accordion-btn-color);text-align:left;background-color:var(--bs-accordion-btn-bg);border:0;border-radius:0;overflow-anchor:none;transition:var(--bs-accordion-transition)}@media(prefers-reduced-motion: reduce){.accordion-button{transition:none}}.accordion-button:not(.collapsed){color:var(--bs-accordion-active-color);background-color:var(--bs-accordion-active-bg);box-shadow:inset 0 calc(-1*var(--bs-accordion-border-width)) 0 var(--bs-accordion-border-color)}.accordion-button:not(.collapsed)::after{background-image:var(--bs-accordion-btn-active-icon);transform:var(--bs-accordion-btn-icon-transform)}.accordion-button::after{flex-shrink:0;-webkit-flex-shrink:0;width:var(--bs-accordion-btn-icon-width);height:var(--bs-accordion-btn-icon-width);margin-left:auto;content:"";background-image:var(--bs-accordion-btn-icon);background-repeat:no-repeat;background-size:var(--bs-accordion-btn-icon-width);transition:var(--bs-accordion-btn-icon-transition)}@media(prefers-reduced-motion: reduce){.accordion-button::after{transition:none}}.accordion-button:hover{z-index:2}.accordion-button:focus{z-index:3;border-color:var(--bs-accordion-btn-focus-border-color);outline:0;box-shadow:var(--bs-accordion-btn-focus-box-shadow)}.accordion-header{margin-bottom:0}.accordion-item{color:var(--bs-accordion-color);background-color:var(--bs-accordion-bg);border:var(--bs-accordion-border-width) solid var(--bs-accordion-border-color)}.accordion-item:first-of-type{border-top-left-radius:var(--bs-accordion-border-radius);border-top-right-radius:var(--bs-accordion-border-radius)}.accordion-item:first-of-type .accordion-button{border-top-left-radius:var(--bs-accordion-inner-border-radius);border-top-right-radius:var(--bs-accordion-inner-border-radius)}.accordion-item:not(:first-of-type){border-top:0}.accordion-item:last-of-type{border-bottom-right-radius:var(--bs-accordion-border-radius);border-bottom-left-radius:var(--bs-accordion-border-radius)}.accordion-item:last-of-type .accordion-button.collapsed{border-bottom-right-radius:var(--bs-accordion-inner-border-radius);border-bottom-left-radius:var(--bs-accordion-inner-border-radius)}.accordion-item:last-of-type .accordion-collapse{border-bottom-right-radius:var(--bs-accordion-border-radius);border-bottom-left-radius:var(--bs-accordion-border-radius)}.accordion-body{padding:var(--bs-accordion-body-padding-y) var(--bs-accordion-body-padding-x)}.accordion-flush .accordion-collapse{border-width:0}.accordion-flush .accordion-item{border-right:0;border-left:0;border-radius:0}.accordion-flush .accordion-item:first-child{border-top:0}.accordion-flush .accordion-item:last-child{border-bottom:0}.accordion-flush .accordion-item .accordion-button,.accordion-flush .accordion-item .accordion-button.collapsed{border-radius:0}[data-bs-theme=dark] .accordion-button::after{--bs-accordion-btn-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%236ea8fe'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");--bs-accordion-btn-active-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%236ea8fe'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e")}.breadcrumb{--bs-breadcrumb-padding-x: 0;--bs-breadcrumb-padding-y: 0;--bs-breadcrumb-margin-bottom: 1rem;--bs-breadcrumb-bg: ;--bs-breadcrumb-border-radius: ;--bs-breadcrumb-divider-color: rgba(33, 37, 41, 0.75);--bs-breadcrumb-item-padding-x: 0.5rem;--bs-breadcrumb-item-active-color: rgba(33, 37, 41, 0.75);display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;padding:var(--bs-breadcrumb-padding-y) var(--bs-breadcrumb-padding-x);margin-bottom:var(--bs-breadcrumb-margin-bottom);font-size:var(--bs-breadcrumb-font-size);list-style:none;background-color:var(--bs-breadcrumb-bg);border-radius:var(--bs-breadcrumb-border-radius)}.breadcrumb-item+.breadcrumb-item{padding-left:var(--bs-breadcrumb-item-padding-x)}.breadcrumb-item+.breadcrumb-item::before{float:left;padding-right:var(--bs-breadcrumb-item-padding-x);color:var(--bs-breadcrumb-divider-color);content:var(--bs-breadcrumb-divider, ">") /* rtl: var(--bs-breadcrumb-divider, ">") */}.breadcrumb-item.active{color:var(--bs-breadcrumb-item-active-color)}.pagination{--bs-pagination-padding-x: 0.75rem;--bs-pagination-padding-y: 0.375rem;--bs-pagination-font-size:1rem;--bs-pagination-color: #0d6efd;--bs-pagination-bg: #ffffff;--bs-pagination-border-width: 1px;--bs-pagination-border-color: #dee2e6;--bs-pagination-border-radius: 0.375rem;--bs-pagination-hover-color: #0a58ca;--bs-pagination-hover-bg: #f8f9fa;--bs-pagination-hover-border-color: #dee2e6;--bs-pagination-focus-color: #0a58ca;--bs-pagination-focus-bg: #e9ecef;--bs-pagination-focus-box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);--bs-pagination-active-color: #ffffff;--bs-pagination-active-bg: #0d6efd;--bs-pagination-active-border-color: #0d6efd;--bs-pagination-disabled-color: rgba(33, 37, 41, 0.75);--bs-pagination-disabled-bg: #e9ecef;--bs-pagination-disabled-border-color: #dee2e6;display:flex;display:-webkit-flex;padding-left:0;list-style:none}.page-link{position:relative;display:block;padding:var(--bs-pagination-padding-y) var(--bs-pagination-padding-x);font-size:var(--bs-pagination-font-size);color:var(--bs-pagination-color);text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;background-color:var(--bs-pagination-bg);border:var(--bs-pagination-border-width) solid var(--bs-pagination-border-color);transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.page-link{transition:none}}.page-link:hover{z-index:2;color:var(--bs-pagination-hover-color);background-color:var(--bs-pagination-hover-bg);border-color:var(--bs-pagination-hover-border-color)}.page-link:focus{z-index:3;color:var(--bs-pagination-focus-color);background-color:var(--bs-pagination-focus-bg);outline:0;box-shadow:var(--bs-pagination-focus-box-shadow)}.page-link.active,.active>.page-link{z-index:3;color:var(--bs-pagination-active-color);background-color:var(--bs-pagination-active-bg);border-color:var(--bs-pagination-active-border-color)}.page-link.disabled,.disabled>.page-link{color:var(--bs-pagination-disabled-color);pointer-events:none;background-color:var(--bs-pagination-disabled-bg);border-color:var(--bs-pagination-disabled-border-color)}.page-item:not(:first-child) .page-link{margin-left:calc(1px*-1)}.page-item:first-child .page-link{border-top-left-radius:var(--bs-pagination-border-radius);border-bottom-left-radius:var(--bs-pagination-border-radius)}.page-item:last-child .page-link{border-top-right-radius:var(--bs-pagination-border-radius);border-bottom-right-radius:var(--bs-pagination-border-radius)}.pagination-lg{--bs-pagination-padding-x: 1.5rem;--bs-pagination-padding-y: 0.75rem;--bs-pagination-font-size:1.25rem;--bs-pagination-border-radius: 0.5rem}.pagination-sm{--bs-pagination-padding-x: 0.5rem;--bs-pagination-padding-y: 0.25rem;--bs-pagination-font-size:0.875rem;--bs-pagination-border-radius: 0.25rem}.badge{--bs-badge-padding-x: 0.65em;--bs-badge-padding-y: 0.35em;--bs-badge-font-size:0.75em;--bs-badge-font-weight: 700;--bs-badge-color: #ffffff;--bs-badge-border-radius: 0.375rem;display:inline-block;padding:var(--bs-badge-padding-y) var(--bs-badge-padding-x);font-size:var(--bs-badge-font-size);font-weight:var(--bs-badge-font-weight);line-height:1;color:var(--bs-badge-color);text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:var(--bs-badge-border-radius)}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.alert{--bs-alert-bg: transparent;--bs-alert-padding-x: 1rem;--bs-alert-padding-y: 1rem;--bs-alert-margin-bottom: 1rem;--bs-alert-color: inherit;--bs-alert-border-color: transparent;--bs-alert-border: 1px solid var(--bs-alert-border-color);--bs-alert-border-radius: 0.375rem;--bs-alert-link-color: inherit;position:relative;padding:var(--bs-alert-padding-y) var(--bs-alert-padding-x);margin-bottom:var(--bs-alert-margin-bottom);color:var(--bs-alert-color);background-color:var(--bs-alert-bg);border:var(--bs-alert-border);border-radius:var(--bs-alert-border-radius)}.alert-heading{color:inherit}.alert-link{font-weight:700;color:var(--bs-alert-link-color)}.alert-dismissible{padding-right:3rem}.alert-dismissible .btn-close{position:absolute;top:0;right:0;z-index:2;padding:1.25rem 1rem}.alert-default{--bs-alert-color: var(--bs-default-text-emphasis);--bs-alert-bg: var(--bs-default-bg-subtle);--bs-alert-border-color: var(--bs-default-border-subtle);--bs-alert-link-color: var(--bs-default-text-emphasis)}.alert-primary{--bs-alert-color: var(--bs-primary-text-emphasis);--bs-alert-bg: var(--bs-primary-bg-subtle);--bs-alert-border-color: var(--bs-primary-border-subtle);--bs-alert-link-color: var(--bs-primary-text-emphasis)}.alert-secondary{--bs-alert-color: var(--bs-secondary-text-emphasis);--bs-alert-bg: var(--bs-secondary-bg-subtle);--bs-alert-border-color: var(--bs-secondary-border-subtle);--bs-alert-link-color: var(--bs-secondary-text-emphasis)}.alert-success{--bs-alert-color: var(--bs-success-text-emphasis);--bs-alert-bg: var(--bs-success-bg-subtle);--bs-alert-border-color: var(--bs-success-border-subtle);--bs-alert-link-color: var(--bs-success-text-emphasis)}.alert-info{--bs-alert-color: var(--bs-info-text-emphasis);--bs-alert-bg: var(--bs-info-bg-subtle);--bs-alert-border-color: var(--bs-info-border-subtle);--bs-alert-link-color: var(--bs-info-text-emphasis)}.alert-warning{--bs-alert-color: var(--bs-warning-text-emphasis);--bs-alert-bg: var(--bs-warning-bg-subtle);--bs-alert-border-color: var(--bs-warning-border-subtle);--bs-alert-link-color: var(--bs-warning-text-emphasis)}.alert-danger{--bs-alert-color: var(--bs-danger-text-emphasis);--bs-alert-bg: var(--bs-danger-bg-subtle);--bs-alert-border-color: var(--bs-danger-border-subtle);--bs-alert-link-color: var(--bs-danger-text-emphasis)}.alert-light{--bs-alert-color: var(--bs-light-text-emphasis);--bs-alert-bg: var(--bs-light-bg-subtle);--bs-alert-border-color: var(--bs-light-border-subtle);--bs-alert-link-color: var(--bs-light-text-emphasis)}.alert-dark{--bs-alert-color: var(--bs-dark-text-emphasis);--bs-alert-bg: var(--bs-dark-bg-subtle);--bs-alert-border-color: var(--bs-dark-border-subtle);--bs-alert-link-color: var(--bs-dark-text-emphasis)}@keyframes progress-bar-stripes{0%{background-position-x:1rem}}.progress,.progress-stacked{--bs-progress-height: 1rem;--bs-progress-font-size:0.75rem;--bs-progress-bg: #e9ecef;--bs-progress-border-radius: 0.375rem;--bs-progress-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.075);--bs-progress-bar-color: #ffffff;--bs-progress-bar-bg: #0d6efd;--bs-progress-bar-transition: width 0.6s ease;display:flex;display:-webkit-flex;height:var(--bs-progress-height);overflow:hidden;font-size:var(--bs-progress-font-size);background-color:var(--bs-progress-bg);border-radius:var(--bs-progress-border-radius)}.progress-bar{display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;justify-content:center;-webkit-justify-content:center;overflow:hidden;color:var(--bs-progress-bar-color);text-align:center;white-space:nowrap;background-color:var(--bs-progress-bar-bg);transition:var(--bs-progress-bar-transition)}@media(prefers-reduced-motion: reduce){.progress-bar{transition:none}}.progress-bar-striped{background-image:linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-size:var(--bs-progress-height) var(--bs-progress-height)}.progress-stacked>.progress{overflow:visible}.progress-stacked>.progress>.progress-bar{width:100%}.progress-bar-animated{animation:1s linear infinite progress-bar-stripes}@media(prefers-reduced-motion: reduce){.progress-bar-animated{animation:none}}.list-group{--bs-list-group-color: #212529;--bs-list-group-bg: #ffffff;--bs-list-group-border-color: #dee2e6;--bs-list-group-border-width: 1px;--bs-list-group-border-radius: 0.375rem;--bs-list-group-item-padding-x: 1rem;--bs-list-group-item-padding-y: 0.5rem;--bs-list-group-action-color: rgba(33, 37, 41, 0.75);--bs-list-group-action-hover-color: #000;--bs-list-group-action-hover-bg: #f8f9fa;--bs-list-group-action-active-color: #212529;--bs-list-group-action-active-bg: #e9ecef;--bs-list-group-disabled-color: rgba(33, 37, 41, 0.75);--bs-list-group-disabled-bg: #ffffff;--bs-list-group-active-color: #ffffff;--bs-list-group-active-bg: #0d6efd;--bs-list-group-active-border-color: #0d6efd;display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;padding-left:0;margin-bottom:0;border-radius:var(--bs-list-group-border-radius)}.list-group-numbered{list-style-type:none;counter-reset:section}.list-group-numbered>.list-group-item::before{content:counters(section, ".") ". ";counter-increment:section}.list-group-item-action{width:100%;color:var(--bs-list-group-action-color);text-align:inherit}.list-group-item-action:hover,.list-group-item-action:focus{z-index:1;color:var(--bs-list-group-action-hover-color);text-decoration:none;background-color:var(--bs-list-group-action-hover-bg)}.list-group-item-action:active{color:var(--bs-list-group-action-active-color);background-color:var(--bs-list-group-action-active-bg)}.list-group-item{position:relative;display:block;padding:var(--bs-list-group-item-padding-y) var(--bs-list-group-item-padding-x);color:var(--bs-list-group-color);text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;background-color:var(--bs-list-group-bg);border:var(--bs-list-group-border-width) solid var(--bs-list-group-border-color)}.list-group-item:first-child{border-top-left-radius:inherit;border-top-right-radius:inherit}.list-group-item:last-child{border-bottom-right-radius:inherit;border-bottom-left-radius:inherit}.list-group-item.disabled,.list-group-item:disabled{color:var(--bs-list-group-disabled-color);pointer-events:none;background-color:var(--bs-list-group-disabled-bg)}.list-group-item.active{z-index:2;color:var(--bs-list-group-active-color);background-color:var(--bs-list-group-active-bg);border-color:var(--bs-list-group-active-border-color)}.list-group-item+.list-group-item{border-top-width:0}.list-group-item+.list-group-item.active{margin-top:calc(-1*var(--bs-list-group-border-width));border-top-width:var(--bs-list-group-border-width)}.list-group-horizontal{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal>.list-group-item.active{margin-top:0}.list-group-horizontal>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal>.list-group-item+.list-group-item.active{margin-left:calc(-1*var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}@media(min-width: 576px){.list-group-horizontal-sm{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal-sm>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-sm>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-sm>.list-group-item.active{margin-top:0}.list-group-horizontal-sm>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-sm>.list-group-item+.list-group-item.active{margin-left:calc(-1*var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media(min-width: 768px){.list-group-horizontal-md{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal-md>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-md>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-md>.list-group-item.active{margin-top:0}.list-group-horizontal-md>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-md>.list-group-item+.list-group-item.active{margin-left:calc(-1*var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media(min-width: 992px){.list-group-horizontal-lg{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal-lg>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-lg>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-lg>.list-group-item.active{margin-top:0}.list-group-horizontal-lg>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-lg>.list-group-item+.list-group-item.active{margin-left:calc(-1*var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media(min-width: 1200px){.list-group-horizontal-xl{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal-xl>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-xl>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-xl>.list-group-item.active{margin-top:0}.list-group-horizontal-xl>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-xl>.list-group-item+.list-group-item.active{margin-left:calc(-1*var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media(min-width: 1400px){.list-group-horizontal-xxl{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal-xxl>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-xxl>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-xxl>.list-group-item.active{margin-top:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item.active{margin-left:calc(-1*var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}.list-group-flush{border-radius:0}.list-group-flush>.list-group-item{border-width:0 0 var(--bs-list-group-border-width)}.list-group-flush>.list-group-item:last-child{border-bottom-width:0}.list-group-item-default{--bs-list-group-color: var(--bs-default-text-emphasis);--bs-list-group-bg: var(--bs-default-bg-subtle);--bs-list-group-border-color: var(--bs-default-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-default-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-default-border-subtle);--bs-list-group-active-color: var(--bs-default-bg-subtle);--bs-list-group-active-bg: var(--bs-default-text-emphasis);--bs-list-group-active-border-color: var(--bs-default-text-emphasis)}.list-group-item-primary{--bs-list-group-color: var(--bs-primary-text-emphasis);--bs-list-group-bg: var(--bs-primary-bg-subtle);--bs-list-group-border-color: var(--bs-primary-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-primary-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-primary-border-subtle);--bs-list-group-active-color: var(--bs-primary-bg-subtle);--bs-list-group-active-bg: var(--bs-primary-text-emphasis);--bs-list-group-active-border-color: var(--bs-primary-text-emphasis)}.list-group-item-secondary{--bs-list-group-color: var(--bs-secondary-text-emphasis);--bs-list-group-bg: var(--bs-secondary-bg-subtle);--bs-list-group-border-color: var(--bs-secondary-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-secondary-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-secondary-border-subtle);--bs-list-group-active-color: var(--bs-secondary-bg-subtle);--bs-list-group-active-bg: var(--bs-secondary-text-emphasis);--bs-list-group-active-border-color: var(--bs-secondary-text-emphasis)}.list-group-item-success{--bs-list-group-color: var(--bs-success-text-emphasis);--bs-list-group-bg: var(--bs-success-bg-subtle);--bs-list-group-border-color: var(--bs-success-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-success-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-success-border-subtle);--bs-list-group-active-color: var(--bs-success-bg-subtle);--bs-list-group-active-bg: var(--bs-success-text-emphasis);--bs-list-group-active-border-color: var(--bs-success-text-emphasis)}.list-group-item-info{--bs-list-group-color: var(--bs-info-text-emphasis);--bs-list-group-bg: var(--bs-info-bg-subtle);--bs-list-group-border-color: var(--bs-info-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-info-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-info-border-subtle);--bs-list-group-active-color: var(--bs-info-bg-subtle);--bs-list-group-active-bg: var(--bs-info-text-emphasis);--bs-list-group-active-border-color: var(--bs-info-text-emphasis)}.list-group-item-warning{--bs-list-group-color: var(--bs-warning-text-emphasis);--bs-list-group-bg: var(--bs-warning-bg-subtle);--bs-list-group-border-color: var(--bs-warning-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-warning-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-warning-border-subtle);--bs-list-group-active-color: var(--bs-warning-bg-subtle);--bs-list-group-active-bg: var(--bs-warning-text-emphasis);--bs-list-group-active-border-color: var(--bs-warning-text-emphasis)}.list-group-item-danger{--bs-list-group-color: var(--bs-danger-text-emphasis);--bs-list-group-bg: var(--bs-danger-bg-subtle);--bs-list-group-border-color: var(--bs-danger-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-danger-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-danger-border-subtle);--bs-list-group-active-color: var(--bs-danger-bg-subtle);--bs-list-group-active-bg: var(--bs-danger-text-emphasis);--bs-list-group-active-border-color: var(--bs-danger-text-emphasis)}.list-group-item-light{--bs-list-group-color: var(--bs-light-text-emphasis);--bs-list-group-bg: var(--bs-light-bg-subtle);--bs-list-group-border-color: var(--bs-light-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-light-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-light-border-subtle);--bs-list-group-active-color: var(--bs-light-bg-subtle);--bs-list-group-active-bg: var(--bs-light-text-emphasis);--bs-list-group-active-border-color: var(--bs-light-text-emphasis)}.list-group-item-dark{--bs-list-group-color: var(--bs-dark-text-emphasis);--bs-list-group-bg: var(--bs-dark-bg-subtle);--bs-list-group-border-color: var(--bs-dark-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-dark-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-dark-border-subtle);--bs-list-group-active-color: var(--bs-dark-bg-subtle);--bs-list-group-active-bg: var(--bs-dark-text-emphasis);--bs-list-group-active-border-color: var(--bs-dark-text-emphasis)}.btn-close{--bs-btn-close-color: #000;--bs-btn-close-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath d='M.293.293a1 1 0 0 1 1.414 0L8 6.586 14.293.293a1 1 0 1 1 1.414 1.414L9.414 8l6.293 6.293a1 1 0 0 1-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 0 1-1.414-1.414L6.586 8 .293 1.707a1 1 0 0 1 0-1.414z'/%3e%3c/svg%3e");--bs-btn-close-opacity: 0.5;--bs-btn-close-hover-opacity: 0.75;--bs-btn-close-focus-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);--bs-btn-close-focus-opacity: 1;--bs-btn-close-disabled-opacity: 0.25;--bs-btn-close-white-filter: invert(1) grayscale(100%) brightness(200%);box-sizing:content-box;width:1em;height:1em;padding:.25em .25em;color:var(--bs-btn-close-color);background:rgba(0,0,0,0) var(--bs-btn-close-bg) center/1em auto no-repeat;border:0;border-radius:.375rem;opacity:var(--bs-btn-close-opacity)}.btn-close:hover{color:var(--bs-btn-close-color);text-decoration:none;opacity:var(--bs-btn-close-hover-opacity)}.btn-close:focus{outline:0;box-shadow:var(--bs-btn-close-focus-shadow);opacity:var(--bs-btn-close-focus-opacity)}.btn-close:disabled,.btn-close.disabled{pointer-events:none;user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;opacity:var(--bs-btn-close-disabled-opacity)}.btn-close-white{filter:var(--bs-btn-close-white-filter)}[data-bs-theme=dark] .btn-close{filter:var(--bs-btn-close-white-filter)}.toast{--bs-toast-zindex: 1090;--bs-toast-padding-x: 0.75rem;--bs-toast-padding-y: 0.5rem;--bs-toast-spacing: 1.5rem;--bs-toast-max-width: 350px;--bs-toast-font-size:0.875rem;--bs-toast-color: ;--bs-toast-bg: rgba(255, 255, 255, 0.85);--bs-toast-border-width: 1px;--bs-toast-border-color: rgba(0, 0, 0, 0.175);--bs-toast-border-radius: 0.375rem;--bs-toast-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);--bs-toast-header-color: rgba(33, 37, 41, 0.75);--bs-toast-header-bg: rgba(255, 255, 255, 0.85);--bs-toast-header-border-color: rgba(0, 0, 0, 0.175);width:var(--bs-toast-max-width);max-width:100%;font-size:var(--bs-toast-font-size);color:var(--bs-toast-color);pointer-events:auto;background-color:var(--bs-toast-bg);background-clip:padding-box;border:var(--bs-toast-border-width) solid var(--bs-toast-border-color);box-shadow:var(--bs-toast-box-shadow);border-radius:var(--bs-toast-border-radius)}.toast.showing{opacity:0}.toast:not(.show){display:none}.toast-container{--bs-toast-zindex: 1090;position:absolute;z-index:var(--bs-toast-zindex);width:max-content;width:-webkit-max-content;width:-moz-max-content;width:-ms-max-content;width:-o-max-content;max-width:100%;pointer-events:none}.toast-container>:not(:last-child){margin-bottom:var(--bs-toast-spacing)}.toast-header{display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;padding:var(--bs-toast-padding-y) var(--bs-toast-padding-x);color:var(--bs-toast-header-color);background-color:var(--bs-toast-header-bg);background-clip:padding-box;border-bottom:var(--bs-toast-border-width) solid var(--bs-toast-header-border-color);border-top-left-radius:calc(var(--bs-toast-border-radius) - var(--bs-toast-border-width));border-top-right-radius:calc(var(--bs-toast-border-radius) - var(--bs-toast-border-width))}.toast-header .btn-close{margin-right:calc(-0.5*var(--bs-toast-padding-x));margin-left:var(--bs-toast-padding-x)}.toast-body{padding:var(--bs-toast-padding-x);word-wrap:break-word}.modal{--bs-modal-zindex: 1055;--bs-modal-width: 500px;--bs-modal-padding: 1rem;--bs-modal-margin: 0.5rem;--bs-modal-color: ;--bs-modal-bg: #ffffff;--bs-modal-border-color: rgba(0, 0, 0, 0.175);--bs-modal-border-width: 1px;--bs-modal-border-radius: 0.5rem;--bs-modal-box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);--bs-modal-inner-border-radius: calc(0.5rem - 1px);--bs-modal-header-padding-x: 1rem;--bs-modal-header-padding-y: 1rem;--bs-modal-header-padding: 1rem 1rem;--bs-modal-header-border-color: #dee2e6;--bs-modal-header-border-width: 1px;--bs-modal-title-line-height: 1.5;--bs-modal-footer-gap: 0.5rem;--bs-modal-footer-bg: ;--bs-modal-footer-border-color: #dee2e6;--bs-modal-footer-border-width: 1px;position:fixed;top:0;left:0;z-index:var(--bs-modal-zindex);display:none;width:100%;height:100%;overflow-x:hidden;overflow-y:auto;outline:0}.modal-dialog{position:relative;width:auto;margin:var(--bs-modal-margin);pointer-events:none}.modal.fade .modal-dialog{transition:transform .3s ease-out;transform:translate(0, -50px)}@media(prefers-reduced-motion: reduce){.modal.fade .modal-dialog{transition:none}}.modal.show .modal-dialog{transform:none}.modal.modal-static .modal-dialog{transform:scale(1.02)}.modal-dialog-scrollable{height:calc(100% - var(--bs-modal-margin)*2)}.modal-dialog-scrollable .modal-content{max-height:100%;overflow:hidden}.modal-dialog-scrollable .modal-body{overflow-y:auto}.modal-dialog-centered{display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;min-height:calc(100% - var(--bs-modal-margin)*2)}.modal-content{position:relative;display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;width:100%;color:var(--bs-modal-color);pointer-events:auto;background-color:var(--bs-modal-bg);background-clip:padding-box;border:var(--bs-modal-border-width) solid var(--bs-modal-border-color);border-radius:var(--bs-modal-border-radius);outline:0}.modal-backdrop{--bs-backdrop-zindex: 1050;--bs-backdrop-bg: #000;--bs-backdrop-opacity: 0.5;position:fixed;top:0;left:0;z-index:var(--bs-backdrop-zindex);width:100vw;height:100vh;background-color:var(--bs-backdrop-bg)}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:var(--bs-backdrop-opacity)}.modal-header{display:flex;display:-webkit-flex;flex-shrink:0;-webkit-flex-shrink:0;align-items:center;-webkit-align-items:center;justify-content:space-between;-webkit-justify-content:space-between;padding:var(--bs-modal-header-padding);border-bottom:var(--bs-modal-header-border-width) solid var(--bs-modal-header-border-color);border-top-left-radius:var(--bs-modal-inner-border-radius);border-top-right-radius:var(--bs-modal-inner-border-radius)}.modal-header .btn-close{padding:calc(var(--bs-modal-header-padding-y)*.5) calc(var(--bs-modal-header-padding-x)*.5);margin:calc(-0.5*var(--bs-modal-header-padding-y)) calc(-0.5*var(--bs-modal-header-padding-x)) calc(-0.5*var(--bs-modal-header-padding-y)) auto}.modal-title{margin-bottom:0;line-height:var(--bs-modal-title-line-height)}.modal-body{position:relative;flex:1 1 auto;-webkit-flex:1 1 auto;padding:var(--bs-modal-padding)}.modal-footer{display:flex;display:-webkit-flex;flex-shrink:0;-webkit-flex-shrink:0;flex-wrap:wrap;-webkit-flex-wrap:wrap;align-items:center;-webkit-align-items:center;justify-content:flex-end;-webkit-justify-content:flex-end;padding:calc(var(--bs-modal-padding) - var(--bs-modal-footer-gap)*.5);background-color:var(--bs-modal-footer-bg);border-top:var(--bs-modal-footer-border-width) solid var(--bs-modal-footer-border-color);border-bottom-right-radius:var(--bs-modal-inner-border-radius);border-bottom-left-radius:var(--bs-modal-inner-border-radius)}.modal-footer>*{margin:calc(var(--bs-modal-footer-gap)*.5)}@media(min-width: 576px){.modal{--bs-modal-margin: 1.75rem;--bs-modal-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15)}.modal-dialog{max-width:var(--bs-modal-width);margin-right:auto;margin-left:auto}.modal-sm{--bs-modal-width: 300px}}@media(min-width: 992px){.modal-lg,.modal-xl{--bs-modal-width: 800px}}@media(min-width: 1200px){.modal-xl{--bs-modal-width: 1140px}}.modal-fullscreen{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen .modal-header,.modal-fullscreen .modal-footer{border-radius:0}.modal-fullscreen .modal-body{overflow-y:auto}@media(max-width: 575.98px){.modal-fullscreen-sm-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-sm-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-sm-down .modal-header,.modal-fullscreen-sm-down .modal-footer{border-radius:0}.modal-fullscreen-sm-down .modal-body{overflow-y:auto}}@media(max-width: 767.98px){.modal-fullscreen-md-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-md-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-md-down .modal-header,.modal-fullscreen-md-down .modal-footer{border-radius:0}.modal-fullscreen-md-down .modal-body{overflow-y:auto}}@media(max-width: 991.98px){.modal-fullscreen-lg-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-lg-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-lg-down .modal-header,.modal-fullscreen-lg-down .modal-footer{border-radius:0}.modal-fullscreen-lg-down .modal-body{overflow-y:auto}}@media(max-width: 1199.98px){.modal-fullscreen-xl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xl-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-xl-down .modal-header,.modal-fullscreen-xl-down .modal-footer{border-radius:0}.modal-fullscreen-xl-down .modal-body{overflow-y:auto}}@media(max-width: 1399.98px){.modal-fullscreen-xxl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xxl-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-xxl-down .modal-header,.modal-fullscreen-xxl-down .modal-footer{border-radius:0}.modal-fullscreen-xxl-down .modal-body{overflow-y:auto}}.tooltip{--bs-tooltip-zindex: 1080;--bs-tooltip-max-width: 200px;--bs-tooltip-padding-x: 0.5rem;--bs-tooltip-padding-y: 0.25rem;--bs-tooltip-margin: ;--bs-tooltip-font-size:0.875rem;--bs-tooltip-color: #ffffff;--bs-tooltip-bg: #000;--bs-tooltip-border-radius: 0.375rem;--bs-tooltip-opacity: 0.9;--bs-tooltip-arrow-width: 0.8rem;--bs-tooltip-arrow-height: 0.4rem;z-index:var(--bs-tooltip-zindex);display:block;margin:var(--bs-tooltip-margin);font-family:system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue","Noto Sans","Liberation Sans",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;white-space:normal;word-spacing:normal;line-break:auto;font-size:var(--bs-tooltip-font-size);word-wrap:break-word;opacity:0}.tooltip.show{opacity:var(--bs-tooltip-opacity)}.tooltip .tooltip-arrow{display:block;width:var(--bs-tooltip-arrow-width);height:var(--bs-tooltip-arrow-height)}.tooltip .tooltip-arrow::before{position:absolute;content:"";border-color:rgba(0,0,0,0);border-style:solid}.bs-tooltip-top .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow{bottom:calc(-1*var(--bs-tooltip-arrow-height))}.bs-tooltip-top .tooltip-arrow::before,.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow::before{top:-1px;border-width:var(--bs-tooltip-arrow-height) calc(var(--bs-tooltip-arrow-width)*.5) 0;border-top-color:var(--bs-tooltip-bg)}.bs-tooltip-end .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow{left:calc(-1*var(--bs-tooltip-arrow-height));width:var(--bs-tooltip-arrow-height);height:var(--bs-tooltip-arrow-width)}.bs-tooltip-end .tooltip-arrow::before,.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow::before{right:-1px;border-width:calc(var(--bs-tooltip-arrow-width)*.5) var(--bs-tooltip-arrow-height) calc(var(--bs-tooltip-arrow-width)*.5) 0;border-right-color:var(--bs-tooltip-bg)}.bs-tooltip-bottom .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow{top:calc(-1*var(--bs-tooltip-arrow-height))}.bs-tooltip-bottom .tooltip-arrow::before,.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow::before{bottom:-1px;border-width:0 calc(var(--bs-tooltip-arrow-width)*.5) var(--bs-tooltip-arrow-height);border-bottom-color:var(--bs-tooltip-bg)}.bs-tooltip-start .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow{right:calc(-1*var(--bs-tooltip-arrow-height));width:var(--bs-tooltip-arrow-height);height:var(--bs-tooltip-arrow-width)}.bs-tooltip-start .tooltip-arrow::before,.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow::before{left:-1px;border-width:calc(var(--bs-tooltip-arrow-width)*.5) 0 calc(var(--bs-tooltip-arrow-width)*.5) var(--bs-tooltip-arrow-height);border-left-color:var(--bs-tooltip-bg)}.tooltip-inner{max-width:var(--bs-tooltip-max-width);padding:var(--bs-tooltip-padding-y) var(--bs-tooltip-padding-x);color:var(--bs-tooltip-color);text-align:center;background-color:var(--bs-tooltip-bg);border-radius:var(--bs-tooltip-border-radius)}.popover{--bs-popover-zindex: 1070;--bs-popover-max-width: 276px;--bs-popover-font-size:0.875rem;--bs-popover-bg: #ffffff;--bs-popover-border-width: 1px;--bs-popover-border-color: rgba(0, 0, 0, 0.175);--bs-popover-border-radius: 0.5rem;--bs-popover-inner-border-radius: calc(0.5rem - 1px);--bs-popover-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);--bs-popover-header-padding-x: 1rem;--bs-popover-header-padding-y: 0.5rem;--bs-popover-header-font-size:1rem;--bs-popover-header-color: inherit;--bs-popover-header-bg: #e9ecef;--bs-popover-body-padding-x: 1rem;--bs-popover-body-padding-y: 1rem;--bs-popover-body-color: #212529;--bs-popover-arrow-width: 1rem;--bs-popover-arrow-height: 0.5rem;--bs-popover-arrow-border: var(--bs-popover-border-color);z-index:var(--bs-popover-zindex);display:block;max-width:var(--bs-popover-max-width);font-family:system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue","Noto Sans","Liberation Sans",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;white-space:normal;word-spacing:normal;line-break:auto;font-size:var(--bs-popover-font-size);word-wrap:break-word;background-color:var(--bs-popover-bg);background-clip:padding-box;border:var(--bs-popover-border-width) solid var(--bs-popover-border-color);border-radius:var(--bs-popover-border-radius)}.popover .popover-arrow{display:block;width:var(--bs-popover-arrow-width);height:var(--bs-popover-arrow-height)}.popover .popover-arrow::before,.popover .popover-arrow::after{position:absolute;display:block;content:"";border-color:rgba(0,0,0,0);border-style:solid;border-width:0}.bs-popover-top>.popover-arrow,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow{bottom:calc(-1*(var(--bs-popover-arrow-height)) - var(--bs-popover-border-width))}.bs-popover-top>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::before,.bs-popover-top>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::after{border-width:var(--bs-popover-arrow-height) calc(var(--bs-popover-arrow-width)*.5) 0}.bs-popover-top>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::before{bottom:0;border-top-color:var(--bs-popover-arrow-border)}.bs-popover-top>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::after{bottom:var(--bs-popover-border-width);border-top-color:var(--bs-popover-bg)}.bs-popover-end>.popover-arrow,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow{left:calc(-1*(var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));width:var(--bs-popover-arrow-height);height:var(--bs-popover-arrow-width)}.bs-popover-end>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::before,.bs-popover-end>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::after{border-width:calc(var(--bs-popover-arrow-width)*.5) var(--bs-popover-arrow-height) calc(var(--bs-popover-arrow-width)*.5) 0}.bs-popover-end>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::before{left:0;border-right-color:var(--bs-popover-arrow-border)}.bs-popover-end>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::after{left:var(--bs-popover-border-width);border-right-color:var(--bs-popover-bg)}.bs-popover-bottom>.popover-arrow,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow{top:calc(-1*(var(--bs-popover-arrow-height)) - var(--bs-popover-border-width))}.bs-popover-bottom>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::before,.bs-popover-bottom>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::after{border-width:0 calc(var(--bs-popover-arrow-width)*.5) var(--bs-popover-arrow-height)}.bs-popover-bottom>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::before{top:0;border-bottom-color:var(--bs-popover-arrow-border)}.bs-popover-bottom>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::after{top:var(--bs-popover-border-width);border-bottom-color:var(--bs-popover-bg)}.bs-popover-bottom .popover-header::before,.bs-popover-auto[data-popper-placement^=bottom] .popover-header::before{position:absolute;top:0;left:50%;display:block;width:var(--bs-popover-arrow-width);margin-left:calc(-0.5*var(--bs-popover-arrow-width));content:"";border-bottom:var(--bs-popover-border-width) solid var(--bs-popover-header-bg)}.bs-popover-start>.popover-arrow,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow{right:calc(-1*(var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));width:var(--bs-popover-arrow-height);height:var(--bs-popover-arrow-width)}.bs-popover-start>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::before,.bs-popover-start>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::after{border-width:calc(var(--bs-popover-arrow-width)*.5) 0 calc(var(--bs-popover-arrow-width)*.5) var(--bs-popover-arrow-height)}.bs-popover-start>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::before{right:0;border-left-color:var(--bs-popover-arrow-border)}.bs-popover-start>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::after{right:var(--bs-popover-border-width);border-left-color:var(--bs-popover-bg)}.popover-header{padding:var(--bs-popover-header-padding-y) var(--bs-popover-header-padding-x);margin-bottom:0;font-size:var(--bs-popover-header-font-size);color:var(--bs-popover-header-color);background-color:var(--bs-popover-header-bg);border-bottom:var(--bs-popover-border-width) solid var(--bs-popover-border-color);border-top-left-radius:var(--bs-popover-inner-border-radius);border-top-right-radius:var(--bs-popover-inner-border-radius)}.popover-header:empty{display:none}.popover-body{padding:var(--bs-popover-body-padding-y) var(--bs-popover-body-padding-x);color:var(--bs-popover-body-color)}.carousel{position:relative}.carousel.pointer-event{touch-action:pan-y;-webkit-touch-action:pan-y;-moz-touch-action:pan-y;-ms-touch-action:pan-y;-o-touch-action:pan-y}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner::after{display:block;clear:both;content:""}.carousel-item{position:relative;display:none;float:left;width:100%;margin-right:-100%;backface-visibility:hidden;-webkit-backface-visibility:hidden;-moz-backface-visibility:hidden;-ms-backface-visibility:hidden;-o-backface-visibility:hidden;transition:transform .6s ease-in-out}@media(prefers-reduced-motion: reduce){.carousel-item{transition:none}}.carousel-item.active,.carousel-item-next,.carousel-item-prev{display:block}.carousel-item-next:not(.carousel-item-start),.active.carousel-item-end{transform:translateX(100%)}.carousel-item-prev:not(.carousel-item-end),.active.carousel-item-start{transform:translateX(-100%)}.carousel-fade .carousel-item{opacity:0;transition-property:opacity;transform:none}.carousel-fade .carousel-item.active,.carousel-fade .carousel-item-next.carousel-item-start,.carousel-fade .carousel-item-prev.carousel-item-end{z-index:1;opacity:1}.carousel-fade .active.carousel-item-start,.carousel-fade .active.carousel-item-end{z-index:0;opacity:0;transition:opacity 0s .6s}@media(prefers-reduced-motion: reduce){.carousel-fade .active.carousel-item-start,.carousel-fade .active.carousel-item-end{transition:none}}.carousel-control-prev,.carousel-control-next{position:absolute;top:0;bottom:0;z-index:1;display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;justify-content:center;-webkit-justify-content:center;width:15%;padding:0;color:#fff;text-align:center;background:none;border:0;opacity:.5;transition:opacity .15s ease}@media(prefers-reduced-motion: reduce){.carousel-control-prev,.carousel-control-next{transition:none}}.carousel-control-prev:hover,.carousel-control-prev:focus,.carousel-control-next:hover,.carousel-control-next:focus{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-prev-icon,.carousel-control-next-icon{display:inline-block;width:2rem;height:2rem;background-repeat:no-repeat;background-position:50%;background-size:100% 100%}.carousel-control-prev-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23ffffff'%3e%3cpath d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z'/%3e%3c/svg%3e")}.carousel-control-next-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23ffffff'%3e%3cpath d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e")}.carousel-indicators{position:absolute;right:0;bottom:0;left:0;z-index:2;display:flex;display:-webkit-flex;justify-content:center;-webkit-justify-content:center;padding:0;margin-right:15%;margin-bottom:1rem;margin-left:15%}.carousel-indicators [data-bs-target]{box-sizing:content-box;flex:0 1 auto;-webkit-flex:0 1 auto;width:30px;height:3px;padding:0;margin-right:3px;margin-left:3px;text-indent:-999px;cursor:pointer;background-color:#fff;background-clip:padding-box;border:0;border-top:10px solid rgba(0,0,0,0);border-bottom:10px solid rgba(0,0,0,0);opacity:.5;transition:opacity .6s ease}@media(prefers-reduced-motion: reduce){.carousel-indicators [data-bs-target]{transition:none}}.carousel-indicators .active{opacity:1}.carousel-caption{position:absolute;right:15%;bottom:1.25rem;left:15%;padding-top:1.25rem;padding-bottom:1.25rem;color:#fff;text-align:center}.carousel-dark .carousel-control-prev-icon,.carousel-dark .carousel-control-next-icon{filter:invert(1) grayscale(100)}.carousel-dark .carousel-indicators [data-bs-target]{background-color:#000}.carousel-dark .carousel-caption{color:#000}[data-bs-theme=dark] .carousel .carousel-control-prev-icon,[data-bs-theme=dark] .carousel .carousel-control-next-icon,[data-bs-theme=dark].carousel .carousel-control-prev-icon,[data-bs-theme=dark].carousel .carousel-control-next-icon{filter:invert(1) grayscale(100)}[data-bs-theme=dark] .carousel .carousel-indicators [data-bs-target],[data-bs-theme=dark].carousel .carousel-indicators [data-bs-target]{background-color:#000}[data-bs-theme=dark] .carousel .carousel-caption,[data-bs-theme=dark].carousel .carousel-caption{color:#000}.spinner-grow,.spinner-border{display:inline-block;width:var(--bs-spinner-width);height:var(--bs-spinner-height);vertical-align:var(--bs-spinner-vertical-align);border-radius:50%;animation:var(--bs-spinner-animation-speed) linear infinite var(--bs-spinner-animation-name)}@keyframes spinner-border{to{transform:rotate(360deg) /* rtl:ignore */}}.spinner-border{--bs-spinner-width: 2rem;--bs-spinner-height: 2rem;--bs-spinner-vertical-align: -0.125em;--bs-spinner-border-width: 0.25em;--bs-spinner-animation-speed: 0.75s;--bs-spinner-animation-name: spinner-border;border:var(--bs-spinner-border-width) solid currentcolor;border-right-color:rgba(0,0,0,0)}.spinner-border-sm{--bs-spinner-width: 1rem;--bs-spinner-height: 1rem;--bs-spinner-border-width: 0.2em}@keyframes spinner-grow{0%{transform:scale(0)}50%{opacity:1;transform:none}}.spinner-grow{--bs-spinner-width: 2rem;--bs-spinner-height: 2rem;--bs-spinner-vertical-align: -0.125em;--bs-spinner-animation-speed: 0.75s;--bs-spinner-animation-name: spinner-grow;background-color:currentcolor;opacity:0}.spinner-grow-sm{--bs-spinner-width: 1rem;--bs-spinner-height: 1rem}@media(prefers-reduced-motion: reduce){.spinner-border,.spinner-grow{--bs-spinner-animation-speed: 1.5s}}.offcanvas,.offcanvas-xxl,.offcanvas-xl,.offcanvas-lg,.offcanvas-md,.offcanvas-sm{--bs-offcanvas-zindex: 1045;--bs-offcanvas-width: 400px;--bs-offcanvas-height: 30vh;--bs-offcanvas-padding-x: 1rem;--bs-offcanvas-padding-y: 1rem;--bs-offcanvas-color: #212529;--bs-offcanvas-bg: #ffffff;--bs-offcanvas-border-width: 1px;--bs-offcanvas-border-color: rgba(0, 0, 0, 0.175);--bs-offcanvas-box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);--bs-offcanvas-transition: transform 0.3s ease-in-out;--bs-offcanvas-title-line-height: 1.5}@media(max-width: 575.98px){.offcanvas-sm{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media(max-width: 575.98px)and (prefers-reduced-motion: reduce){.offcanvas-sm{transition:none}}@media(max-width: 575.98px){.offcanvas-sm.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-sm.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-sm.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-sm.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-sm.showing,.offcanvas-sm.show:not(.hiding){transform:none}.offcanvas-sm.showing,.offcanvas-sm.hiding,.offcanvas-sm.show{visibility:visible}}@media(min-width: 576px){.offcanvas-sm{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:rgba(0,0,0,0) !important}.offcanvas-sm .offcanvas-header{display:none}.offcanvas-sm .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible;background-color:rgba(0,0,0,0) !important}}@media(max-width: 767.98px){.offcanvas-md{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media(max-width: 767.98px)and (prefers-reduced-motion: reduce){.offcanvas-md{transition:none}}@media(max-width: 767.98px){.offcanvas-md.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-md.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-md.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-md.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-md.showing,.offcanvas-md.show:not(.hiding){transform:none}.offcanvas-md.showing,.offcanvas-md.hiding,.offcanvas-md.show{visibility:visible}}@media(min-width: 768px){.offcanvas-md{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:rgba(0,0,0,0) !important}.offcanvas-md .offcanvas-header{display:none}.offcanvas-md .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible;background-color:rgba(0,0,0,0) !important}}@media(max-width: 991.98px){.offcanvas-lg{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media(max-width: 991.98px)and (prefers-reduced-motion: reduce){.offcanvas-lg{transition:none}}@media(max-width: 991.98px){.offcanvas-lg.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-lg.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-lg.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-lg.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-lg.showing,.offcanvas-lg.show:not(.hiding){transform:none}.offcanvas-lg.showing,.offcanvas-lg.hiding,.offcanvas-lg.show{visibility:visible}}@media(min-width: 992px){.offcanvas-lg{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:rgba(0,0,0,0) !important}.offcanvas-lg .offcanvas-header{display:none}.offcanvas-lg .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible;background-color:rgba(0,0,0,0) !important}}@media(max-width: 1199.98px){.offcanvas-xl{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media(max-width: 1199.98px)and (prefers-reduced-motion: reduce){.offcanvas-xl{transition:none}}@media(max-width: 1199.98px){.offcanvas-xl.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-xl.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-xl.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-xl.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-xl.showing,.offcanvas-xl.show:not(.hiding){transform:none}.offcanvas-xl.showing,.offcanvas-xl.hiding,.offcanvas-xl.show{visibility:visible}}@media(min-width: 1200px){.offcanvas-xl{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:rgba(0,0,0,0) !important}.offcanvas-xl .offcanvas-header{display:none}.offcanvas-xl .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible;background-color:rgba(0,0,0,0) !important}}@media(max-width: 1399.98px){.offcanvas-xxl{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media(max-width: 1399.98px)and (prefers-reduced-motion: reduce){.offcanvas-xxl{transition:none}}@media(max-width: 1399.98px){.offcanvas-xxl.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-xxl.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-xxl.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-xxl.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-xxl.showing,.offcanvas-xxl.show:not(.hiding){transform:none}.offcanvas-xxl.showing,.offcanvas-xxl.hiding,.offcanvas-xxl.show{visibility:visible}}@media(min-width: 1400px){.offcanvas-xxl{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:rgba(0,0,0,0) !important}.offcanvas-xxl .offcanvas-header{display:none}.offcanvas-xxl .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible;background-color:rgba(0,0,0,0) !important}}.offcanvas{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}@media(prefers-reduced-motion: reduce){.offcanvas{transition:none}}.offcanvas.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas.showing,.offcanvas.show:not(.hiding){transform:none}.offcanvas.showing,.offcanvas.hiding,.offcanvas.show{visibility:visible}.offcanvas-backdrop{position:fixed;top:0;left:0;z-index:1040;width:100vw;height:100vh;background-color:#000}.offcanvas-backdrop.fade{opacity:0}.offcanvas-backdrop.show{opacity:.5}.offcanvas-header{display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;justify-content:space-between;-webkit-justify-content:space-between;padding:var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x)}.offcanvas-header .btn-close{padding:calc(var(--bs-offcanvas-padding-y)*.5) calc(var(--bs-offcanvas-padding-x)*.5);margin-top:calc(-0.5*var(--bs-offcanvas-padding-y));margin-right:calc(-0.5*var(--bs-offcanvas-padding-x));margin-bottom:calc(-0.5*var(--bs-offcanvas-padding-y))}.offcanvas-title{margin-bottom:0;line-height:var(--bs-offcanvas-title-line-height)}.offcanvas-body{flex-grow:1;-webkit-flex-grow:1;padding:var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x);overflow-y:auto}.placeholder{display:inline-block;min-height:1em;vertical-align:middle;cursor:wait;background-color:currentcolor;opacity:.5}.placeholder.btn::before{display:inline-block;content:""}.placeholder-xs{min-height:.6em}.placeholder-sm{min-height:.8em}.placeholder-lg{min-height:1.2em}.placeholder-glow .placeholder{animation:placeholder-glow 2s ease-in-out infinite}@keyframes placeholder-glow{50%{opacity:.2}}.placeholder-wave{mask-image:linear-gradient(130deg, #000 55%, rgba(0, 0, 0, 0.8) 75%, #000 95%);-webkit-mask-image:linear-gradient(130deg, #000 55%, rgba(0, 0, 0, 0.8) 75%, #000 95%);mask-size:200% 100%;-webkit-mask-size:200% 100%;animation:placeholder-wave 2s linear infinite}@keyframes placeholder-wave{100%{mask-position:-200% 0%;-webkit-mask-position:-200% 0%}}.clearfix::after{display:block;clear:both;content:""}.text-bg-default{color:#000 !important;background-color:RGBA(var(--bs-default-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-primary{color:#fff !important;background-color:RGBA(var(--bs-primary-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-secondary{color:#fff !important;background-color:RGBA(var(--bs-secondary-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-success{color:#fff !important;background-color:RGBA(var(--bs-success-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-info{color:#000 !important;background-color:RGBA(var(--bs-info-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-warning{color:#000 !important;background-color:RGBA(var(--bs-warning-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-danger{color:#fff !important;background-color:RGBA(var(--bs-danger-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-light{color:#000 !important;background-color:RGBA(var(--bs-light-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-dark{color:#fff !important;background-color:RGBA(var(--bs-dark-rgb), var(--bs-bg-opacity, 1)) !important}.link-default{color:RGBA(var(--bs-default-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-default-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-default:hover,.link-default:focus{color:RGBA(229, 232, 235, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(229, 232, 235, var(--bs-link-underline-opacity, 1)) !important}.link-primary{color:RGBA(var(--bs-primary-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-primary-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-primary:hover,.link-primary:focus{color:RGBA(10, 88, 202, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(10, 88, 202, var(--bs-link-underline-opacity, 1)) !important}.link-secondary{color:RGBA(var(--bs-secondary-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-secondary-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-secondary:hover,.link-secondary:focus{color:RGBA(86, 94, 100, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(86, 94, 100, var(--bs-link-underline-opacity, 1)) !important}.link-success{color:RGBA(var(--bs-success-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-success-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-success:hover,.link-success:focus{color:RGBA(20, 108, 67, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(20, 108, 67, var(--bs-link-underline-opacity, 1)) !important}.link-info{color:RGBA(var(--bs-info-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-info-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-info:hover,.link-info:focus{color:RGBA(61, 213, 243, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(61, 213, 243, var(--bs-link-underline-opacity, 1)) !important}.link-warning{color:RGBA(var(--bs-warning-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-warning-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-warning:hover,.link-warning:focus{color:RGBA(255, 205, 57, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(255, 205, 57, var(--bs-link-underline-opacity, 1)) !important}.link-danger{color:RGBA(var(--bs-danger-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-danger-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-danger:hover,.link-danger:focus{color:RGBA(176, 42, 55, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(176, 42, 55, var(--bs-link-underline-opacity, 1)) !important}.link-light{color:RGBA(var(--bs-light-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-light-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-light:hover,.link-light:focus{color:RGBA(249, 250, 251, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(249, 250, 251, var(--bs-link-underline-opacity, 1)) !important}.link-dark{color:RGBA(var(--bs-dark-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-dark-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-dark:hover,.link-dark:focus{color:RGBA(26, 30, 33, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(26, 30, 33, var(--bs-link-underline-opacity, 1)) !important}.link-body-emphasis{color:RGBA(var(--bs-emphasis-color-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-emphasis-color-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-body-emphasis:hover,.link-body-emphasis:focus{color:RGBA(var(--bs-emphasis-color-rgb), var(--bs-link-opacity, 0.75)) !important;text-decoration-color:RGBA(var(--bs-emphasis-color-rgb), var(--bs-link-underline-opacity, 0.75)) !important}.focus-ring:focus{outline:0;box-shadow:var(--bs-focus-ring-x, 0) var(--bs-focus-ring-y, 0) var(--bs-focus-ring-blur, 0) var(--bs-focus-ring-width) var(--bs-focus-ring-color)}.icon-link{display:inline-flex;gap:.375rem;align-items:center;-webkit-align-items:center;text-decoration-color:rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 0.5));text-underline-offset:.25em;backface-visibility:hidden;-webkit-backface-visibility:hidden;-moz-backface-visibility:hidden;-ms-backface-visibility:hidden;-o-backface-visibility:hidden}.icon-link>.bi{flex-shrink:0;-webkit-flex-shrink:0;width:1em;height:1em;fill:currentcolor;transition:.2s ease-in-out transform}@media(prefers-reduced-motion: reduce){.icon-link>.bi{transition:none}}.icon-link-hover:hover>.bi,.icon-link-hover:focus-visible>.bi{transform:var(--bs-icon-link-transform, translate3d(0.25em, 0, 0))}.ratio{position:relative;width:100%}.ratio::before{display:block;padding-top:var(--bs-aspect-ratio);content:""}.ratio>*{position:absolute;top:0;left:0;width:100%;height:100%}.ratio-1x1{--bs-aspect-ratio: 100%}.ratio-4x3{--bs-aspect-ratio: 75%}.ratio-16x9{--bs-aspect-ratio: 56.25%}.ratio-21x9{--bs-aspect-ratio: 42.8571428571%}.fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030}.fixed-bottom{position:fixed;right:0;bottom:0;left:0;z-index:1030}.sticky-top{position:sticky;top:0;z-index:1020}.sticky-bottom{position:sticky;bottom:0;z-index:1020}@media(min-width: 576px){.sticky-sm-top{position:sticky;top:0;z-index:1020}.sticky-sm-bottom{position:sticky;bottom:0;z-index:1020}}@media(min-width: 768px){.sticky-md-top{position:sticky;top:0;z-index:1020}.sticky-md-bottom{position:sticky;bottom:0;z-index:1020}}@media(min-width: 992px){.sticky-lg-top{position:sticky;top:0;z-index:1020}.sticky-lg-bottom{position:sticky;bottom:0;z-index:1020}}@media(min-width: 1200px){.sticky-xl-top{position:sticky;top:0;z-index:1020}.sticky-xl-bottom{position:sticky;bottom:0;z-index:1020}}@media(min-width: 1400px){.sticky-xxl-top{position:sticky;top:0;z-index:1020}.sticky-xxl-bottom{position:sticky;bottom:0;z-index:1020}}.hstack{display:flex;display:-webkit-flex;flex-direction:row;-webkit-flex-direction:row;align-items:center;-webkit-align-items:center;align-self:stretch;-webkit-align-self:stretch}.vstack{display:flex;display:-webkit-flex;flex:1 1 auto;-webkit-flex:1 1 auto;flex-direction:column;-webkit-flex-direction:column;align-self:stretch;-webkit-align-self:stretch}.visually-hidden,.visually-hidden-focusable:not(:focus):not(:focus-within){width:1px !important;height:1px !important;padding:0 !important;margin:-1px !important;overflow:hidden !important;clip:rect(0, 0, 0, 0) !important;white-space:nowrap !important;border:0 !important}.visually-hidden:not(caption),.visually-hidden-focusable:not(:focus):not(:focus-within):not(caption){position:absolute !important}.stretched-link::after{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;content:""}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vr{display:inline-block;align-self:stretch;-webkit-align-self:stretch;width:1px;min-height:1em;background-color:currentcolor;opacity:.25}.align-baseline{vertical-align:baseline !important}.align-top{vertical-align:top !important}.align-middle{vertical-align:middle !important}.align-bottom{vertical-align:bottom !important}.align-text-bottom{vertical-align:text-bottom !important}.align-text-top{vertical-align:text-top !important}.float-start{float:left !important}.float-end{float:right !important}.float-none{float:none !important}.object-fit-contain{object-fit:contain !important}.object-fit-cover{object-fit:cover !important}.object-fit-fill{object-fit:fill !important}.object-fit-scale{object-fit:scale-down !important}.object-fit-none{object-fit:none !important}.opacity-0{opacity:0 !important}.opacity-25{opacity:.25 !important}.opacity-50{opacity:.5 !important}.opacity-75{opacity:.75 !important}.opacity-100{opacity:1 !important}.overflow-auto{overflow:auto !important}.overflow-hidden{overflow:hidden !important}.overflow-visible{overflow:visible !important}.overflow-scroll{overflow:scroll !important}.overflow-x-auto{overflow-x:auto !important}.overflow-x-hidden{overflow-x:hidden !important}.overflow-x-visible{overflow-x:visible !important}.overflow-x-scroll{overflow-x:scroll !important}.overflow-y-auto{overflow-y:auto !important}.overflow-y-hidden{overflow-y:hidden !important}.overflow-y-visible{overflow-y:visible !important}.overflow-y-scroll{overflow-y:scroll !important}.d-inline{display:inline !important}.d-inline-block{display:inline-block !important}.d-block{display:block !important}.d-grid{display:grid !important}.d-inline-grid{display:inline-grid !important}.d-table{display:table !important}.d-table-row{display:table-row !important}.d-table-cell{display:table-cell !important}.d-flex{display:flex !important}.d-inline-flex{display:inline-flex !important}.d-none{display:none !important}.shadow{box-shadow:0 .5rem 1rem rgba(0,0,0,.15) !important}.shadow-sm{box-shadow:0 .125rem .25rem rgba(0,0,0,.075) !important}.shadow-lg{box-shadow:0 1rem 3rem rgba(0,0,0,.175) !important}.shadow-none{box-shadow:none !important}.focus-ring-default{--bs-focus-ring-color: rgba(var(--bs-default-rgb), var(--bs-focus-ring-opacity))}.focus-ring-primary{--bs-focus-ring-color: rgba(var(--bs-primary-rgb), var(--bs-focus-ring-opacity))}.focus-ring-secondary{--bs-focus-ring-color: rgba(var(--bs-secondary-rgb), var(--bs-focus-ring-opacity))}.focus-ring-success{--bs-focus-ring-color: rgba(var(--bs-success-rgb), var(--bs-focus-ring-opacity))}.focus-ring-info{--bs-focus-ring-color: rgba(var(--bs-info-rgb), var(--bs-focus-ring-opacity))}.focus-ring-warning{--bs-focus-ring-color: rgba(var(--bs-warning-rgb), var(--bs-focus-ring-opacity))}.focus-ring-danger{--bs-focus-ring-color: rgba(var(--bs-danger-rgb), var(--bs-focus-ring-opacity))}.focus-ring-light{--bs-focus-ring-color: rgba(var(--bs-light-rgb), var(--bs-focus-ring-opacity))}.focus-ring-dark{--bs-focus-ring-color: rgba(var(--bs-dark-rgb), var(--bs-focus-ring-opacity))}.position-static{position:static !important}.position-relative{position:relative !important}.position-absolute{position:absolute !important}.position-fixed{position:fixed !important}.position-sticky{position:sticky !important}.top-0{top:0 !important}.top-50{top:50% !important}.top-100{top:100% !important}.bottom-0{bottom:0 !important}.bottom-50{bottom:50% !important}.bottom-100{bottom:100% !important}.start-0{left:0 !important}.start-50{left:50% !important}.start-100{left:100% !important}.end-0{right:0 !important}.end-50{right:50% !important}.end-100{right:100% !important}.translate-middle{transform:translate(-50%, -50%) !important}.translate-middle-x{transform:translateX(-50%) !important}.translate-middle-y{transform:translateY(-50%) !important}.border{border:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important}.border-0{border:0 !important}.border-top{border-top:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important}.border-top-0{border-top:0 !important}.border-end{border-right:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important}.border-end-0{border-right:0 !important}.border-bottom{border-bottom:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important}.border-bottom-0{border-bottom:0 !important}.border-start{border-left:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important}.border-start-0{border-left:0 !important}.border-default{--bs-border-opacity: 1;border-color:rgba(var(--bs-default-rgb), var(--bs-border-opacity)) !important}.border-primary{--bs-border-opacity: 1;border-color:rgba(var(--bs-primary-rgb), var(--bs-border-opacity)) !important}.border-secondary{--bs-border-opacity: 1;border-color:rgba(var(--bs-secondary-rgb), var(--bs-border-opacity)) !important}.border-success{--bs-border-opacity: 1;border-color:rgba(var(--bs-success-rgb), var(--bs-border-opacity)) !important}.border-info{--bs-border-opacity: 1;border-color:rgba(var(--bs-info-rgb), var(--bs-border-opacity)) !important}.border-warning{--bs-border-opacity: 1;border-color:rgba(var(--bs-warning-rgb), var(--bs-border-opacity)) !important}.border-danger{--bs-border-opacity: 1;border-color:rgba(var(--bs-danger-rgb), var(--bs-border-opacity)) !important}.border-light{--bs-border-opacity: 1;border-color:rgba(var(--bs-light-rgb), var(--bs-border-opacity)) !important}.border-dark{--bs-border-opacity: 1;border-color:rgba(var(--bs-dark-rgb), var(--bs-border-opacity)) !important}.border-black{--bs-border-opacity: 1;border-color:rgba(var(--bs-black-rgb), var(--bs-border-opacity)) !important}.border-white{--bs-border-opacity: 1;border-color:rgba(var(--bs-white-rgb), var(--bs-border-opacity)) !important}.border-primary-subtle{border-color:var(--bs-primary-border-subtle) !important}.border-secondary-subtle{border-color:var(--bs-secondary-border-subtle) !important}.border-success-subtle{border-color:var(--bs-success-border-subtle) !important}.border-info-subtle{border-color:var(--bs-info-border-subtle) !important}.border-warning-subtle{border-color:var(--bs-warning-border-subtle) !important}.border-danger-subtle{border-color:var(--bs-danger-border-subtle) !important}.border-light-subtle{border-color:var(--bs-light-border-subtle) !important}.border-dark-subtle{border-color:var(--bs-dark-border-subtle) !important}.border-1{border-width:1px !important}.border-2{border-width:2px !important}.border-3{border-width:3px !important}.border-4{border-width:4px !important}.border-5{border-width:5px !important}.border-opacity-10{--bs-border-opacity: 0.1}.border-opacity-25{--bs-border-opacity: 0.25}.border-opacity-50{--bs-border-opacity: 0.5}.border-opacity-75{--bs-border-opacity: 0.75}.border-opacity-100{--bs-border-opacity: 1}.w-25{width:25% !important}.w-50{width:50% !important}.w-75{width:75% !important}.w-100{width:100% !important}.w-auto{width:auto !important}.mw-100{max-width:100% !important}.vw-100{width:100vw !important}.min-vw-100{min-width:100vw !important}.h-25{height:25% !important}.h-50{height:50% !important}.h-75{height:75% !important}.h-100{height:100% !important}.h-auto{height:auto !important}.mh-100{max-height:100% !important}.vh-100{height:100vh !important}.min-vh-100{min-height:100vh !important}.flex-fill{flex:1 1 auto !important}.flex-row{flex-direction:row !important}.flex-column{flex-direction:column !important}.flex-row-reverse{flex-direction:row-reverse !important}.flex-column-reverse{flex-direction:column-reverse !important}.flex-grow-0{flex-grow:0 !important}.flex-grow-1{flex-grow:1 !important}.flex-shrink-0{flex-shrink:0 !important}.flex-shrink-1{flex-shrink:1 !important}.flex-wrap{flex-wrap:wrap !important}.flex-nowrap{flex-wrap:nowrap !important}.flex-wrap-reverse{flex-wrap:wrap-reverse !important}.justify-content-start{justify-content:flex-start !important}.justify-content-end{justify-content:flex-end !important}.justify-content-center{justify-content:center !important}.justify-content-between{justify-content:space-between !important}.justify-content-around{justify-content:space-around !important}.justify-content-evenly{justify-content:space-evenly !important}.align-items-start{align-items:flex-start !important}.align-items-end{align-items:flex-end !important}.align-items-center{align-items:center !important}.align-items-baseline{align-items:baseline !important}.align-items-stretch{align-items:stretch !important}.align-content-start{align-content:flex-start !important}.align-content-end{align-content:flex-end !important}.align-content-center{align-content:center !important}.align-content-between{align-content:space-between !important}.align-content-around{align-content:space-around !important}.align-content-stretch{align-content:stretch !important}.align-self-auto{align-self:auto !important}.align-self-start{align-self:flex-start !important}.align-self-end{align-self:flex-end !important}.align-self-center{align-self:center !important}.align-self-baseline{align-self:baseline !important}.align-self-stretch{align-self:stretch !important}.order-first{order:-1 !important}.order-0{order:0 !important}.order-1{order:1 !important}.order-2{order:2 !important}.order-3{order:3 !important}.order-4{order:4 !important}.order-5{order:5 !important}.order-last{order:6 !important}.m-0{margin:0 !important}.m-1{margin:.25rem !important}.m-2{margin:.5rem !important}.m-3{margin:1rem !important}.m-4{margin:1.5rem !important}.m-5{margin:3rem !important}.m-auto{margin:auto !important}.mx-0{margin-right:0 !important;margin-left:0 !important}.mx-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-3{margin-right:1rem !important;margin-left:1rem !important}.mx-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-5{margin-right:3rem !important;margin-left:3rem !important}.mx-auto{margin-right:auto !important;margin-left:auto !important}.my-0{margin-top:0 !important;margin-bottom:0 !important}.my-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-0{margin-top:0 !important}.mt-1{margin-top:.25rem !important}.mt-2{margin-top:.5rem !important}.mt-3{margin-top:1rem !important}.mt-4{margin-top:1.5rem !important}.mt-5{margin-top:3rem !important}.mt-auto{margin-top:auto !important}.me-0{margin-right:0 !important}.me-1{margin-right:.25rem !important}.me-2{margin-right:.5rem !important}.me-3{margin-right:1rem !important}.me-4{margin-right:1.5rem !important}.me-5{margin-right:3rem !important}.me-auto{margin-right:auto !important}.mb-0{margin-bottom:0 !important}.mb-1{margin-bottom:.25rem !important}.mb-2{margin-bottom:.5rem !important}.mb-3{margin-bottom:1rem !important}.mb-4{margin-bottom:1.5rem !important}.mb-5{margin-bottom:3rem !important}.mb-auto{margin-bottom:auto !important}.ms-0{margin-left:0 !important}.ms-1{margin-left:.25rem !important}.ms-2{margin-left:.5rem !important}.ms-3{margin-left:1rem !important}.ms-4{margin-left:1.5rem !important}.ms-5{margin-left:3rem !important}.ms-auto{margin-left:auto !important}.p-0{padding:0 !important}.p-1{padding:.25rem !important}.p-2{padding:.5rem !important}.p-3{padding:1rem !important}.p-4{padding:1.5rem !important}.p-5{padding:3rem !important}.px-0{padding-right:0 !important;padding-left:0 !important}.px-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-3{padding-right:1rem !important;padding-left:1rem !important}.px-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-5{padding-right:3rem !important;padding-left:3rem !important}.py-0{padding-top:0 !important;padding-bottom:0 !important}.py-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-0{padding-top:0 !important}.pt-1{padding-top:.25rem !important}.pt-2{padding-top:.5rem !important}.pt-3{padding-top:1rem !important}.pt-4{padding-top:1.5rem !important}.pt-5{padding-top:3rem !important}.pe-0{padding-right:0 !important}.pe-1{padding-right:.25rem !important}.pe-2{padding-right:.5rem !important}.pe-3{padding-right:1rem !important}.pe-4{padding-right:1.5rem !important}.pe-5{padding-right:3rem !important}.pb-0{padding-bottom:0 !important}.pb-1{padding-bottom:.25rem !important}.pb-2{padding-bottom:.5rem !important}.pb-3{padding-bottom:1rem !important}.pb-4{padding-bottom:1.5rem !important}.pb-5{padding-bottom:3rem !important}.ps-0{padding-left:0 !important}.ps-1{padding-left:.25rem !important}.ps-2{padding-left:.5rem !important}.ps-3{padding-left:1rem !important}.ps-4{padding-left:1.5rem !important}.ps-5{padding-left:3rem !important}.gap-0{gap:0 !important}.gap-1{gap:.25rem !important}.gap-2{gap:.5rem !important}.gap-3{gap:1rem !important}.gap-4{gap:1.5rem !important}.gap-5{gap:3rem !important}.row-gap-0{row-gap:0 !important}.row-gap-1{row-gap:.25rem !important}.row-gap-2{row-gap:.5rem !important}.row-gap-3{row-gap:1rem !important}.row-gap-4{row-gap:1.5rem !important}.row-gap-5{row-gap:3rem !important}.column-gap-0{column-gap:0 !important}.column-gap-1{column-gap:.25rem !important}.column-gap-2{column-gap:.5rem !important}.column-gap-3{column-gap:1rem !important}.column-gap-4{column-gap:1.5rem !important}.column-gap-5{column-gap:3rem !important}.font-monospace{font-family:var(--bs-font-monospace) !important}.fs-1{font-size:calc(1.325rem + 0.9vw) !important}.fs-2{font-size:calc(1.29rem + 0.48vw) !important}.fs-3{font-size:calc(1.27rem + 0.24vw) !important}.fs-4{font-size:1.25rem !important}.fs-5{font-size:1.1rem !important}.fs-6{font-size:1rem !important}.fst-italic{font-style:italic !important}.fst-normal{font-style:normal !important}.fw-lighter{font-weight:lighter !important}.fw-light{font-weight:300 !important}.fw-normal{font-weight:400 !important}.fw-medium{font-weight:500 !important}.fw-semibold{font-weight:600 !important}.fw-bold{font-weight:700 !important}.fw-bolder{font-weight:bolder !important}.lh-1{line-height:1 !important}.lh-sm{line-height:1.25 !important}.lh-base{line-height:1.5 !important}.lh-lg{line-height:2 !important}.text-start{text-align:left !important}.text-end{text-align:right !important}.text-center{text-align:center !important}.text-decoration-none{text-decoration:none !important}.text-decoration-underline{text-decoration:underline !important}.text-decoration-line-through{text-decoration:line-through !important}.text-lowercase{text-transform:lowercase !important}.text-uppercase{text-transform:uppercase !important}.text-capitalize{text-transform:capitalize !important}.text-wrap{white-space:normal !important}.text-nowrap{white-space:nowrap !important}.text-break{word-wrap:break-word !important;word-break:break-word !important}.text-default{--bs-text-opacity: 1;color:rgba(var(--bs-default-rgb), var(--bs-text-opacity)) !important}.text-primary{--bs-text-opacity: 1;color:rgba(var(--bs-primary-rgb), var(--bs-text-opacity)) !important}.text-secondary{--bs-text-opacity: 1;color:rgba(var(--bs-secondary-rgb), var(--bs-text-opacity)) !important}.text-success{--bs-text-opacity: 1;color:rgba(var(--bs-success-rgb), var(--bs-text-opacity)) !important}.text-info{--bs-text-opacity: 1;color:rgba(var(--bs-info-rgb), var(--bs-text-opacity)) !important}.text-warning{--bs-text-opacity: 1;color:rgba(var(--bs-warning-rgb), var(--bs-text-opacity)) !important}.text-danger{--bs-text-opacity: 1;color:rgba(var(--bs-danger-rgb), var(--bs-text-opacity)) !important}.text-light{--bs-text-opacity: 1;color:rgba(var(--bs-light-rgb), var(--bs-text-opacity)) !important}.text-dark{--bs-text-opacity: 1;color:rgba(var(--bs-dark-rgb), var(--bs-text-opacity)) !important}.text-black{--bs-text-opacity: 1;color:rgba(var(--bs-black-rgb), var(--bs-text-opacity)) !important}.text-white{--bs-text-opacity: 1;color:rgba(var(--bs-white-rgb), var(--bs-text-opacity)) !important}.text-body{--bs-text-opacity: 1;color:rgba(var(--bs-body-color-rgb), var(--bs-text-opacity)) !important}.text-muted{--bs-text-opacity: 1;color:var(--bs-secondary-color) !important}.text-black-50{--bs-text-opacity: 1;color:rgba(0,0,0,.5) !important}.text-white-50{--bs-text-opacity: 1;color:rgba(255,255,255,.5) !important}.text-body-secondary{--bs-text-opacity: 1;color:var(--bs-secondary-color) !important}.text-body-tertiary{--bs-text-opacity: 1;color:var(--bs-tertiary-color) !important}.text-body-emphasis{--bs-text-opacity: 1;color:var(--bs-emphasis-color) !important}.text-reset{--bs-text-opacity: 1;color:inherit !important}.text-opacity-25{--bs-text-opacity: 0.25}.text-opacity-50{--bs-text-opacity: 0.5}.text-opacity-75{--bs-text-opacity: 0.75}.text-opacity-100{--bs-text-opacity: 1}.text-primary-emphasis{color:var(--bs-primary-text-emphasis) !important}.text-secondary-emphasis{color:var(--bs-secondary-text-emphasis) !important}.text-success-emphasis{color:var(--bs-success-text-emphasis) !important}.text-info-emphasis{color:var(--bs-info-text-emphasis) !important}.text-warning-emphasis{color:var(--bs-warning-text-emphasis) !important}.text-danger-emphasis{color:var(--bs-danger-text-emphasis) !important}.text-light-emphasis{color:var(--bs-light-text-emphasis) !important}.text-dark-emphasis{color:var(--bs-dark-text-emphasis) !important}.link-opacity-10{--bs-link-opacity: 0.1}.link-opacity-10-hover:hover{--bs-link-opacity: 0.1}.link-opacity-25{--bs-link-opacity: 0.25}.link-opacity-25-hover:hover{--bs-link-opacity: 0.25}.link-opacity-50{--bs-link-opacity: 0.5}.link-opacity-50-hover:hover{--bs-link-opacity: 0.5}.link-opacity-75{--bs-link-opacity: 0.75}.link-opacity-75-hover:hover{--bs-link-opacity: 0.75}.link-opacity-100{--bs-link-opacity: 1}.link-opacity-100-hover:hover{--bs-link-opacity: 1}.link-offset-1{text-underline-offset:.125em !important}.link-offset-1-hover:hover{text-underline-offset:.125em !important}.link-offset-2{text-underline-offset:.25em !important}.link-offset-2-hover:hover{text-underline-offset:.25em !important}.link-offset-3{text-underline-offset:.375em !important}.link-offset-3-hover:hover{text-underline-offset:.375em !important}.link-underline-default{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-default-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-primary{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-primary-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-secondary{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-secondary-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-success{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-success-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-info{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-info-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-warning{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-warning-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-danger{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-danger-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-light{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-light-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-dark{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-dark-rgb), var(--bs-link-underline-opacity)) !important}.link-underline{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-link-color-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-underline-opacity-0{--bs-link-underline-opacity: 0}.link-underline-opacity-0-hover:hover{--bs-link-underline-opacity: 0}.link-underline-opacity-10{--bs-link-underline-opacity: 0.1}.link-underline-opacity-10-hover:hover{--bs-link-underline-opacity: 0.1}.link-underline-opacity-25{--bs-link-underline-opacity: 0.25}.link-underline-opacity-25-hover:hover{--bs-link-underline-opacity: 0.25}.link-underline-opacity-50{--bs-link-underline-opacity: 0.5}.link-underline-opacity-50-hover:hover{--bs-link-underline-opacity: 0.5}.link-underline-opacity-75{--bs-link-underline-opacity: 0.75}.link-underline-opacity-75-hover:hover{--bs-link-underline-opacity: 0.75}.link-underline-opacity-100{--bs-link-underline-opacity: 1}.link-underline-opacity-100-hover:hover{--bs-link-underline-opacity: 1}.bg-default{--bs-bg-opacity: 1;background-color:rgba(var(--bs-default-rgb), var(--bs-bg-opacity)) !important}.bg-primary{--bs-bg-opacity: 1;background-color:rgba(var(--bs-primary-rgb), var(--bs-bg-opacity)) !important}.bg-secondary{--bs-bg-opacity: 1;background-color:rgba(var(--bs-secondary-rgb), var(--bs-bg-opacity)) !important}.bg-success{--bs-bg-opacity: 1;background-color:rgba(var(--bs-success-rgb), var(--bs-bg-opacity)) !important}.bg-info{--bs-bg-opacity: 1;background-color:rgba(var(--bs-info-rgb), var(--bs-bg-opacity)) !important}.bg-warning{--bs-bg-opacity: 1;background-color:rgba(var(--bs-warning-rgb), var(--bs-bg-opacity)) !important}.bg-danger{--bs-bg-opacity: 1;background-color:rgba(var(--bs-danger-rgb), var(--bs-bg-opacity)) !important}.bg-light{--bs-bg-opacity: 1;background-color:rgba(var(--bs-light-rgb), var(--bs-bg-opacity)) !important}.bg-dark{--bs-bg-opacity: 1;background-color:rgba(var(--bs-dark-rgb), var(--bs-bg-opacity)) !important}.bg-black{--bs-bg-opacity: 1;background-color:rgba(var(--bs-black-rgb), var(--bs-bg-opacity)) !important}.bg-white{--bs-bg-opacity: 1;background-color:rgba(var(--bs-white-rgb), var(--bs-bg-opacity)) !important}.bg-body{--bs-bg-opacity: 1;background-color:rgba(var(--bs-body-bg-rgb), var(--bs-bg-opacity)) !important}.bg-transparent{--bs-bg-opacity: 1;background-color:rgba(0,0,0,0) !important}.bg-body-secondary{--bs-bg-opacity: 1;background-color:rgba(var(--bs-secondary-bg-rgb), var(--bs-bg-opacity)) !important}.bg-body-tertiary{--bs-bg-opacity: 1;background-color:rgba(var(--bs-tertiary-bg-rgb), var(--bs-bg-opacity)) !important}.bg-opacity-10{--bs-bg-opacity: 0.1}.bg-opacity-25{--bs-bg-opacity: 0.25}.bg-opacity-50{--bs-bg-opacity: 0.5}.bg-opacity-75{--bs-bg-opacity: 0.75}.bg-opacity-100{--bs-bg-opacity: 1}.bg-primary-subtle{background-color:var(--bs-primary-bg-subtle) !important}.bg-secondary-subtle{background-color:var(--bs-secondary-bg-subtle) !important}.bg-success-subtle{background-color:var(--bs-success-bg-subtle) !important}.bg-info-subtle{background-color:var(--bs-info-bg-subtle) !important}.bg-warning-subtle{background-color:var(--bs-warning-bg-subtle) !important}.bg-danger-subtle{background-color:var(--bs-danger-bg-subtle) !important}.bg-light-subtle{background-color:var(--bs-light-bg-subtle) !important}.bg-dark-subtle{background-color:var(--bs-dark-bg-subtle) !important}.bg-gradient{background-image:var(--bs-gradient) !important}.user-select-all{user-select:all !important}.user-select-auto{user-select:auto !important}.user-select-none{user-select:none !important}.pe-none{pointer-events:none !important}.pe-auto{pointer-events:auto !important}.rounded{border-radius:var(--bs-border-radius) !important}.rounded-0{border-radius:0 !important}.rounded-1{border-radius:var(--bs-border-radius-sm) !important}.rounded-2{border-radius:var(--bs-border-radius) !important}.rounded-3{border-radius:var(--bs-border-radius-lg) !important}.rounded-4{border-radius:var(--bs-border-radius-xl) !important}.rounded-5{border-radius:var(--bs-border-radius-xxl) !important}.rounded-circle{border-radius:50% !important}.rounded-pill{border-radius:var(--bs-border-radius-pill) !important}.rounded-top{border-top-left-radius:var(--bs-border-radius) !important;border-top-right-radius:var(--bs-border-radius) !important}.rounded-top-0{border-top-left-radius:0 !important;border-top-right-radius:0 !important}.rounded-top-1{border-top-left-radius:var(--bs-border-radius-sm) !important;border-top-right-radius:var(--bs-border-radius-sm) !important}.rounded-top-2{border-top-left-radius:var(--bs-border-radius) !important;border-top-right-radius:var(--bs-border-radius) !important}.rounded-top-3{border-top-left-radius:var(--bs-border-radius-lg) !important;border-top-right-radius:var(--bs-border-radius-lg) !important}.rounded-top-4{border-top-left-radius:var(--bs-border-radius-xl) !important;border-top-right-radius:var(--bs-border-radius-xl) !important}.rounded-top-5{border-top-left-radius:var(--bs-border-radius-xxl) !important;border-top-right-radius:var(--bs-border-radius-xxl) !important}.rounded-top-circle{border-top-left-radius:50% !important;border-top-right-radius:50% !important}.rounded-top-pill{border-top-left-radius:var(--bs-border-radius-pill) !important;border-top-right-radius:var(--bs-border-radius-pill) !important}.rounded-end{border-top-right-radius:var(--bs-border-radius) !important;border-bottom-right-radius:var(--bs-border-radius) !important}.rounded-end-0{border-top-right-radius:0 !important;border-bottom-right-radius:0 !important}.rounded-end-1{border-top-right-radius:var(--bs-border-radius-sm) !important;border-bottom-right-radius:var(--bs-border-radius-sm) !important}.rounded-end-2{border-top-right-radius:var(--bs-border-radius) !important;border-bottom-right-radius:var(--bs-border-radius) !important}.rounded-end-3{border-top-right-radius:var(--bs-border-radius-lg) !important;border-bottom-right-radius:var(--bs-border-radius-lg) !important}.rounded-end-4{border-top-right-radius:var(--bs-border-radius-xl) !important;border-bottom-right-radius:var(--bs-border-radius-xl) !important}.rounded-end-5{border-top-right-radius:var(--bs-border-radius-xxl) !important;border-bottom-right-radius:var(--bs-border-radius-xxl) !important}.rounded-end-circle{border-top-right-radius:50% !important;border-bottom-right-radius:50% !important}.rounded-end-pill{border-top-right-radius:var(--bs-border-radius-pill) !important;border-bottom-right-radius:var(--bs-border-radius-pill) !important}.rounded-bottom{border-bottom-right-radius:var(--bs-border-radius) !important;border-bottom-left-radius:var(--bs-border-radius) !important}.rounded-bottom-0{border-bottom-right-radius:0 !important;border-bottom-left-radius:0 !important}.rounded-bottom-1{border-bottom-right-radius:var(--bs-border-radius-sm) !important;border-bottom-left-radius:var(--bs-border-radius-sm) !important}.rounded-bottom-2{border-bottom-right-radius:var(--bs-border-radius) !important;border-bottom-left-radius:var(--bs-border-radius) !important}.rounded-bottom-3{border-bottom-right-radius:var(--bs-border-radius-lg) !important;border-bottom-left-radius:var(--bs-border-radius-lg) !important}.rounded-bottom-4{border-bottom-right-radius:var(--bs-border-radius-xl) !important;border-bottom-left-radius:var(--bs-border-radius-xl) !important}.rounded-bottom-5{border-bottom-right-radius:var(--bs-border-radius-xxl) !important;border-bottom-left-radius:var(--bs-border-radius-xxl) !important}.rounded-bottom-circle{border-bottom-right-radius:50% !important;border-bottom-left-radius:50% !important}.rounded-bottom-pill{border-bottom-right-radius:var(--bs-border-radius-pill) !important;border-bottom-left-radius:var(--bs-border-radius-pill) !important}.rounded-start{border-bottom-left-radius:var(--bs-border-radius) !important;border-top-left-radius:var(--bs-border-radius) !important}.rounded-start-0{border-bottom-left-radius:0 !important;border-top-left-radius:0 !important}.rounded-start-1{border-bottom-left-radius:var(--bs-border-radius-sm) !important;border-top-left-radius:var(--bs-border-radius-sm) !important}.rounded-start-2{border-bottom-left-radius:var(--bs-border-radius) !important;border-top-left-radius:var(--bs-border-radius) !important}.rounded-start-3{border-bottom-left-radius:var(--bs-border-radius-lg) !important;border-top-left-radius:var(--bs-border-radius-lg) !important}.rounded-start-4{border-bottom-left-radius:var(--bs-border-radius-xl) !important;border-top-left-radius:var(--bs-border-radius-xl) !important}.rounded-start-5{border-bottom-left-radius:var(--bs-border-radius-xxl) !important;border-top-left-radius:var(--bs-border-radius-xxl) !important}.rounded-start-circle{border-bottom-left-radius:50% !important;border-top-left-radius:50% !important}.rounded-start-pill{border-bottom-left-radius:var(--bs-border-radius-pill) !important;border-top-left-radius:var(--bs-border-radius-pill) !important}.visible{visibility:visible !important}.invisible{visibility:hidden !important}.z-n1{z-index:-1 !important}.z-0{z-index:0 !important}.z-1{z-index:1 !important}.z-2{z-index:2 !important}.z-3{z-index:3 !important}@media(min-width: 576px){.float-sm-start{float:left !important}.float-sm-end{float:right !important}.float-sm-none{float:none !important}.object-fit-sm-contain{object-fit:contain !important}.object-fit-sm-cover{object-fit:cover !important}.object-fit-sm-fill{object-fit:fill !important}.object-fit-sm-scale{object-fit:scale-down !important}.object-fit-sm-none{object-fit:none !important}.d-sm-inline{display:inline !important}.d-sm-inline-block{display:inline-block !important}.d-sm-block{display:block !important}.d-sm-grid{display:grid !important}.d-sm-inline-grid{display:inline-grid !important}.d-sm-table{display:table !important}.d-sm-table-row{display:table-row !important}.d-sm-table-cell{display:table-cell !important}.d-sm-flex{display:flex !important}.d-sm-inline-flex{display:inline-flex !important}.d-sm-none{display:none !important}.flex-sm-fill{flex:1 1 auto !important}.flex-sm-row{flex-direction:row !important}.flex-sm-column{flex-direction:column !important}.flex-sm-row-reverse{flex-direction:row-reverse !important}.flex-sm-column-reverse{flex-direction:column-reverse !important}.flex-sm-grow-0{flex-grow:0 !important}.flex-sm-grow-1{flex-grow:1 !important}.flex-sm-shrink-0{flex-shrink:0 !important}.flex-sm-shrink-1{flex-shrink:1 !important}.flex-sm-wrap{flex-wrap:wrap !important}.flex-sm-nowrap{flex-wrap:nowrap !important}.flex-sm-wrap-reverse{flex-wrap:wrap-reverse !important}.justify-content-sm-start{justify-content:flex-start !important}.justify-content-sm-end{justify-content:flex-end !important}.justify-content-sm-center{justify-content:center !important}.justify-content-sm-between{justify-content:space-between !important}.justify-content-sm-around{justify-content:space-around !important}.justify-content-sm-evenly{justify-content:space-evenly !important}.align-items-sm-start{align-items:flex-start !important}.align-items-sm-end{align-items:flex-end !important}.align-items-sm-center{align-items:center !important}.align-items-sm-baseline{align-items:baseline !important}.align-items-sm-stretch{align-items:stretch !important}.align-content-sm-start{align-content:flex-start !important}.align-content-sm-end{align-content:flex-end !important}.align-content-sm-center{align-content:center !important}.align-content-sm-between{align-content:space-between !important}.align-content-sm-around{align-content:space-around !important}.align-content-sm-stretch{align-content:stretch !important}.align-self-sm-auto{align-self:auto !important}.align-self-sm-start{align-self:flex-start !important}.align-self-sm-end{align-self:flex-end !important}.align-self-sm-center{align-self:center !important}.align-self-sm-baseline{align-self:baseline !important}.align-self-sm-stretch{align-self:stretch !important}.order-sm-first{order:-1 !important}.order-sm-0{order:0 !important}.order-sm-1{order:1 !important}.order-sm-2{order:2 !important}.order-sm-3{order:3 !important}.order-sm-4{order:4 !important}.order-sm-5{order:5 !important}.order-sm-last{order:6 !important}.m-sm-0{margin:0 !important}.m-sm-1{margin:.25rem !important}.m-sm-2{margin:.5rem !important}.m-sm-3{margin:1rem !important}.m-sm-4{margin:1.5rem !important}.m-sm-5{margin:3rem !important}.m-sm-auto{margin:auto !important}.mx-sm-0{margin-right:0 !important;margin-left:0 !important}.mx-sm-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-sm-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-sm-3{margin-right:1rem !important;margin-left:1rem !important}.mx-sm-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-sm-5{margin-right:3rem !important;margin-left:3rem !important}.mx-sm-auto{margin-right:auto !important;margin-left:auto !important}.my-sm-0{margin-top:0 !important;margin-bottom:0 !important}.my-sm-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-sm-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-sm-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-sm-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-sm-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-sm-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-sm-0{margin-top:0 !important}.mt-sm-1{margin-top:.25rem !important}.mt-sm-2{margin-top:.5rem !important}.mt-sm-3{margin-top:1rem !important}.mt-sm-4{margin-top:1.5rem !important}.mt-sm-5{margin-top:3rem !important}.mt-sm-auto{margin-top:auto !important}.me-sm-0{margin-right:0 !important}.me-sm-1{margin-right:.25rem !important}.me-sm-2{margin-right:.5rem !important}.me-sm-3{margin-right:1rem !important}.me-sm-4{margin-right:1.5rem !important}.me-sm-5{margin-right:3rem !important}.me-sm-auto{margin-right:auto !important}.mb-sm-0{margin-bottom:0 !important}.mb-sm-1{margin-bottom:.25rem !important}.mb-sm-2{margin-bottom:.5rem !important}.mb-sm-3{margin-bottom:1rem !important}.mb-sm-4{margin-bottom:1.5rem !important}.mb-sm-5{margin-bottom:3rem !important}.mb-sm-auto{margin-bottom:auto !important}.ms-sm-0{margin-left:0 !important}.ms-sm-1{margin-left:.25rem !important}.ms-sm-2{margin-left:.5rem !important}.ms-sm-3{margin-left:1rem !important}.ms-sm-4{margin-left:1.5rem !important}.ms-sm-5{margin-left:3rem !important}.ms-sm-auto{margin-left:auto !important}.p-sm-0{padding:0 !important}.p-sm-1{padding:.25rem !important}.p-sm-2{padding:.5rem !important}.p-sm-3{padding:1rem !important}.p-sm-4{padding:1.5rem !important}.p-sm-5{padding:3rem !important}.px-sm-0{padding-right:0 !important;padding-left:0 !important}.px-sm-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-sm-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-sm-3{padding-right:1rem !important;padding-left:1rem !important}.px-sm-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-sm-5{padding-right:3rem !important;padding-left:3rem !important}.py-sm-0{padding-top:0 !important;padding-bottom:0 !important}.py-sm-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-sm-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-sm-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-sm-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-sm-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-sm-0{padding-top:0 !important}.pt-sm-1{padding-top:.25rem !important}.pt-sm-2{padding-top:.5rem !important}.pt-sm-3{padding-top:1rem !important}.pt-sm-4{padding-top:1.5rem !important}.pt-sm-5{padding-top:3rem !important}.pe-sm-0{padding-right:0 !important}.pe-sm-1{padding-right:.25rem !important}.pe-sm-2{padding-right:.5rem !important}.pe-sm-3{padding-right:1rem !important}.pe-sm-4{padding-right:1.5rem !important}.pe-sm-5{padding-right:3rem !important}.pb-sm-0{padding-bottom:0 !important}.pb-sm-1{padding-bottom:.25rem !important}.pb-sm-2{padding-bottom:.5rem !important}.pb-sm-3{padding-bottom:1rem !important}.pb-sm-4{padding-bottom:1.5rem !important}.pb-sm-5{padding-bottom:3rem !important}.ps-sm-0{padding-left:0 !important}.ps-sm-1{padding-left:.25rem !important}.ps-sm-2{padding-left:.5rem !important}.ps-sm-3{padding-left:1rem !important}.ps-sm-4{padding-left:1.5rem !important}.ps-sm-5{padding-left:3rem !important}.gap-sm-0{gap:0 !important}.gap-sm-1{gap:.25rem !important}.gap-sm-2{gap:.5rem !important}.gap-sm-3{gap:1rem !important}.gap-sm-4{gap:1.5rem !important}.gap-sm-5{gap:3rem !important}.row-gap-sm-0{row-gap:0 !important}.row-gap-sm-1{row-gap:.25rem !important}.row-gap-sm-2{row-gap:.5rem !important}.row-gap-sm-3{row-gap:1rem !important}.row-gap-sm-4{row-gap:1.5rem !important}.row-gap-sm-5{row-gap:3rem !important}.column-gap-sm-0{column-gap:0 !important}.column-gap-sm-1{column-gap:.25rem !important}.column-gap-sm-2{column-gap:.5rem !important}.column-gap-sm-3{column-gap:1rem !important}.column-gap-sm-4{column-gap:1.5rem !important}.column-gap-sm-5{column-gap:3rem !important}.text-sm-start{text-align:left !important}.text-sm-end{text-align:right !important}.text-sm-center{text-align:center !important}}@media(min-width: 768px){.float-md-start{float:left !important}.float-md-end{float:right !important}.float-md-none{float:none !important}.object-fit-md-contain{object-fit:contain !important}.object-fit-md-cover{object-fit:cover !important}.object-fit-md-fill{object-fit:fill !important}.object-fit-md-scale{object-fit:scale-down !important}.object-fit-md-none{object-fit:none !important}.d-md-inline{display:inline !important}.d-md-inline-block{display:inline-block !important}.d-md-block{display:block !important}.d-md-grid{display:grid !important}.d-md-inline-grid{display:inline-grid !important}.d-md-table{display:table !important}.d-md-table-row{display:table-row !important}.d-md-table-cell{display:table-cell !important}.d-md-flex{display:flex !important}.d-md-inline-flex{display:inline-flex !important}.d-md-none{display:none !important}.flex-md-fill{flex:1 1 auto !important}.flex-md-row{flex-direction:row !important}.flex-md-column{flex-direction:column !important}.flex-md-row-reverse{flex-direction:row-reverse !important}.flex-md-column-reverse{flex-direction:column-reverse !important}.flex-md-grow-0{flex-grow:0 !important}.flex-md-grow-1{flex-grow:1 !important}.flex-md-shrink-0{flex-shrink:0 !important}.flex-md-shrink-1{flex-shrink:1 !important}.flex-md-wrap{flex-wrap:wrap !important}.flex-md-nowrap{flex-wrap:nowrap !important}.flex-md-wrap-reverse{flex-wrap:wrap-reverse !important}.justify-content-md-start{justify-content:flex-start !important}.justify-content-md-end{justify-content:flex-end !important}.justify-content-md-center{justify-content:center !important}.justify-content-md-between{justify-content:space-between !important}.justify-content-md-around{justify-content:space-around !important}.justify-content-md-evenly{justify-content:space-evenly !important}.align-items-md-start{align-items:flex-start !important}.align-items-md-end{align-items:flex-end !important}.align-items-md-center{align-items:center !important}.align-items-md-baseline{align-items:baseline !important}.align-items-md-stretch{align-items:stretch !important}.align-content-md-start{align-content:flex-start !important}.align-content-md-end{align-content:flex-end !important}.align-content-md-center{align-content:center !important}.align-content-md-between{align-content:space-between !important}.align-content-md-around{align-content:space-around !important}.align-content-md-stretch{align-content:stretch !important}.align-self-md-auto{align-self:auto !important}.align-self-md-start{align-self:flex-start !important}.align-self-md-end{align-self:flex-end !important}.align-self-md-center{align-self:center !important}.align-self-md-baseline{align-self:baseline !important}.align-self-md-stretch{align-self:stretch !important}.order-md-first{order:-1 !important}.order-md-0{order:0 !important}.order-md-1{order:1 !important}.order-md-2{order:2 !important}.order-md-3{order:3 !important}.order-md-4{order:4 !important}.order-md-5{order:5 !important}.order-md-last{order:6 !important}.m-md-0{margin:0 !important}.m-md-1{margin:.25rem !important}.m-md-2{margin:.5rem !important}.m-md-3{margin:1rem !important}.m-md-4{margin:1.5rem !important}.m-md-5{margin:3rem !important}.m-md-auto{margin:auto !important}.mx-md-0{margin-right:0 !important;margin-left:0 !important}.mx-md-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-md-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-md-3{margin-right:1rem !important;margin-left:1rem !important}.mx-md-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-md-5{margin-right:3rem !important;margin-left:3rem !important}.mx-md-auto{margin-right:auto !important;margin-left:auto !important}.my-md-0{margin-top:0 !important;margin-bottom:0 !important}.my-md-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-md-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-md-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-md-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-md-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-md-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-md-0{margin-top:0 !important}.mt-md-1{margin-top:.25rem !important}.mt-md-2{margin-top:.5rem !important}.mt-md-3{margin-top:1rem !important}.mt-md-4{margin-top:1.5rem !important}.mt-md-5{margin-top:3rem !important}.mt-md-auto{margin-top:auto !important}.me-md-0{margin-right:0 !important}.me-md-1{margin-right:.25rem !important}.me-md-2{margin-right:.5rem !important}.me-md-3{margin-right:1rem !important}.me-md-4{margin-right:1.5rem !important}.me-md-5{margin-right:3rem !important}.me-md-auto{margin-right:auto !important}.mb-md-0{margin-bottom:0 !important}.mb-md-1{margin-bottom:.25rem !important}.mb-md-2{margin-bottom:.5rem !important}.mb-md-3{margin-bottom:1rem !important}.mb-md-4{margin-bottom:1.5rem !important}.mb-md-5{margin-bottom:3rem !important}.mb-md-auto{margin-bottom:auto !important}.ms-md-0{margin-left:0 !important}.ms-md-1{margin-left:.25rem !important}.ms-md-2{margin-left:.5rem !important}.ms-md-3{margin-left:1rem !important}.ms-md-4{margin-left:1.5rem !important}.ms-md-5{margin-left:3rem !important}.ms-md-auto{margin-left:auto !important}.p-md-0{padding:0 !important}.p-md-1{padding:.25rem !important}.p-md-2{padding:.5rem !important}.p-md-3{padding:1rem !important}.p-md-4{padding:1.5rem !important}.p-md-5{padding:3rem !important}.px-md-0{padding-right:0 !important;padding-left:0 !important}.px-md-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-md-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-md-3{padding-right:1rem !important;padding-left:1rem !important}.px-md-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-md-5{padding-right:3rem !important;padding-left:3rem !important}.py-md-0{padding-top:0 !important;padding-bottom:0 !important}.py-md-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-md-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-md-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-md-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-md-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-md-0{padding-top:0 !important}.pt-md-1{padding-top:.25rem !important}.pt-md-2{padding-top:.5rem !important}.pt-md-3{padding-top:1rem !important}.pt-md-4{padding-top:1.5rem !important}.pt-md-5{padding-top:3rem !important}.pe-md-0{padding-right:0 !important}.pe-md-1{padding-right:.25rem !important}.pe-md-2{padding-right:.5rem !important}.pe-md-3{padding-right:1rem !important}.pe-md-4{padding-right:1.5rem !important}.pe-md-5{padding-right:3rem !important}.pb-md-0{padding-bottom:0 !important}.pb-md-1{padding-bottom:.25rem !important}.pb-md-2{padding-bottom:.5rem !important}.pb-md-3{padding-bottom:1rem !important}.pb-md-4{padding-bottom:1.5rem !important}.pb-md-5{padding-bottom:3rem !important}.ps-md-0{padding-left:0 !important}.ps-md-1{padding-left:.25rem !important}.ps-md-2{padding-left:.5rem !important}.ps-md-3{padding-left:1rem !important}.ps-md-4{padding-left:1.5rem !important}.ps-md-5{padding-left:3rem !important}.gap-md-0{gap:0 !important}.gap-md-1{gap:.25rem !important}.gap-md-2{gap:.5rem !important}.gap-md-3{gap:1rem !important}.gap-md-4{gap:1.5rem !important}.gap-md-5{gap:3rem !important}.row-gap-md-0{row-gap:0 !important}.row-gap-md-1{row-gap:.25rem !important}.row-gap-md-2{row-gap:.5rem !important}.row-gap-md-3{row-gap:1rem !important}.row-gap-md-4{row-gap:1.5rem !important}.row-gap-md-5{row-gap:3rem !important}.column-gap-md-0{column-gap:0 !important}.column-gap-md-1{column-gap:.25rem !important}.column-gap-md-2{column-gap:.5rem !important}.column-gap-md-3{column-gap:1rem !important}.column-gap-md-4{column-gap:1.5rem !important}.column-gap-md-5{column-gap:3rem !important}.text-md-start{text-align:left !important}.text-md-end{text-align:right !important}.text-md-center{text-align:center !important}}@media(min-width: 992px){.float-lg-start{float:left !important}.float-lg-end{float:right !important}.float-lg-none{float:none !important}.object-fit-lg-contain{object-fit:contain !important}.object-fit-lg-cover{object-fit:cover !important}.object-fit-lg-fill{object-fit:fill !important}.object-fit-lg-scale{object-fit:scale-down !important}.object-fit-lg-none{object-fit:none !important}.d-lg-inline{display:inline !important}.d-lg-inline-block{display:inline-block !important}.d-lg-block{display:block !important}.d-lg-grid{display:grid !important}.d-lg-inline-grid{display:inline-grid !important}.d-lg-table{display:table !important}.d-lg-table-row{display:table-row !important}.d-lg-table-cell{display:table-cell !important}.d-lg-flex{display:flex !important}.d-lg-inline-flex{display:inline-flex !important}.d-lg-none{display:none !important}.flex-lg-fill{flex:1 1 auto !important}.flex-lg-row{flex-direction:row !important}.flex-lg-column{flex-direction:column !important}.flex-lg-row-reverse{flex-direction:row-reverse !important}.flex-lg-column-reverse{flex-direction:column-reverse !important}.flex-lg-grow-0{flex-grow:0 !important}.flex-lg-grow-1{flex-grow:1 !important}.flex-lg-shrink-0{flex-shrink:0 !important}.flex-lg-shrink-1{flex-shrink:1 !important}.flex-lg-wrap{flex-wrap:wrap !important}.flex-lg-nowrap{flex-wrap:nowrap !important}.flex-lg-wrap-reverse{flex-wrap:wrap-reverse !important}.justify-content-lg-start{justify-content:flex-start !important}.justify-content-lg-end{justify-content:flex-end !important}.justify-content-lg-center{justify-content:center !important}.justify-content-lg-between{justify-content:space-between !important}.justify-content-lg-around{justify-content:space-around !important}.justify-content-lg-evenly{justify-content:space-evenly !important}.align-items-lg-start{align-items:flex-start !important}.align-items-lg-end{align-items:flex-end !important}.align-items-lg-center{align-items:center !important}.align-items-lg-baseline{align-items:baseline !important}.align-items-lg-stretch{align-items:stretch !important}.align-content-lg-start{align-content:flex-start !important}.align-content-lg-end{align-content:flex-end !important}.align-content-lg-center{align-content:center !important}.align-content-lg-between{align-content:space-between !important}.align-content-lg-around{align-content:space-around !important}.align-content-lg-stretch{align-content:stretch !important}.align-self-lg-auto{align-self:auto !important}.align-self-lg-start{align-self:flex-start !important}.align-self-lg-end{align-self:flex-end !important}.align-self-lg-center{align-self:center !important}.align-self-lg-baseline{align-self:baseline !important}.align-self-lg-stretch{align-self:stretch !important}.order-lg-first{order:-1 !important}.order-lg-0{order:0 !important}.order-lg-1{order:1 !important}.order-lg-2{order:2 !important}.order-lg-3{order:3 !important}.order-lg-4{order:4 !important}.order-lg-5{order:5 !important}.order-lg-last{order:6 !important}.m-lg-0{margin:0 !important}.m-lg-1{margin:.25rem !important}.m-lg-2{margin:.5rem !important}.m-lg-3{margin:1rem !important}.m-lg-4{margin:1.5rem !important}.m-lg-5{margin:3rem !important}.m-lg-auto{margin:auto !important}.mx-lg-0{margin-right:0 !important;margin-left:0 !important}.mx-lg-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-lg-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-lg-3{margin-right:1rem !important;margin-left:1rem !important}.mx-lg-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-lg-5{margin-right:3rem !important;margin-left:3rem !important}.mx-lg-auto{margin-right:auto !important;margin-left:auto !important}.my-lg-0{margin-top:0 !important;margin-bottom:0 !important}.my-lg-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-lg-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-lg-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-lg-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-lg-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-lg-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-lg-0{margin-top:0 !important}.mt-lg-1{margin-top:.25rem !important}.mt-lg-2{margin-top:.5rem !important}.mt-lg-3{margin-top:1rem !important}.mt-lg-4{margin-top:1.5rem !important}.mt-lg-5{margin-top:3rem !important}.mt-lg-auto{margin-top:auto !important}.me-lg-0{margin-right:0 !important}.me-lg-1{margin-right:.25rem !important}.me-lg-2{margin-right:.5rem !important}.me-lg-3{margin-right:1rem !important}.me-lg-4{margin-right:1.5rem !important}.me-lg-5{margin-right:3rem !important}.me-lg-auto{margin-right:auto !important}.mb-lg-0{margin-bottom:0 !important}.mb-lg-1{margin-bottom:.25rem !important}.mb-lg-2{margin-bottom:.5rem !important}.mb-lg-3{margin-bottom:1rem !important}.mb-lg-4{margin-bottom:1.5rem !important}.mb-lg-5{margin-bottom:3rem !important}.mb-lg-auto{margin-bottom:auto !important}.ms-lg-0{margin-left:0 !important}.ms-lg-1{margin-left:.25rem !important}.ms-lg-2{margin-left:.5rem !important}.ms-lg-3{margin-left:1rem !important}.ms-lg-4{margin-left:1.5rem !important}.ms-lg-5{margin-left:3rem !important}.ms-lg-auto{margin-left:auto !important}.p-lg-0{padding:0 !important}.p-lg-1{padding:.25rem !important}.p-lg-2{padding:.5rem !important}.p-lg-3{padding:1rem !important}.p-lg-4{padding:1.5rem !important}.p-lg-5{padding:3rem !important}.px-lg-0{padding-right:0 !important;padding-left:0 !important}.px-lg-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-lg-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-lg-3{padding-right:1rem !important;padding-left:1rem !important}.px-lg-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-lg-5{padding-right:3rem !important;padding-left:3rem !important}.py-lg-0{padding-top:0 !important;padding-bottom:0 !important}.py-lg-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-lg-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-lg-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-lg-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-lg-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-lg-0{padding-top:0 !important}.pt-lg-1{padding-top:.25rem !important}.pt-lg-2{padding-top:.5rem !important}.pt-lg-3{padding-top:1rem !important}.pt-lg-4{padding-top:1.5rem !important}.pt-lg-5{padding-top:3rem !important}.pe-lg-0{padding-right:0 !important}.pe-lg-1{padding-right:.25rem !important}.pe-lg-2{padding-right:.5rem !important}.pe-lg-3{padding-right:1rem !important}.pe-lg-4{padding-right:1.5rem !important}.pe-lg-5{padding-right:3rem !important}.pb-lg-0{padding-bottom:0 !important}.pb-lg-1{padding-bottom:.25rem !important}.pb-lg-2{padding-bottom:.5rem !important}.pb-lg-3{padding-bottom:1rem !important}.pb-lg-4{padding-bottom:1.5rem !important}.pb-lg-5{padding-bottom:3rem !important}.ps-lg-0{padding-left:0 !important}.ps-lg-1{padding-left:.25rem !important}.ps-lg-2{padding-left:.5rem !important}.ps-lg-3{padding-left:1rem !important}.ps-lg-4{padding-left:1.5rem !important}.ps-lg-5{padding-left:3rem !important}.gap-lg-0{gap:0 !important}.gap-lg-1{gap:.25rem !important}.gap-lg-2{gap:.5rem !important}.gap-lg-3{gap:1rem !important}.gap-lg-4{gap:1.5rem !important}.gap-lg-5{gap:3rem !important}.row-gap-lg-0{row-gap:0 !important}.row-gap-lg-1{row-gap:.25rem !important}.row-gap-lg-2{row-gap:.5rem !important}.row-gap-lg-3{row-gap:1rem !important}.row-gap-lg-4{row-gap:1.5rem !important}.row-gap-lg-5{row-gap:3rem !important}.column-gap-lg-0{column-gap:0 !important}.column-gap-lg-1{column-gap:.25rem !important}.column-gap-lg-2{column-gap:.5rem !important}.column-gap-lg-3{column-gap:1rem !important}.column-gap-lg-4{column-gap:1.5rem !important}.column-gap-lg-5{column-gap:3rem !important}.text-lg-start{text-align:left !important}.text-lg-end{text-align:right !important}.text-lg-center{text-align:center !important}}@media(min-width: 1200px){.float-xl-start{float:left !important}.float-xl-end{float:right !important}.float-xl-none{float:none !important}.object-fit-xl-contain{object-fit:contain !important}.object-fit-xl-cover{object-fit:cover !important}.object-fit-xl-fill{object-fit:fill !important}.object-fit-xl-scale{object-fit:scale-down !important}.object-fit-xl-none{object-fit:none !important}.d-xl-inline{display:inline !important}.d-xl-inline-block{display:inline-block !important}.d-xl-block{display:block !important}.d-xl-grid{display:grid !important}.d-xl-inline-grid{display:inline-grid !important}.d-xl-table{display:table !important}.d-xl-table-row{display:table-row !important}.d-xl-table-cell{display:table-cell !important}.d-xl-flex{display:flex !important}.d-xl-inline-flex{display:inline-flex !important}.d-xl-none{display:none !important}.flex-xl-fill{flex:1 1 auto !important}.flex-xl-row{flex-direction:row !important}.flex-xl-column{flex-direction:column !important}.flex-xl-row-reverse{flex-direction:row-reverse !important}.flex-xl-column-reverse{flex-direction:column-reverse !important}.flex-xl-grow-0{flex-grow:0 !important}.flex-xl-grow-1{flex-grow:1 !important}.flex-xl-shrink-0{flex-shrink:0 !important}.flex-xl-shrink-1{flex-shrink:1 !important}.flex-xl-wrap{flex-wrap:wrap !important}.flex-xl-nowrap{flex-wrap:nowrap !important}.flex-xl-wrap-reverse{flex-wrap:wrap-reverse !important}.justify-content-xl-start{justify-content:flex-start !important}.justify-content-xl-end{justify-content:flex-end !important}.justify-content-xl-center{justify-content:center !important}.justify-content-xl-between{justify-content:space-between !important}.justify-content-xl-around{justify-content:space-around !important}.justify-content-xl-evenly{justify-content:space-evenly !important}.align-items-xl-start{align-items:flex-start !important}.align-items-xl-end{align-items:flex-end !important}.align-items-xl-center{align-items:center !important}.align-items-xl-baseline{align-items:baseline !important}.align-items-xl-stretch{align-items:stretch !important}.align-content-xl-start{align-content:flex-start !important}.align-content-xl-end{align-content:flex-end !important}.align-content-xl-center{align-content:center !important}.align-content-xl-between{align-content:space-between !important}.align-content-xl-around{align-content:space-around !important}.align-content-xl-stretch{align-content:stretch !important}.align-self-xl-auto{align-self:auto !important}.align-self-xl-start{align-self:flex-start !important}.align-self-xl-end{align-self:flex-end !important}.align-self-xl-center{align-self:center !important}.align-self-xl-baseline{align-self:baseline !important}.align-self-xl-stretch{align-self:stretch !important}.order-xl-first{order:-1 !important}.order-xl-0{order:0 !important}.order-xl-1{order:1 !important}.order-xl-2{order:2 !important}.order-xl-3{order:3 !important}.order-xl-4{order:4 !important}.order-xl-5{order:5 !important}.order-xl-last{order:6 !important}.m-xl-0{margin:0 !important}.m-xl-1{margin:.25rem !important}.m-xl-2{margin:.5rem !important}.m-xl-3{margin:1rem !important}.m-xl-4{margin:1.5rem !important}.m-xl-5{margin:3rem !important}.m-xl-auto{margin:auto !important}.mx-xl-0{margin-right:0 !important;margin-left:0 !important}.mx-xl-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-xl-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-xl-3{margin-right:1rem !important;margin-left:1rem !important}.mx-xl-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-xl-5{margin-right:3rem !important;margin-left:3rem !important}.mx-xl-auto{margin-right:auto !important;margin-left:auto !important}.my-xl-0{margin-top:0 !important;margin-bottom:0 !important}.my-xl-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-xl-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-xl-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-xl-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-xl-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-xl-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-xl-0{margin-top:0 !important}.mt-xl-1{margin-top:.25rem !important}.mt-xl-2{margin-top:.5rem !important}.mt-xl-3{margin-top:1rem !important}.mt-xl-4{margin-top:1.5rem !important}.mt-xl-5{margin-top:3rem !important}.mt-xl-auto{margin-top:auto !important}.me-xl-0{margin-right:0 !important}.me-xl-1{margin-right:.25rem !important}.me-xl-2{margin-right:.5rem !important}.me-xl-3{margin-right:1rem !important}.me-xl-4{margin-right:1.5rem !important}.me-xl-5{margin-right:3rem !important}.me-xl-auto{margin-right:auto !important}.mb-xl-0{margin-bottom:0 !important}.mb-xl-1{margin-bottom:.25rem !important}.mb-xl-2{margin-bottom:.5rem !important}.mb-xl-3{margin-bottom:1rem !important}.mb-xl-4{margin-bottom:1.5rem !important}.mb-xl-5{margin-bottom:3rem !important}.mb-xl-auto{margin-bottom:auto !important}.ms-xl-0{margin-left:0 !important}.ms-xl-1{margin-left:.25rem !important}.ms-xl-2{margin-left:.5rem !important}.ms-xl-3{margin-left:1rem !important}.ms-xl-4{margin-left:1.5rem !important}.ms-xl-5{margin-left:3rem !important}.ms-xl-auto{margin-left:auto !important}.p-xl-0{padding:0 !important}.p-xl-1{padding:.25rem !important}.p-xl-2{padding:.5rem !important}.p-xl-3{padding:1rem !important}.p-xl-4{padding:1.5rem !important}.p-xl-5{padding:3rem !important}.px-xl-0{padding-right:0 !important;padding-left:0 !important}.px-xl-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-xl-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-xl-3{padding-right:1rem !important;padding-left:1rem !important}.px-xl-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-xl-5{padding-right:3rem !important;padding-left:3rem !important}.py-xl-0{padding-top:0 !important;padding-bottom:0 !important}.py-xl-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-xl-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-xl-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-xl-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-xl-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-xl-0{padding-top:0 !important}.pt-xl-1{padding-top:.25rem !important}.pt-xl-2{padding-top:.5rem !important}.pt-xl-3{padding-top:1rem !important}.pt-xl-4{padding-top:1.5rem !important}.pt-xl-5{padding-top:3rem !important}.pe-xl-0{padding-right:0 !important}.pe-xl-1{padding-right:.25rem !important}.pe-xl-2{padding-right:.5rem !important}.pe-xl-3{padding-right:1rem !important}.pe-xl-4{padding-right:1.5rem !important}.pe-xl-5{padding-right:3rem !important}.pb-xl-0{padding-bottom:0 !important}.pb-xl-1{padding-bottom:.25rem !important}.pb-xl-2{padding-bottom:.5rem !important}.pb-xl-3{padding-bottom:1rem !important}.pb-xl-4{padding-bottom:1.5rem !important}.pb-xl-5{padding-bottom:3rem !important}.ps-xl-0{padding-left:0 !important}.ps-xl-1{padding-left:.25rem !important}.ps-xl-2{padding-left:.5rem !important}.ps-xl-3{padding-left:1rem !important}.ps-xl-4{padding-left:1.5rem !important}.ps-xl-5{padding-left:3rem !important}.gap-xl-0{gap:0 !important}.gap-xl-1{gap:.25rem !important}.gap-xl-2{gap:.5rem !important}.gap-xl-3{gap:1rem !important}.gap-xl-4{gap:1.5rem !important}.gap-xl-5{gap:3rem !important}.row-gap-xl-0{row-gap:0 !important}.row-gap-xl-1{row-gap:.25rem !important}.row-gap-xl-2{row-gap:.5rem !important}.row-gap-xl-3{row-gap:1rem !important}.row-gap-xl-4{row-gap:1.5rem !important}.row-gap-xl-5{row-gap:3rem !important}.column-gap-xl-0{column-gap:0 !important}.column-gap-xl-1{column-gap:.25rem !important}.column-gap-xl-2{column-gap:.5rem !important}.column-gap-xl-3{column-gap:1rem !important}.column-gap-xl-4{column-gap:1.5rem !important}.column-gap-xl-5{column-gap:3rem !important}.text-xl-start{text-align:left !important}.text-xl-end{text-align:right !important}.text-xl-center{text-align:center !important}}@media(min-width: 1400px){.float-xxl-start{float:left !important}.float-xxl-end{float:right !important}.float-xxl-none{float:none !important}.object-fit-xxl-contain{object-fit:contain !important}.object-fit-xxl-cover{object-fit:cover !important}.object-fit-xxl-fill{object-fit:fill !important}.object-fit-xxl-scale{object-fit:scale-down !important}.object-fit-xxl-none{object-fit:none !important}.d-xxl-inline{display:inline !important}.d-xxl-inline-block{display:inline-block !important}.d-xxl-block{display:block !important}.d-xxl-grid{display:grid !important}.d-xxl-inline-grid{display:inline-grid !important}.d-xxl-table{display:table !important}.d-xxl-table-row{display:table-row !important}.d-xxl-table-cell{display:table-cell !important}.d-xxl-flex{display:flex !important}.d-xxl-inline-flex{display:inline-flex !important}.d-xxl-none{display:none !important}.flex-xxl-fill{flex:1 1 auto !important}.flex-xxl-row{flex-direction:row !important}.flex-xxl-column{flex-direction:column !important}.flex-xxl-row-reverse{flex-direction:row-reverse !important}.flex-xxl-column-reverse{flex-direction:column-reverse !important}.flex-xxl-grow-0{flex-grow:0 !important}.flex-xxl-grow-1{flex-grow:1 !important}.flex-xxl-shrink-0{flex-shrink:0 !important}.flex-xxl-shrink-1{flex-shrink:1 !important}.flex-xxl-wrap{flex-wrap:wrap !important}.flex-xxl-nowrap{flex-wrap:nowrap !important}.flex-xxl-wrap-reverse{flex-wrap:wrap-reverse !important}.justify-content-xxl-start{justify-content:flex-start !important}.justify-content-xxl-end{justify-content:flex-end !important}.justify-content-xxl-center{justify-content:center !important}.justify-content-xxl-between{justify-content:space-between !important}.justify-content-xxl-around{justify-content:space-around !important}.justify-content-xxl-evenly{justify-content:space-evenly !important}.align-items-xxl-start{align-items:flex-start !important}.align-items-xxl-end{align-items:flex-end !important}.align-items-xxl-center{align-items:center !important}.align-items-xxl-baseline{align-items:baseline !important}.align-items-xxl-stretch{align-items:stretch !important}.align-content-xxl-start{align-content:flex-start !important}.align-content-xxl-end{align-content:flex-end !important}.align-content-xxl-center{align-content:center !important}.align-content-xxl-between{align-content:space-between !important}.align-content-xxl-around{align-content:space-around !important}.align-content-xxl-stretch{align-content:stretch !important}.align-self-xxl-auto{align-self:auto !important}.align-self-xxl-start{align-self:flex-start !important}.align-self-xxl-end{align-self:flex-end !important}.align-self-xxl-center{align-self:center !important}.align-self-xxl-baseline{align-self:baseline !important}.align-self-xxl-stretch{align-self:stretch !important}.order-xxl-first{order:-1 !important}.order-xxl-0{order:0 !important}.order-xxl-1{order:1 !important}.order-xxl-2{order:2 !important}.order-xxl-3{order:3 !important}.order-xxl-4{order:4 !important}.order-xxl-5{order:5 !important}.order-xxl-last{order:6 !important}.m-xxl-0{margin:0 !important}.m-xxl-1{margin:.25rem !important}.m-xxl-2{margin:.5rem !important}.m-xxl-3{margin:1rem !important}.m-xxl-4{margin:1.5rem !important}.m-xxl-5{margin:3rem !important}.m-xxl-auto{margin:auto !important}.mx-xxl-0{margin-right:0 !important;margin-left:0 !important}.mx-xxl-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-xxl-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-xxl-3{margin-right:1rem !important;margin-left:1rem !important}.mx-xxl-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-xxl-5{margin-right:3rem !important;margin-left:3rem !important}.mx-xxl-auto{margin-right:auto !important;margin-left:auto !important}.my-xxl-0{margin-top:0 !important;margin-bottom:0 !important}.my-xxl-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-xxl-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-xxl-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-xxl-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-xxl-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-xxl-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-xxl-0{margin-top:0 !important}.mt-xxl-1{margin-top:.25rem !important}.mt-xxl-2{margin-top:.5rem !important}.mt-xxl-3{margin-top:1rem !important}.mt-xxl-4{margin-top:1.5rem !important}.mt-xxl-5{margin-top:3rem !important}.mt-xxl-auto{margin-top:auto !important}.me-xxl-0{margin-right:0 !important}.me-xxl-1{margin-right:.25rem !important}.me-xxl-2{margin-right:.5rem !important}.me-xxl-3{margin-right:1rem !important}.me-xxl-4{margin-right:1.5rem !important}.me-xxl-5{margin-right:3rem !important}.me-xxl-auto{margin-right:auto !important}.mb-xxl-0{margin-bottom:0 !important}.mb-xxl-1{margin-bottom:.25rem !important}.mb-xxl-2{margin-bottom:.5rem !important}.mb-xxl-3{margin-bottom:1rem !important}.mb-xxl-4{margin-bottom:1.5rem !important}.mb-xxl-5{margin-bottom:3rem !important}.mb-xxl-auto{margin-bottom:auto !important}.ms-xxl-0{margin-left:0 !important}.ms-xxl-1{margin-left:.25rem !important}.ms-xxl-2{margin-left:.5rem !important}.ms-xxl-3{margin-left:1rem !important}.ms-xxl-4{margin-left:1.5rem !important}.ms-xxl-5{margin-left:3rem !important}.ms-xxl-auto{margin-left:auto !important}.p-xxl-0{padding:0 !important}.p-xxl-1{padding:.25rem !important}.p-xxl-2{padding:.5rem !important}.p-xxl-3{padding:1rem !important}.p-xxl-4{padding:1.5rem !important}.p-xxl-5{padding:3rem !important}.px-xxl-0{padding-right:0 !important;padding-left:0 !important}.px-xxl-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-xxl-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-xxl-3{padding-right:1rem !important;padding-left:1rem !important}.px-xxl-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-xxl-5{padding-right:3rem !important;padding-left:3rem !important}.py-xxl-0{padding-top:0 !important;padding-bottom:0 !important}.py-xxl-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-xxl-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-xxl-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-xxl-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-xxl-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-xxl-0{padding-top:0 !important}.pt-xxl-1{padding-top:.25rem !important}.pt-xxl-2{padding-top:.5rem !important}.pt-xxl-3{padding-top:1rem !important}.pt-xxl-4{padding-top:1.5rem !important}.pt-xxl-5{padding-top:3rem !important}.pe-xxl-0{padding-right:0 !important}.pe-xxl-1{padding-right:.25rem !important}.pe-xxl-2{padding-right:.5rem !important}.pe-xxl-3{padding-right:1rem !important}.pe-xxl-4{padding-right:1.5rem !important}.pe-xxl-5{padding-right:3rem !important}.pb-xxl-0{padding-bottom:0 !important}.pb-xxl-1{padding-bottom:.25rem !important}.pb-xxl-2{padding-bottom:.5rem !important}.pb-xxl-3{padding-bottom:1rem !important}.pb-xxl-4{padding-bottom:1.5rem !important}.pb-xxl-5{padding-bottom:3rem !important}.ps-xxl-0{padding-left:0 !important}.ps-xxl-1{padding-left:.25rem !important}.ps-xxl-2{padding-left:.5rem !important}.ps-xxl-3{padding-left:1rem !important}.ps-xxl-4{padding-left:1.5rem !important}.ps-xxl-5{padding-left:3rem !important}.gap-xxl-0{gap:0 !important}.gap-xxl-1{gap:.25rem !important}.gap-xxl-2{gap:.5rem !important}.gap-xxl-3{gap:1rem !important}.gap-xxl-4{gap:1.5rem !important}.gap-xxl-5{gap:3rem !important}.row-gap-xxl-0{row-gap:0 !important}.row-gap-xxl-1{row-gap:.25rem !important}.row-gap-xxl-2{row-gap:.5rem !important}.row-gap-xxl-3{row-gap:1rem !important}.row-gap-xxl-4{row-gap:1.5rem !important}.row-gap-xxl-5{row-gap:3rem !important}.column-gap-xxl-0{column-gap:0 !important}.column-gap-xxl-1{column-gap:.25rem !important}.column-gap-xxl-2{column-gap:.5rem !important}.column-gap-xxl-3{column-gap:1rem !important}.column-gap-xxl-4{column-gap:1.5rem !important}.column-gap-xxl-5{column-gap:3rem !important}.text-xxl-start{text-align:left !important}.text-xxl-end{text-align:right !important}.text-xxl-center{text-align:center !important}}.bg-default{color:#000}.bg-primary{color:#fff}.bg-secondary{color:#fff}.bg-success{color:#fff}.bg-info{color:#000}.bg-warning{color:#000}.bg-danger{color:#fff}.bg-light{color:#000}.bg-dark{color:#fff}@media(min-width: 1200px){.fs-1{font-size:2rem !important}.fs-2{font-size:1.65rem !important}.fs-3{font-size:1.45rem !important}}@media print{.d-print-inline{display:inline !important}.d-print-inline-block{display:inline-block !important}.d-print-block{display:block !important}.d-print-grid{display:grid !important}.d-print-inline-grid{display:inline-grid !important}.d-print-table{display:table !important}.d-print-table-row{display:table-row !important}.d-print-table-cell{display:table-cell !important}.d-print-flex{display:flex !important}.d-print-inline-flex{display:inline-flex !important}.d-print-none{display:none !important}}.tab-content>.tab-pane.html-fill-container{display:none}.tab-content>.active.html-fill-container{display:flex}.tab-content.html-fill-container{padding:0}:root{--bslib-spacer: 1rem;--bslib-mb-spacer: var(--bslib-spacer, 1rem)}.bslib-mb-spacing{margin-bottom:var(--bslib-mb-spacer)}.bslib-gap-spacing{gap:var(--bslib-mb-spacer)}.bslib-gap-spacing>.bslib-mb-spacing,.bslib-gap-spacing>.form-group,.bslib-gap-spacing>p,.bslib-gap-spacing>pre{margin-bottom:0}.html-fill-container>.html-fill-item.bslib-mb-spacing{margin-bottom:0}.tab-content>.tab-pane.html-fill-container{display:none}.tab-content>.active.html-fill-container{display:flex}.tab-content.html-fill-container{padding:0}.bg-blue{--bslib-color-bg: #0d6efd;--bslib-color-fg: #ffffff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-blue{--bslib-color-fg: #0d6efd;color:var(--bslib-color-fg)}.bg-indigo{--bslib-color-bg: #6610f2;--bslib-color-fg: #ffffff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-indigo{--bslib-color-fg: #6610f2;color:var(--bslib-color-fg)}.bg-purple{--bslib-color-bg: #6f42c1;--bslib-color-fg: #ffffff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-purple{--bslib-color-fg: #6f42c1;color:var(--bslib-color-fg)}.bg-pink{--bslib-color-bg: #d63384;--bslib-color-fg: #ffffff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-pink{--bslib-color-fg: #d63384;color:var(--bslib-color-fg)}.bg-red{--bslib-color-bg: #dc3545;--bslib-color-fg: #ffffff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-red{--bslib-color-fg: #dc3545;color:var(--bslib-color-fg)}.bg-orange{--bslib-color-bg: #fd7e14;--bslib-color-fg: #000;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-orange{--bslib-color-fg: #fd7e14;color:var(--bslib-color-fg)}.bg-yellow{--bslib-color-bg: #ffc107;--bslib-color-fg: #000;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-yellow{--bslib-color-fg: #ffc107;color:var(--bslib-color-fg)}.bg-green{--bslib-color-bg: #198754;--bslib-color-fg: #ffffff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-green{--bslib-color-fg: #198754;color:var(--bslib-color-fg)}.bg-teal{--bslib-color-bg: #20c997;--bslib-color-fg: #000;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-teal{--bslib-color-fg: #20c997;color:var(--bslib-color-fg)}.bg-cyan{--bslib-color-bg: #0dcaf0;--bslib-color-fg: #000;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-cyan{--bslib-color-fg: #0dcaf0;color:var(--bslib-color-fg)}.text-default{--bslib-color-fg: #dee2e6}.bg-default{--bslib-color-bg: #dee2e6;--bslib-color-fg: #000}.text-primary{--bslib-color-fg: #0d6efd}.bg-primary{--bslib-color-bg: #0d6efd;--bslib-color-fg: #ffffff}.text-secondary{--bslib-color-fg: #6c757d}.bg-secondary{--bslib-color-bg: #6c757d;--bslib-color-fg: #ffffff}.text-success{--bslib-color-fg: #198754}.bg-success{--bslib-color-bg: #198754;--bslib-color-fg: #ffffff}.text-info{--bslib-color-fg: #0dcaf0}.bg-info{--bslib-color-bg: #0dcaf0;--bslib-color-fg: #000}.text-warning{--bslib-color-fg: #ffc107}.bg-warning{--bslib-color-bg: #ffc107;--bslib-color-fg: #000}.text-danger{--bslib-color-fg: #dc3545}.bg-danger{--bslib-color-bg: #dc3545;--bslib-color-fg: #ffffff}.text-light{--bslib-color-fg: #f8f9fa}.bg-light{--bslib-color-bg: #f8f9fa;--bslib-color-fg: #000}.text-dark{--bslib-color-fg: #212529}.bg-dark{--bslib-color-bg: #212529;--bslib-color-fg: #ffffff}.bg-gradient-blue-indigo{--bslib-color-fg: #ffffff;--bslib-color-bg: #3148f9;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #3148f9;color:#fff}.bg-gradient-blue-purple{--bslib-color-fg: #ffffff;--bslib-color-bg: #345ce5;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #345ce5;color:#fff}.bg-gradient-blue-pink{--bslib-color-fg: #ffffff;--bslib-color-bg: #5d56cd;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #5d56cd;color:#fff}.bg-gradient-blue-red{--bslib-color-fg: #ffffff;--bslib-color-bg: #6057b3;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #6057b3;color:#fff}.bg-gradient-blue-orange{--bslib-color-fg: #ffffff;--bslib-color-bg: #6d74a0;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #6d74a0;color:#fff}.bg-gradient-blue-yellow{--bslib-color-fg: #000;--bslib-color-bg: #6e8f9b;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #6e8f9b;color:#000}.bg-gradient-blue-green{--bslib-color-fg: #ffffff;--bslib-color-bg: #1278b9;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #1278b9;color:#fff}.bg-gradient-blue-teal{--bslib-color-fg: #000;--bslib-color-bg: #1592d4;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #1592d4;color:#000}.bg-gradient-blue-cyan{--bslib-color-fg: #000;--bslib-color-bg: #0d93f8;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #0d93f8;color:#000}.bg-gradient-indigo-blue{--bslib-color-fg: #ffffff;--bslib-color-bg: #4236f6;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #4236f6;color:#fff}.bg-gradient-indigo-purple{--bslib-color-fg: #ffffff;--bslib-color-bg: #6a24de;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #6a24de;color:#fff}.bg-gradient-indigo-pink{--bslib-color-fg: #ffffff;--bslib-color-bg: #931ec6;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #931ec6;color:#fff}.bg-gradient-indigo-red{--bslib-color-fg: #ffffff;--bslib-color-bg: #951fad;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #951fad;color:#fff}.bg-gradient-indigo-orange{--bslib-color-fg: #ffffff;--bslib-color-bg: #a23c99;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #a23c99;color:#fff}.bg-gradient-indigo-yellow{--bslib-color-fg: #ffffff;--bslib-color-bg: #a35794;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #a35794;color:#fff}.bg-gradient-indigo-green{--bslib-color-fg: #ffffff;--bslib-color-bg: #4740b3;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #4740b3;color:#fff}.bg-gradient-indigo-teal{--bslib-color-fg: #ffffff;--bslib-color-bg: #4a5ace;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #4a5ace;color:#fff}.bg-gradient-indigo-cyan{--bslib-color-fg: #ffffff;--bslib-color-bg: #425af1;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #425af1;color:#fff}.bg-gradient-purple-blue{--bslib-color-fg: #ffffff;--bslib-color-bg: #4854d9;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #4854d9;color:#fff}.bg-gradient-purple-indigo{--bslib-color-fg: #ffffff;--bslib-color-bg: #6b2ed5;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #6b2ed5;color:#fff}.bg-gradient-purple-pink{--bslib-color-fg: #ffffff;--bslib-color-bg: #983ca9;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #983ca9;color:#fff}.bg-gradient-purple-red{--bslib-color-fg: #ffffff;--bslib-color-bg: #9b3d8f;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #9b3d8f;color:#fff}.bg-gradient-purple-orange{--bslib-color-fg: #ffffff;--bslib-color-bg: #a85a7c;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #a85a7c;color:#fff}.bg-gradient-purple-yellow{--bslib-color-fg: #000;--bslib-color-bg: #a97577;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #a97577;color:#000}.bg-gradient-purple-green{--bslib-color-fg: #ffffff;--bslib-color-bg: #4d5e95;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #4d5e95;color:#fff}.bg-gradient-purple-teal{--bslib-color-fg: #ffffff;--bslib-color-bg: #4f78b0;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #4f78b0;color:#fff}.bg-gradient-purple-cyan{--bslib-color-fg: #000;--bslib-color-bg: #4878d4;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #4878d4;color:#000}.bg-gradient-pink-blue{--bslib-color-fg: #ffffff;--bslib-color-bg: #864bb4;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #864bb4;color:#fff}.bg-gradient-pink-indigo{--bslib-color-fg: #ffffff;--bslib-color-bg: #a925b0;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #a925b0;color:#fff}.bg-gradient-pink-purple{--bslib-color-fg: #ffffff;--bslib-color-bg: #ad399c;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #ad399c;color:#fff}.bg-gradient-pink-red{--bslib-color-fg: #ffffff;--bslib-color-bg: #d8346b;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #d8346b;color:#fff}.bg-gradient-pink-orange{--bslib-color-fg: #000;--bslib-color-bg: #e65157;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #e65157;color:#000}.bg-gradient-pink-yellow{--bslib-color-fg: #000;--bslib-color-bg: #e66c52;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #e66c52;color:#000}.bg-gradient-pink-green{--bslib-color-fg: #ffffff;--bslib-color-bg: #8a5571;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #8a5571;color:#fff}.bg-gradient-pink-teal{--bslib-color-fg: #000;--bslib-color-bg: #8d6f8c;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #8d6f8c;color:#000}.bg-gradient-pink-cyan{--bslib-color-fg: #000;--bslib-color-bg: #866faf;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #866faf;color:#000}.bg-gradient-red-blue{--bslib-color-fg: #ffffff;--bslib-color-bg: #894c8f;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #894c8f;color:#fff}.bg-gradient-red-indigo{--bslib-color-fg: #ffffff;--bslib-color-bg: #ad268a;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #ad268a;color:#fff}.bg-gradient-red-purple{--bslib-color-fg: #ffffff;--bslib-color-bg: #b03a77;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #b03a77;color:#fff}.bg-gradient-red-pink{--bslib-color-fg: #ffffff;--bslib-color-bg: #da345e;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #da345e;color:#fff}.bg-gradient-red-orange{--bslib-color-fg: #000;--bslib-color-bg: #e95231;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #e95231;color:#000}.bg-gradient-red-yellow{--bslib-color-fg: #000;--bslib-color-bg: #ea6d2c;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #ea6d2c;color:#000}.bg-gradient-red-green{--bslib-color-fg: #ffffff;--bslib-color-bg: #8e564b;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #8e564b;color:#fff}.bg-gradient-red-teal{--bslib-color-fg: #000;--bslib-color-bg: #917066;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #917066;color:#000}.bg-gradient-red-cyan{--bslib-color-fg: #000;--bslib-color-bg: #897189;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #897189;color:#000}.bg-gradient-orange-blue{--bslib-color-fg: #000;--bslib-color-bg: #9d7871;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #9d7871;color:#000}.bg-gradient-orange-indigo{--bslib-color-fg: #000;--bslib-color-bg: #c1526d;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #c1526d;color:#000}.bg-gradient-orange-purple{--bslib-color-fg: #000;--bslib-color-bg: #c46659;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #c46659;color:#000}.bg-gradient-orange-pink{--bslib-color-fg: #000;--bslib-color-bg: #ed6041;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #ed6041;color:#000}.bg-gradient-orange-red{--bslib-color-fg: #000;--bslib-color-bg: #f06128;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #f06128;color:#000}.bg-gradient-orange-yellow{--bslib-color-fg: #000;--bslib-color-bg: #fe990f;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #fe990f;color:#000}.bg-gradient-orange-green{--bslib-color-fg: #000;--bslib-color-bg: #a2822e;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #a2822e;color:#000}.bg-gradient-orange-teal{--bslib-color-fg: #000;--bslib-color-bg: #a59c48;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #a59c48;color:#000}.bg-gradient-orange-cyan{--bslib-color-fg: #000;--bslib-color-bg: #9d9c6c;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #9d9c6c;color:#000}.bg-gradient-yellow-blue{--bslib-color-fg: #000;--bslib-color-bg: #9ea069;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #9ea069;color:#000}.bg-gradient-yellow-indigo{--bslib-color-fg: #000;--bslib-color-bg: #c27a65;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #c27a65;color:#000}.bg-gradient-yellow-purple{--bslib-color-fg: #000;--bslib-color-bg: #c58e51;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #c58e51;color:#000}.bg-gradient-yellow-pink{--bslib-color-fg: #000;--bslib-color-bg: #ef8839;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #ef8839;color:#000}.bg-gradient-yellow-red{--bslib-color-fg: #000;--bslib-color-bg: #f18920;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #f18920;color:#000}.bg-gradient-yellow-orange{--bslib-color-fg: #000;--bslib-color-bg: #fea60c;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #fea60c;color:#000}.bg-gradient-yellow-green{--bslib-color-fg: #000;--bslib-color-bg: #a3aa26;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #a3aa26;color:#000}.bg-gradient-yellow-teal{--bslib-color-fg: #000;--bslib-color-bg: #a6c441;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #a6c441;color:#000}.bg-gradient-yellow-cyan{--bslib-color-fg: #000;--bslib-color-bg: #9ec564;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #9ec564;color:#000}.bg-gradient-green-blue{--bslib-color-fg: #ffffff;--bslib-color-bg: #147d98;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #147d98;color:#fff}.bg-gradient-green-indigo{--bslib-color-fg: #ffffff;--bslib-color-bg: #385793;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #385793;color:#fff}.bg-gradient-green-purple{--bslib-color-fg: #ffffff;--bslib-color-bg: #3b6b80;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #3b6b80;color:#fff}.bg-gradient-green-pink{--bslib-color-fg: #ffffff;--bslib-color-bg: #656567;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #656567;color:#fff}.bg-gradient-green-red{--bslib-color-fg: #ffffff;--bslib-color-bg: #67664e;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #67664e;color:#fff}.bg-gradient-green-orange{--bslib-color-fg: #000;--bslib-color-bg: #74833a;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #74833a;color:#000}.bg-gradient-green-yellow{--bslib-color-fg: #000;--bslib-color-bg: #759e35;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #759e35;color:#000}.bg-gradient-green-teal{--bslib-color-fg: #000;--bslib-color-bg: #1ca16f;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #1ca16f;color:#000}.bg-gradient-green-cyan{--bslib-color-fg: #000;--bslib-color-bg: #14a292;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #14a292;color:#000}.bg-gradient-teal-blue{--bslib-color-fg: #000;--bslib-color-bg: #18a5c0;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #18a5c0;color:#000}.bg-gradient-teal-indigo{--bslib-color-fg: #000;--bslib-color-bg: #3c7fbb;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #3c7fbb;color:#000}.bg-gradient-teal-purple{--bslib-color-fg: #000;--bslib-color-bg: #4093a8;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #4093a8;color:#000}.bg-gradient-teal-pink{--bslib-color-fg: #000;--bslib-color-bg: #698d8f;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #698d8f;color:#000}.bg-gradient-teal-red{--bslib-color-fg: #000;--bslib-color-bg: #6b8e76;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #6b8e76;color:#000}.bg-gradient-teal-orange{--bslib-color-fg: #000;--bslib-color-bg: #78ab63;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #78ab63;color:#000}.bg-gradient-teal-yellow{--bslib-color-fg: #000;--bslib-color-bg: #79c65d;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #79c65d;color:#000}.bg-gradient-teal-green{--bslib-color-fg: #000;--bslib-color-bg: #1daf7c;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #1daf7c;color:#000}.bg-gradient-teal-cyan{--bslib-color-fg: #000;--bslib-color-bg: #18c9bb;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #18c9bb;color:#000}.bg-gradient-cyan-blue{--bslib-color-fg: #000;--bslib-color-bg: #0da5f5;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #0da5f5;color:#000}.bg-gradient-cyan-indigo{--bslib-color-fg: #000;--bslib-color-bg: #3180f1;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #3180f1;color:#000}.bg-gradient-cyan-purple{--bslib-color-fg: #000;--bslib-color-bg: #3494dd;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #3494dd;color:#000}.bg-gradient-cyan-pink{--bslib-color-fg: #000;--bslib-color-bg: #5d8ec5;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #5d8ec5;color:#000}.bg-gradient-cyan-red{--bslib-color-fg: #000;--bslib-color-bg: #608eac;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #608eac;color:#000}.bg-gradient-cyan-orange{--bslib-color-fg: #000;--bslib-color-bg: #6dac98;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #6dac98;color:#000}.bg-gradient-cyan-yellow{--bslib-color-fg: #000;--bslib-color-bg: #6ec693;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #6ec693;color:#000}.bg-gradient-cyan-green{--bslib-color-fg: #000;--bslib-color-bg: #12afb2;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #12afb2;color:#000}.bg-gradient-cyan-teal{--bslib-color-fg: #000;--bslib-color-bg: #15cacc;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #15cacc;color:#000}.bg-blue{--bslib-color-bg: #0d6efd;--bslib-color-fg: #ffffff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-blue{--bslib-color-fg: #0d6efd;color:var(--bslib-color-fg)}.bg-indigo{--bslib-color-bg: #6610f2;--bslib-color-fg: #ffffff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-indigo{--bslib-color-fg: #6610f2;color:var(--bslib-color-fg)}.bg-purple{--bslib-color-bg: #6f42c1;--bslib-color-fg: #ffffff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-purple{--bslib-color-fg: #6f42c1;color:var(--bslib-color-fg)}.bg-pink{--bslib-color-bg: #d63384;--bslib-color-fg: #ffffff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-pink{--bslib-color-fg: #d63384;color:var(--bslib-color-fg)}.bg-red{--bslib-color-bg: #dc3545;--bslib-color-fg: #ffffff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-red{--bslib-color-fg: #dc3545;color:var(--bslib-color-fg)}.bg-orange{--bslib-color-bg: #fd7e14;--bslib-color-fg: #000;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-orange{--bslib-color-fg: #fd7e14;color:var(--bslib-color-fg)}.bg-yellow{--bslib-color-bg: #ffc107;--bslib-color-fg: #000;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-yellow{--bslib-color-fg: #ffc107;color:var(--bslib-color-fg)}.bg-green{--bslib-color-bg: #198754;--bslib-color-fg: #ffffff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-green{--bslib-color-fg: #198754;color:var(--bslib-color-fg)}.bg-teal{--bslib-color-bg: #20c997;--bslib-color-fg: #000;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-teal{--bslib-color-fg: #20c997;color:var(--bslib-color-fg)}.bg-cyan{--bslib-color-bg: #0dcaf0;--bslib-color-fg: #000;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-cyan{--bslib-color-fg: #0dcaf0;color:var(--bslib-color-fg)}.text-default{--bslib-color-fg: #dee2e6}.bg-default{--bslib-color-bg: #dee2e6;--bslib-color-fg: #000}.text-primary{--bslib-color-fg: #0d6efd}.bg-primary{--bslib-color-bg: #0d6efd;--bslib-color-fg: #ffffff}.text-secondary{--bslib-color-fg: #6c757d}.bg-secondary{--bslib-color-bg: #6c757d;--bslib-color-fg: #ffffff}.text-success{--bslib-color-fg: #198754}.bg-success{--bslib-color-bg: #198754;--bslib-color-fg: #ffffff}.text-info{--bslib-color-fg: #0dcaf0}.bg-info{--bslib-color-bg: #0dcaf0;--bslib-color-fg: #000}.text-warning{--bslib-color-fg: #ffc107}.bg-warning{--bslib-color-bg: #ffc107;--bslib-color-fg: #000}.text-danger{--bslib-color-fg: #dc3545}.bg-danger{--bslib-color-bg: #dc3545;--bslib-color-fg: #ffffff}.text-light{--bslib-color-fg: #f8f9fa}.bg-light{--bslib-color-bg: #f8f9fa;--bslib-color-fg: #000}.text-dark{--bslib-color-fg: #212529}.bg-dark{--bslib-color-bg: #212529;--bslib-color-fg: #ffffff}.bg-gradient-blue-indigo{--bslib-color-fg: #ffffff;--bslib-color-bg: #3148f9;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #3148f9;color:#fff}.bg-gradient-blue-purple{--bslib-color-fg: #ffffff;--bslib-color-bg: #345ce5;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #345ce5;color:#fff}.bg-gradient-blue-pink{--bslib-color-fg: #ffffff;--bslib-color-bg: #5d56cd;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #5d56cd;color:#fff}.bg-gradient-blue-red{--bslib-color-fg: #ffffff;--bslib-color-bg: #6057b3;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #6057b3;color:#fff}.bg-gradient-blue-orange{--bslib-color-fg: #ffffff;--bslib-color-bg: #6d74a0;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #6d74a0;color:#fff}.bg-gradient-blue-yellow{--bslib-color-fg: #000;--bslib-color-bg: #6e8f9b;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #6e8f9b;color:#000}.bg-gradient-blue-green{--bslib-color-fg: #ffffff;--bslib-color-bg: #1278b9;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #1278b9;color:#fff}.bg-gradient-blue-teal{--bslib-color-fg: #000;--bslib-color-bg: #1592d4;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #1592d4;color:#000}.bg-gradient-blue-cyan{--bslib-color-fg: #000;--bslib-color-bg: #0d93f8;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #0d93f8;color:#000}.bg-gradient-indigo-blue{--bslib-color-fg: #ffffff;--bslib-color-bg: #4236f6;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #4236f6;color:#fff}.bg-gradient-indigo-purple{--bslib-color-fg: #ffffff;--bslib-color-bg: #6a24de;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #6a24de;color:#fff}.bg-gradient-indigo-pink{--bslib-color-fg: #ffffff;--bslib-color-bg: #931ec6;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #931ec6;color:#fff}.bg-gradient-indigo-red{--bslib-color-fg: #ffffff;--bslib-color-bg: #951fad;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #951fad;color:#fff}.bg-gradient-indigo-orange{--bslib-color-fg: #ffffff;--bslib-color-bg: #a23c99;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #a23c99;color:#fff}.bg-gradient-indigo-yellow{--bslib-color-fg: #ffffff;--bslib-color-bg: #a35794;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #a35794;color:#fff}.bg-gradient-indigo-green{--bslib-color-fg: #ffffff;--bslib-color-bg: #4740b3;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #4740b3;color:#fff}.bg-gradient-indigo-teal{--bslib-color-fg: #ffffff;--bslib-color-bg: #4a5ace;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #4a5ace;color:#fff}.bg-gradient-indigo-cyan{--bslib-color-fg: #ffffff;--bslib-color-bg: #425af1;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #425af1;color:#fff}.bg-gradient-purple-blue{--bslib-color-fg: #ffffff;--bslib-color-bg: #4854d9;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #4854d9;color:#fff}.bg-gradient-purple-indigo{--bslib-color-fg: #ffffff;--bslib-color-bg: #6b2ed5;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #6b2ed5;color:#fff}.bg-gradient-purple-pink{--bslib-color-fg: #ffffff;--bslib-color-bg: #983ca9;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #983ca9;color:#fff}.bg-gradient-purple-red{--bslib-color-fg: #ffffff;--bslib-color-bg: #9b3d8f;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #9b3d8f;color:#fff}.bg-gradient-purple-orange{--bslib-color-fg: #ffffff;--bslib-color-bg: #a85a7c;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #a85a7c;color:#fff}.bg-gradient-purple-yellow{--bslib-color-fg: #000;--bslib-color-bg: #a97577;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #a97577;color:#000}.bg-gradient-purple-green{--bslib-color-fg: #ffffff;--bslib-color-bg: #4d5e95;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #4d5e95;color:#fff}.bg-gradient-purple-teal{--bslib-color-fg: #ffffff;--bslib-color-bg: #4f78b0;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #4f78b0;color:#fff}.bg-gradient-purple-cyan{--bslib-color-fg: #000;--bslib-color-bg: #4878d4;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #4878d4;color:#000}.bg-gradient-pink-blue{--bslib-color-fg: #ffffff;--bslib-color-bg: #864bb4;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #864bb4;color:#fff}.bg-gradient-pink-indigo{--bslib-color-fg: #ffffff;--bslib-color-bg: #a925b0;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #a925b0;color:#fff}.bg-gradient-pink-purple{--bslib-color-fg: #ffffff;--bslib-color-bg: #ad399c;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #ad399c;color:#fff}.bg-gradient-pink-red{--bslib-color-fg: #ffffff;--bslib-color-bg: #d8346b;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #d8346b;color:#fff}.bg-gradient-pink-orange{--bslib-color-fg: #000;--bslib-color-bg: #e65157;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #e65157;color:#000}.bg-gradient-pink-yellow{--bslib-color-fg: #000;--bslib-color-bg: #e66c52;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #e66c52;color:#000}.bg-gradient-pink-green{--bslib-color-fg: #ffffff;--bslib-color-bg: #8a5571;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #8a5571;color:#fff}.bg-gradient-pink-teal{--bslib-color-fg: #000;--bslib-color-bg: #8d6f8c;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #8d6f8c;color:#000}.bg-gradient-pink-cyan{--bslib-color-fg: #000;--bslib-color-bg: #866faf;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #866faf;color:#000}.bg-gradient-red-blue{--bslib-color-fg: #ffffff;--bslib-color-bg: #894c8f;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #894c8f;color:#fff}.bg-gradient-red-indigo{--bslib-color-fg: #ffffff;--bslib-color-bg: #ad268a;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #ad268a;color:#fff}.bg-gradient-red-purple{--bslib-color-fg: #ffffff;--bslib-color-bg: #b03a77;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #b03a77;color:#fff}.bg-gradient-red-pink{--bslib-color-fg: #ffffff;--bslib-color-bg: #da345e;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #da345e;color:#fff}.bg-gradient-red-orange{--bslib-color-fg: #000;--bslib-color-bg: #e95231;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #e95231;color:#000}.bg-gradient-red-yellow{--bslib-color-fg: #000;--bslib-color-bg: #ea6d2c;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #ea6d2c;color:#000}.bg-gradient-red-green{--bslib-color-fg: #ffffff;--bslib-color-bg: #8e564b;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #8e564b;color:#fff}.bg-gradient-red-teal{--bslib-color-fg: #000;--bslib-color-bg: #917066;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #917066;color:#000}.bg-gradient-red-cyan{--bslib-color-fg: #000;--bslib-color-bg: #897189;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #897189;color:#000}.bg-gradient-orange-blue{--bslib-color-fg: #000;--bslib-color-bg: #9d7871;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #9d7871;color:#000}.bg-gradient-orange-indigo{--bslib-color-fg: #000;--bslib-color-bg: #c1526d;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #c1526d;color:#000}.bg-gradient-orange-purple{--bslib-color-fg: #000;--bslib-color-bg: #c46659;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #c46659;color:#000}.bg-gradient-orange-pink{--bslib-color-fg: #000;--bslib-color-bg: #ed6041;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #ed6041;color:#000}.bg-gradient-orange-red{--bslib-color-fg: #000;--bslib-color-bg: #f06128;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #f06128;color:#000}.bg-gradient-orange-yellow{--bslib-color-fg: #000;--bslib-color-bg: #fe990f;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #fe990f;color:#000}.bg-gradient-orange-green{--bslib-color-fg: #000;--bslib-color-bg: #a2822e;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #a2822e;color:#000}.bg-gradient-orange-teal{--bslib-color-fg: #000;--bslib-color-bg: #a59c48;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #a59c48;color:#000}.bg-gradient-orange-cyan{--bslib-color-fg: #000;--bslib-color-bg: #9d9c6c;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #9d9c6c;color:#000}.bg-gradient-yellow-blue{--bslib-color-fg: #000;--bslib-color-bg: #9ea069;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #9ea069;color:#000}.bg-gradient-yellow-indigo{--bslib-color-fg: #000;--bslib-color-bg: #c27a65;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #c27a65;color:#000}.bg-gradient-yellow-purple{--bslib-color-fg: #000;--bslib-color-bg: #c58e51;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #c58e51;color:#000}.bg-gradient-yellow-pink{--bslib-color-fg: #000;--bslib-color-bg: #ef8839;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #ef8839;color:#000}.bg-gradient-yellow-red{--bslib-color-fg: #000;--bslib-color-bg: #f18920;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #f18920;color:#000}.bg-gradient-yellow-orange{--bslib-color-fg: #000;--bslib-color-bg: #fea60c;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #fea60c;color:#000}.bg-gradient-yellow-green{--bslib-color-fg: #000;--bslib-color-bg: #a3aa26;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #a3aa26;color:#000}.bg-gradient-yellow-teal{--bslib-color-fg: #000;--bslib-color-bg: #a6c441;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #a6c441;color:#000}.bg-gradient-yellow-cyan{--bslib-color-fg: #000;--bslib-color-bg: #9ec564;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #9ec564;color:#000}.bg-gradient-green-blue{--bslib-color-fg: #ffffff;--bslib-color-bg: #147d98;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #147d98;color:#fff}.bg-gradient-green-indigo{--bslib-color-fg: #ffffff;--bslib-color-bg: #385793;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #385793;color:#fff}.bg-gradient-green-purple{--bslib-color-fg: #ffffff;--bslib-color-bg: #3b6b80;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #3b6b80;color:#fff}.bg-gradient-green-pink{--bslib-color-fg: #ffffff;--bslib-color-bg: #656567;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #656567;color:#fff}.bg-gradient-green-red{--bslib-color-fg: #ffffff;--bslib-color-bg: #67664e;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #67664e;color:#fff}.bg-gradient-green-orange{--bslib-color-fg: #000;--bslib-color-bg: #74833a;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #74833a;color:#000}.bg-gradient-green-yellow{--bslib-color-fg: #000;--bslib-color-bg: #759e35;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #759e35;color:#000}.bg-gradient-green-teal{--bslib-color-fg: #000;--bslib-color-bg: #1ca16f;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #1ca16f;color:#000}.bg-gradient-green-cyan{--bslib-color-fg: #000;--bslib-color-bg: #14a292;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #14a292;color:#000}.bg-gradient-teal-blue{--bslib-color-fg: #000;--bslib-color-bg: #18a5c0;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #18a5c0;color:#000}.bg-gradient-teal-indigo{--bslib-color-fg: #000;--bslib-color-bg: #3c7fbb;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #3c7fbb;color:#000}.bg-gradient-teal-purple{--bslib-color-fg: #000;--bslib-color-bg: #4093a8;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #4093a8;color:#000}.bg-gradient-teal-pink{--bslib-color-fg: #000;--bslib-color-bg: #698d8f;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #698d8f;color:#000}.bg-gradient-teal-red{--bslib-color-fg: #000;--bslib-color-bg: #6b8e76;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #6b8e76;color:#000}.bg-gradient-teal-orange{--bslib-color-fg: #000;--bslib-color-bg: #78ab63;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #78ab63;color:#000}.bg-gradient-teal-yellow{--bslib-color-fg: #000;--bslib-color-bg: #79c65d;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #79c65d;color:#000}.bg-gradient-teal-green{--bslib-color-fg: #000;--bslib-color-bg: #1daf7c;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #1daf7c;color:#000}.bg-gradient-teal-cyan{--bslib-color-fg: #000;--bslib-color-bg: #18c9bb;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #18c9bb;color:#000}.bg-gradient-cyan-blue{--bslib-color-fg: #000;--bslib-color-bg: #0da5f5;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #0da5f5;color:#000}.bg-gradient-cyan-indigo{--bslib-color-fg: #000;--bslib-color-bg: #3180f1;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #3180f1;color:#000}.bg-gradient-cyan-purple{--bslib-color-fg: #000;--bslib-color-bg: #3494dd;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #3494dd;color:#000}.bg-gradient-cyan-pink{--bslib-color-fg: #000;--bslib-color-bg: #5d8ec5;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #5d8ec5;color:#000}.bg-gradient-cyan-red{--bslib-color-fg: #000;--bslib-color-bg: #608eac;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #608eac;color:#000}.bg-gradient-cyan-orange{--bslib-color-fg: #000;--bslib-color-bg: #6dac98;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #6dac98;color:#000}.bg-gradient-cyan-yellow{--bslib-color-fg: #000;--bslib-color-bg: #6ec693;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #6ec693;color:#000}.bg-gradient-cyan-green{--bslib-color-fg: #000;--bslib-color-bg: #12afb2;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #12afb2;color:#000}.bg-gradient-cyan-teal{--bslib-color-fg: #000;--bslib-color-bg: #15cacc;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #15cacc;color:#000}:root{--bslib-spacer: 1rem;--bslib-mb-spacer: var(--bslib-spacer, 1rem)}.bslib-mb-spacing{margin-bottom:var(--bslib-mb-spacer)}.bslib-gap-spacing{gap:var(--bslib-mb-spacer)}.bslib-gap-spacing>.bslib-mb-spacing,.bslib-gap-spacing>.form-group,.bslib-gap-spacing>p,.bslib-gap-spacing>pre{margin-bottom:0}.html-fill-container>.html-fill-item.bslib-mb-spacing{margin-bottom:0}.bslib-grid{display:grid !important;gap:var(--bslib-spacer, 1rem);height:var(--bslib-grid-height)}.bslib-grid.grid{grid-template-columns:repeat(var(--bs-columns, 12), minmax(0, 1fr));grid-template-rows:unset;grid-auto-rows:var(--bslib-grid--row-heights);--bslib-grid--row-heights--xs: unset;--bslib-grid--row-heights--sm: unset;--bslib-grid--row-heights--md: unset;--bslib-grid--row-heights--lg: unset;--bslib-grid--row-heights--xl: unset;--bslib-grid--row-heights--xxl: unset}.bslib-grid.grid.bslib-grid--row-heights--xs{--bslib-grid--row-heights: var(--bslib-grid--row-heights--xs)}@media(min-width: 576px){.bslib-grid.grid.bslib-grid--row-heights--sm{--bslib-grid--row-heights: var(--bslib-grid--row-heights--sm)}}@media(min-width: 768px){.bslib-grid.grid.bslib-grid--row-heights--md{--bslib-grid--row-heights: var(--bslib-grid--row-heights--md)}}@media(min-width: 992px){.bslib-grid.grid.bslib-grid--row-heights--lg{--bslib-grid--row-heights: var(--bslib-grid--row-heights--lg)}}@media(min-width: 1200px){.bslib-grid.grid.bslib-grid--row-heights--xl{--bslib-grid--row-heights: var(--bslib-grid--row-heights--xl)}}@media(min-width: 1400px){.bslib-grid.grid.bslib-grid--row-heights--xxl{--bslib-grid--row-heights: var(--bslib-grid--row-heights--xxl)}}.bslib-grid>*>.shiny-input-container{width:100%}.bslib-grid-item{grid-column:auto/span 1}@media(max-width: 767.98px){.bslib-grid-item{grid-column:1/-1}}@media(max-width: 575.98px){.bslib-grid{grid-template-columns:1fr !important;height:var(--bslib-grid-height-mobile)}.bslib-grid.grid{height:unset !important;grid-auto-rows:var(--bslib-grid--row-heights--xs, auto)}}@media(min-width: 576px){.nav:not(.nav-hidden){display:flex !important;display:-webkit-flex !important}.nav:not(.nav-hidden):not(.nav-stacked):not(.flex-column){float:none !important}.nav:not(.nav-hidden):not(.nav-stacked):not(.flex-column)>.bslib-nav-spacer{margin-left:auto !important}.nav:not(.nav-hidden):not(.nav-stacked):not(.flex-column)>.form-inline{margin-top:auto;margin-bottom:auto}.nav:not(.nav-hidden).nav-stacked{flex-direction:column;-webkit-flex-direction:column;height:100%}.nav:not(.nav-hidden).nav-stacked>.bslib-nav-spacer{margin-top:auto !important}}.accordion .accordion-header{font-size:calc(1.29rem + 0.48vw);margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2;color:var(--bs-heading-color);margin-bottom:0}@media(min-width: 1200px){.accordion .accordion-header{font-size:1.65rem}}.accordion .accordion-icon:not(:empty){margin-right:.75rem;display:flex}.accordion .accordion-button:not(.collapsed){box-shadow:none}.accordion .accordion-button:not(.collapsed):focus{box-shadow:var(--bs-accordion-btn-focus-box-shadow)}html{height:100%}.bslib-page-fill{width:100%;height:100%;margin:0;padding:var(--bslib-spacer, 1rem);gap:var(--bslib-spacer, 1rem)}@media(max-width: 575.98px){.bslib-page-fill{height:var(--bslib-page-fill-mobile-height, auto)}}.bslib-sidebar-layout{--bslib-sidebar-transition-duration: 500ms;--bslib-sidebar-transition-easing-x: cubic-bezier(0.8, 0.78, 0.22, 1.07);--bslib-sidebar-border: var(--bs-card-border-width, 1px) solid var(--bs-card-border-color, rgba(0, 0, 0, 0.175));--bslib-sidebar-border-radius: var(--bs-border-radius);--bslib-sidebar-vert-border: var(--bs-card-border-width, 1px) solid var(--bs-card-border-color, rgba(0, 0, 0, 0.175));--bslib-sidebar-bg: rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.05);--bslib-sidebar-fg: var(--bs-emphasis-color, black);--bslib-sidebar-main-fg: var(--bs-card-color, var(--bs-body-color));--bslib-sidebar-main-bg: var(--bs-card-bg, var(--bs-body-bg));--bslib-sidebar-toggle-bg: rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.1);--bslib-sidebar-padding: calc(var(--bslib-spacer) * 1.5);--bslib-sidebar-icon-size: var(--bslib-spacer, 1rem);--bslib-sidebar-icon-button-size: calc(var(--bslib-sidebar-icon-size, 1rem) * 2);--bslib-sidebar-padding-icon: calc(var(--bslib-sidebar-icon-button-size, 2rem) * 1.5);--bslib-collapse-toggle-border-radius: var(--bs-border-radius, 0.375rem);--bslib-collapse-toggle-transform: 0deg;--bslib-sidebar-toggle-transition-easing: cubic-bezier(1, 0, 0, 1);--bslib-collapse-toggle-right-transform: 180deg;--bslib-sidebar-column-main: minmax(0, 1fr);display:grid !important;grid-template-columns:min(100% - var(--bslib-sidebar-icon-size),var(--bslib-sidebar-width, 250px)) var(--bslib-sidebar-column-main);position:relative;transition:grid-template-columns ease-in-out var(--bslib-sidebar-transition-duration);border:var(--bslib-sidebar-border);border-radius:var(--bslib-sidebar-border-radius)}@media(prefers-reduced-motion: reduce){.bslib-sidebar-layout{transition:none}}.bslib-sidebar-layout[data-bslib-sidebar-border=false]{border:none}.bslib-sidebar-layout[data-bslib-sidebar-border-radius=false]{border-radius:initial}.bslib-sidebar-layout>.main,.bslib-sidebar-layout>.sidebar{grid-row:1/2;border-radius:inherit;overflow:auto}.bslib-sidebar-layout>.main{grid-column:2/3;border-top-left-radius:0;border-bottom-left-radius:0;padding:var(--bslib-sidebar-padding);transition:padding var(--bslib-sidebar-transition-easing-x) var(--bslib-sidebar-transition-duration);color:var(--bslib-sidebar-main-fg);background-color:var(--bslib-sidebar-main-bg)}.bslib-sidebar-layout>.sidebar{grid-column:1/2;width:100%;height:100%;border-right:var(--bslib-sidebar-vert-border);border-top-right-radius:0;border-bottom-right-radius:0;color:var(--bslib-sidebar-fg);background-color:var(--bslib-sidebar-bg);backdrop-filter:blur(5px)}.bslib-sidebar-layout>.sidebar>.sidebar-content{display:flex;flex-direction:column;gap:var(--bslib-spacer, 1rem);padding:var(--bslib-sidebar-padding);padding-top:var(--bslib-sidebar-padding-icon)}.bslib-sidebar-layout>.sidebar>.sidebar-content>:last-child:not(.sidebar-title){margin-bottom:0}.bslib-sidebar-layout>.sidebar>.sidebar-content>.accordion{margin-left:calc(-1*var(--bslib-sidebar-padding));margin-right:calc(-1*var(--bslib-sidebar-padding))}.bslib-sidebar-layout>.sidebar>.sidebar-content>.accordion:last-child{margin-bottom:calc(-1*var(--bslib-sidebar-padding))}.bslib-sidebar-layout>.sidebar>.sidebar-content>.accordion:not(:last-child){margin-bottom:1rem}.bslib-sidebar-layout>.sidebar>.sidebar-content>.accordion .accordion-body{display:flex;flex-direction:column}.bslib-sidebar-layout>.sidebar>.sidebar-content>.accordion:not(:first-child) .accordion-item:first-child{border-top:var(--bs-accordion-border-width) solid var(--bs-accordion-border-color)}.bslib-sidebar-layout>.sidebar>.sidebar-content>.accordion:not(:last-child) .accordion-item:last-child{border-bottom:var(--bs-accordion-border-width) solid var(--bs-accordion-border-color)}.bslib-sidebar-layout>.sidebar>.sidebar-content.has-accordion>.sidebar-title{border-bottom:none;padding-bottom:0}.bslib-sidebar-layout>.sidebar .shiny-input-container{width:100%}.bslib-sidebar-layout[data-bslib-sidebar-open=always]>.sidebar>.sidebar-content{padding-top:var(--bslib-sidebar-padding)}.bslib-sidebar-layout>.collapse-toggle{grid-row:1/2;grid-column:1/2;display:inline-flex;align-items:center;position:absolute;right:calc(var(--bslib-sidebar-icon-size));top:calc(var(--bslib-sidebar-icon-size, 1rem)/2);border:none;border-radius:var(--bslib-collapse-toggle-border-radius);height:var(--bslib-sidebar-icon-button-size, 2rem);width:var(--bslib-sidebar-icon-button-size, 2rem);display:flex;align-items:center;justify-content:center;padding:0;color:var(--bslib-sidebar-fg);background-color:unset;transition:color var(--bslib-sidebar-transition-easing-x) var(--bslib-sidebar-transition-duration),top var(--bslib-sidebar-transition-easing-x) var(--bslib-sidebar-transition-duration),right var(--bslib-sidebar-transition-easing-x) var(--bslib-sidebar-transition-duration),left var(--bslib-sidebar-transition-easing-x) var(--bslib-sidebar-transition-duration)}.bslib-sidebar-layout>.collapse-toggle:hover{background-color:var(--bslib-sidebar-toggle-bg)}.bslib-sidebar-layout>.collapse-toggle>.collapse-icon{opacity:.8;width:var(--bslib-sidebar-icon-size);height:var(--bslib-sidebar-icon-size);transform:rotateY(var(--bslib-collapse-toggle-transform));transition:transform var(--bslib-sidebar-toggle-transition-easing) var(--bslib-sidebar-transition-duration)}.bslib-sidebar-layout>.collapse-toggle:hover>.collapse-icon{opacity:1}.bslib-sidebar-layout .sidebar-title{font-size:1.25rem;line-height:1.25;margin-top:0;margin-bottom:1rem;padding-bottom:1rem;border-bottom:var(--bslib-sidebar-border)}.bslib-sidebar-layout.sidebar-right{grid-template-columns:var(--bslib-sidebar-column-main) min(100% - var(--bslib-sidebar-icon-size),var(--bslib-sidebar-width, 250px))}.bslib-sidebar-layout.sidebar-right>.main{grid-column:1/2;border-top-right-radius:0;border-bottom-right-radius:0;border-top-left-radius:inherit;border-bottom-left-radius:inherit}.bslib-sidebar-layout.sidebar-right>.sidebar{grid-column:2/3;border-right:none;border-left:var(--bslib-sidebar-vert-border);border-top-left-radius:0;border-bottom-left-radius:0}.bslib-sidebar-layout.sidebar-right>.collapse-toggle{grid-column:2/3;left:var(--bslib-sidebar-icon-size);right:unset;border:var(--bslib-collapse-toggle-border)}.bslib-sidebar-layout.sidebar-right>.collapse-toggle>.collapse-icon{transform:rotateY(var(--bslib-collapse-toggle-right-transform))}.bslib-sidebar-layout.sidebar-collapsed{--bslib-collapse-toggle-transform: 180deg;--bslib-collapse-toggle-right-transform: 0deg;--bslib-sidebar-vert-border: none;grid-template-columns:0 minmax(0, 1fr)}.bslib-sidebar-layout.sidebar-collapsed.sidebar-right{grid-template-columns:minmax(0, 1fr) 0}.bslib-sidebar-layout.sidebar-collapsed:not(.transitioning)>.sidebar>*{display:none}.bslib-sidebar-layout.sidebar-collapsed>.main{border-radius:inherit}.bslib-sidebar-layout.sidebar-collapsed:not(.sidebar-right)>.main{padding-left:var(--bslib-sidebar-padding-icon)}.bslib-sidebar-layout.sidebar-collapsed.sidebar-right>.main{padding-right:var(--bslib-sidebar-padding-icon)}.bslib-sidebar-layout.sidebar-collapsed>.collapse-toggle{color:var(--bslib-sidebar-main-fg);top:calc(var(--bslib-sidebar-overlap-counter, 0)*(var(--bslib-sidebar-icon-size) + var(--bslib-sidebar-padding)) + var(--bslib-sidebar-icon-size, 1rem)/2);right:calc(-2.5*var(--bslib-sidebar-icon-size) - var(--bs-card-border-width, 1px))}.bslib-sidebar-layout.sidebar-collapsed.sidebar-right>.collapse-toggle{left:calc(-2.5*var(--bslib-sidebar-icon-size) - var(--bs-card-border-width, 1px));right:unset}@media(min-width: 576px){.bslib-sidebar-layout.transitioning>.sidebar>.sidebar-content{display:none}}@media(max-width: 575.98px){.bslib-sidebar-layout[data-bslib-sidebar-open=desktop]{--bslib-sidebar-js-init-collapsed: true}.bslib-sidebar-layout>.sidebar,.bslib-sidebar-layout.sidebar-right>.sidebar{border:none}.bslib-sidebar-layout>.main,.bslib-sidebar-layout.sidebar-right>.main{grid-column:1/3}.bslib-sidebar-layout[data-bslib-sidebar-open=always]{display:block !important}.bslib-sidebar-layout[data-bslib-sidebar-open=always]>.sidebar{max-height:var(--bslib-sidebar-max-height-mobile);overflow-y:auto;border-top:var(--bslib-sidebar-vert-border)}.bslib-sidebar-layout:not([data-bslib-sidebar-open=always]){grid-template-columns:100% 0}.bslib-sidebar-layout:not([data-bslib-sidebar-open=always]):not(.sidebar-collapsed)>.sidebar{z-index:1}.bslib-sidebar-layout:not([data-bslib-sidebar-open=always]):not(.sidebar-collapsed)>.collapse-toggle{z-index:1}.bslib-sidebar-layout:not([data-bslib-sidebar-open=always]).sidebar-right{grid-template-columns:0 100%}.bslib-sidebar-layout:not([data-bslib-sidebar-open=always]).sidebar-collapsed{grid-template-columns:0 100%}.bslib-sidebar-layout:not([data-bslib-sidebar-open=always]).sidebar-collapsed.sidebar-right{grid-template-columns:100% 0}.bslib-sidebar-layout:not([data-bslib-sidebar-open=always]):not(.sidebar-right)>.main{padding-left:var(--bslib-sidebar-padding-icon)}.bslib-sidebar-layout:not([data-bslib-sidebar-open=always]).sidebar-right>.main{padding-right:var(--bslib-sidebar-padding-icon)}.bslib-sidebar-layout:not([data-bslib-sidebar-open=always])>.main{opacity:0;transition:opacity var(--bslib-sidebar-transition-easing-x) var(--bslib-sidebar-transition-duration)}.bslib-sidebar-layout:not([data-bslib-sidebar-open=always]).sidebar-collapsed>.main{opacity:1}}:root{--bslib-value-box-shadow: none;--bslib-value-box-border-width-auto-yes: var(--bslib-value-box-border-width-baseline);--bslib-value-box-border-width-auto-no: 0;--bslib-value-box-border-width-baseline: 1px}.bslib-value-box{border-width:var(--bslib-value-box-border-width-auto-no, var(--bslib-value-box-border-width-baseline));container-name:bslib-value-box;container-type:inline-size}.bslib-value-box.card{box-shadow:var(--bslib-value-box-shadow)}.bslib-value-box.border-auto{border-width:var(--bslib-value-box-border-width-auto-yes, var(--bslib-value-box-border-width-baseline))}.bslib-value-box.default{--bslib-value-box-bg-default: var(--bs-card-bg, #ffffff);--bslib-value-box-border-color-default: var(--bs-card-border-color, rgba(0, 0, 0, 0.175));color:var(--bslib-value-box-color);background-color:var(--bslib-value-box-bg, var(--bslib-value-box-bg-default));border-color:var(--bslib-value-box-border-color, var(--bslib-value-box-border-color-default))}.bslib-value-box .value-box-grid{display:grid;grid-template-areas:"left right";align-items:center;overflow:hidden}.bslib-value-box .value-box-showcase{height:100%;max-height:var(---bslib-value-box-showcase-max-h, 100%)}.bslib-value-box .value-box-showcase,.bslib-value-box .value-box-showcase>.html-fill-item{width:100%}.bslib-value-box[data-full-screen=true] .value-box-showcase{max-height:var(---bslib-value-box-showcase-max-h-fs, 100%)}@media screen and (min-width: 575.98px){@container bslib-value-box (max-width: 300px){.bslib-value-box:not(.showcase-bottom) .value-box-grid{grid-template-columns:1fr !important;grid-template-rows:auto auto;grid-template-areas:"top" "bottom"}.bslib-value-box:not(.showcase-bottom) .value-box-grid .value-box-showcase{grid-area:top !important}.bslib-value-box:not(.showcase-bottom) .value-box-grid .value-box-area{grid-area:bottom !important;justify-content:end}}}.bslib-value-box .value-box-area{justify-content:center;padding:1.5rem 1rem;font-size:.9rem;font-weight:500}.bslib-value-box .value-box-area *{margin-bottom:0;margin-top:0}.bslib-value-box .value-box-title{font-size:1rem;margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2}.bslib-value-box .value-box-title:empty::after{content:" "}.bslib-value-box .value-box-value{font-size:calc(1.29rem + 0.48vw);margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2}@media(min-width: 1200px){.bslib-value-box .value-box-value{font-size:1.65rem}}.bslib-value-box .value-box-value:empty::after{content:" "}.bslib-value-box .value-box-showcase{align-items:center;justify-content:center;margin-top:auto;margin-bottom:auto;padding:1rem}.bslib-value-box .value-box-showcase .bi,.bslib-value-box .value-box-showcase .fa,.bslib-value-box .value-box-showcase .fab,.bslib-value-box .value-box-showcase .fas,.bslib-value-box .value-box-showcase .far{opacity:.85;min-width:50px;max-width:125%}.bslib-value-box .value-box-showcase .bi,.bslib-value-box .value-box-showcase .fa,.bslib-value-box .value-box-showcase .fab,.bslib-value-box .value-box-showcase .fas,.bslib-value-box .value-box-showcase .far{font-size:4rem}.bslib-value-box.showcase-top-right .value-box-grid{grid-template-columns:1fr var(---bslib-value-box-showcase-w, 50%)}.bslib-value-box.showcase-top-right .value-box-grid .value-box-showcase{grid-area:right;margin-left:auto;align-self:start;align-items:end;padding-left:0;padding-bottom:0}.bslib-value-box.showcase-top-right .value-box-grid .value-box-area{grid-area:left;align-self:end}.bslib-value-box.showcase-top-right[data-full-screen=true] .value-box-grid{grid-template-columns:auto var(---bslib-value-box-showcase-w-fs, 1fr)}.bslib-value-box.showcase-top-right[data-full-screen=true] .value-box-grid>div{align-self:center}.bslib-value-box.showcase-top-right:not([data-full-screen=true]) .value-box-showcase{margin-top:0}@container bslib-value-box (max-width: 300px){.bslib-value-box.showcase-top-right:not([data-full-screen=true]) .value-box-grid .value-box-showcase{padding-left:1rem}}.bslib-value-box.showcase-left-center .value-box-grid{grid-template-columns:var(---bslib-value-box-showcase-w, 30%) auto}.bslib-value-box.showcase-left-center[data-full-screen=true] .value-box-grid{grid-template-columns:var(---bslib-value-box-showcase-w-fs, 1fr) auto}.bslib-value-box.showcase-left-center:not([data-fill-screen=true]) .value-box-grid .value-box-showcase{grid-area:left}.bslib-value-box.showcase-left-center:not([data-fill-screen=true]) .value-box-grid .value-box-area{grid-area:right}.bslib-value-box.showcase-bottom .value-box-grid{grid-template-columns:1fr;grid-template-rows:1fr var(---bslib-value-box-showcase-h, auto);grid-template-areas:"top" "bottom";overflow:hidden}.bslib-value-box.showcase-bottom .value-box-grid .value-box-showcase{grid-area:bottom;padding:0;margin:0}.bslib-value-box.showcase-bottom .value-box-grid .value-box-area{grid-area:top}.bslib-value-box.showcase-bottom[data-full-screen=true] .value-box-grid{grid-template-rows:1fr var(---bslib-value-box-showcase-h-fs, 2fr)}.bslib-value-box.showcase-bottom[data-full-screen=true] .value-box-grid .value-box-showcase{padding:1rem}[data-bs-theme=dark] .bslib-value-box{--bslib-value-box-shadow: 0 0.5rem 1rem rgb(0 0 0 / 50%)}.bslib-card{overflow:auto}.bslib-card .card-body+.card-body{padding-top:0}.bslib-card .card-body{overflow:auto}.bslib-card .card-body p{margin-top:0}.bslib-card .card-body p:last-child{margin-bottom:0}.bslib-card .card-body{max-height:var(--bslib-card-body-max-height, none)}.bslib-card[data-full-screen=true]>.card-body{max-height:var(--bslib-card-body-max-height-full-screen, none)}.bslib-card .card-header .form-group{margin-bottom:0}.bslib-card .card-header .selectize-control{margin-bottom:0}.bslib-card .card-header .selectize-control .item{margin-right:1.15rem}.bslib-card .card-footer{margin-top:auto}.bslib-card .bslib-navs-card-title{display:flex;flex-wrap:wrap;justify-content:space-between;align-items:center}.bslib-card .bslib-navs-card-title .nav{margin-left:auto}.bslib-card .bslib-sidebar-layout:not([data-bslib-sidebar-border=true]){border:none}.bslib-card .bslib-sidebar-layout:not([data-bslib-sidebar-border-radius=true]){border-top-left-radius:0;border-top-right-radius:0}[data-full-screen=true]{position:fixed;inset:3.5rem 1rem 1rem;height:auto !important;max-height:none !important;width:auto !important;z-index:1070}.bslib-full-screen-enter{display:none;position:absolute;bottom:var(--bslib-full-screen-enter-bottom, 0.2rem);right:var(--bslib-full-screen-enter-right, 0);top:var(--bslib-full-screen-enter-top);left:var(--bslib-full-screen-enter-left);color:var(--bslib-color-fg, var(--bs-card-color));background-color:var(--bslib-color-bg, var(--bs-card-bg, var(--bs-body-bg)));border:var(--bs-card-border-width) solid var(--bslib-color-fg, var(--bs-card-border-color));box-shadow:0 2px 4px rgba(0,0,0,.15);margin:.2rem .4rem;padding:.55rem !important;font-size:.8rem;cursor:pointer;opacity:.7;z-index:1070}.bslib-full-screen-enter:hover{opacity:1}.card[data-full-screen=false]:hover>*>.bslib-full-screen-enter{display:block}.bslib-has-full-screen .card:hover>*>.bslib-full-screen-enter{display:none}@media(max-width: 575.98px){.bslib-full-screen-enter{display:none !important}}.bslib-full-screen-exit{position:relative;top:1.35rem;font-size:.9rem;cursor:pointer;text-decoration:none;display:flex;float:right;margin-right:2.15rem;align-items:center;color:rgba(var(--bs-body-bg-rgb), 0.8)}.bslib-full-screen-exit:hover{color:rgba(var(--bs-body-bg-rgb), 1)}.bslib-full-screen-exit svg{margin-left:.5rem;font-size:1.5rem}#bslib-full-screen-overlay{position:fixed;inset:0;background-color:rgba(var(--bs-body-color-rgb), 0.6);backdrop-filter:blur(2px);-webkit-backdrop-filter:blur(2px);z-index:1069;animation:bslib-full-screen-overlay-enter 400ms cubic-bezier(0.6, 0.02, 0.65, 1) forwards}@keyframes bslib-full-screen-overlay-enter{0%{opacity:0}100%{opacity:1}}.navbar+.container-fluid:has(>.tab-content>.tab-pane.active.html-fill-container),.navbar+.container-sm:has(>.tab-content>.tab-pane.active.html-fill-container),.navbar+.container-md:has(>.tab-content>.tab-pane.active.html-fill-container),.navbar+.container-lg:has(>.tab-content>.tab-pane.active.html-fill-container),.navbar+.container-xl:has(>.tab-content>.tab-pane.active.html-fill-container),.navbar+.container-xxl:has(>.tab-content>.tab-pane.active.html-fill-container){padding-left:0;padding-right:0}.navbar+.container-fluid>.tab-content>.tab-pane.active.html-fill-container,.navbar+.container-sm>.tab-content>.tab-pane.active.html-fill-container,.navbar+.container-md>.tab-content>.tab-pane.active.html-fill-container,.navbar+.container-lg>.tab-content>.tab-pane.active.html-fill-container,.navbar+.container-xl>.tab-content>.tab-pane.active.html-fill-container,.navbar+.container-xxl>.tab-content>.tab-pane.active.html-fill-container{padding:var(--bslib-spacer, 1rem);gap:var(--bslib-spacer, 1rem)}.navbar+.container-fluid>.tab-content>.tab-pane.active.html-fill-container:has(>.bslib-sidebar-layout:only-child),.navbar+.container-sm>.tab-content>.tab-pane.active.html-fill-container:has(>.bslib-sidebar-layout:only-child),.navbar+.container-md>.tab-content>.tab-pane.active.html-fill-container:has(>.bslib-sidebar-layout:only-child),.navbar+.container-lg>.tab-content>.tab-pane.active.html-fill-container:has(>.bslib-sidebar-layout:only-child),.navbar+.container-xl>.tab-content>.tab-pane.active.html-fill-container:has(>.bslib-sidebar-layout:only-child),.navbar+.container-xxl>.tab-content>.tab-pane.active.html-fill-container:has(>.bslib-sidebar-layout:only-child){padding:0}.navbar+.container-fluid>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border=true]),.navbar+.container-sm>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border=true]),.navbar+.container-md>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border=true]),.navbar+.container-lg>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border=true]),.navbar+.container-xl>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border=true]),.navbar+.container-xxl>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border=true]){border-left:none;border-right:none;border-bottom:none}.navbar+.container-fluid>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border-radius=true]),.navbar+.container-sm>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border-radius=true]),.navbar+.container-md>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border-radius=true]),.navbar+.container-lg>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border-radius=true]),.navbar+.container-xl>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border-radius=true]),.navbar+.container-xxl>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border-radius=true]){border-radius:0}.navbar+div>.bslib-sidebar-layout{border-top:var(--bslib-sidebar-border)}:root{--bslib-page-sidebar-title-bg: #517699;--bslib-page-sidebar-title-color: #ffffff}.bslib-page-title{background-color:var(--bslib-page-sidebar-title-bg);color:var(--bslib-page-sidebar-title-color);font-size:1.25rem;font-weight:300;padding:var(--bslib-spacer, 1rem);padding-left:1.5rem;margin-bottom:0;border-bottom:1px solid #dee2e6}.html-fill-container{display:flex;flex-direction:column;min-height:0;min-width:0}.html-fill-container>.html-fill-item{flex:1 1 auto;min-height:0;min-width:0}.html-fill-container>:not(.html-fill-item){flex:0 0 auto}.tippy-box[data-theme~=quarto]{background-color:#fff;border:solid 1px #dee2e6;border-radius:.375rem;color:#212529;font-size:.875rem}.tippy-box[data-theme~=quarto]>.tippy-backdrop{background-color:#fff}.tippy-box[data-theme~=quarto]>.tippy-arrow:after,.tippy-box[data-theme~=quarto]>.tippy-svg-arrow:after{content:"";position:absolute;z-index:-1}.tippy-box[data-theme~=quarto]>.tippy-arrow:after{border-color:rgba(0,0,0,0);border-style:solid}.tippy-box[data-placement^=top]>.tippy-arrow:before{bottom:-6px}.tippy-box[data-placement^=bottom]>.tippy-arrow:before{top:-6px}.tippy-box[data-placement^=right]>.tippy-arrow:before{left:-6px}.tippy-box[data-placement^=left]>.tippy-arrow:before{right:-6px}.tippy-box[data-theme~=quarto][data-placement^=top]>.tippy-arrow:before{border-top-color:#fff}.tippy-box[data-theme~=quarto][data-placement^=top]>.tippy-arrow:after{border-top-color:#dee2e6;border-width:7px 7px 0;top:17px;left:1px}.tippy-box[data-theme~=quarto][data-placement^=top]>.tippy-svg-arrow>svg{top:16px}.tippy-box[data-theme~=quarto][data-placement^=top]>.tippy-svg-arrow:after{top:17px}.tippy-box[data-theme~=quarto][data-placement^=bottom]>.tippy-arrow:before{border-bottom-color:#fff;bottom:16px}.tippy-box[data-theme~=quarto][data-placement^=bottom]>.tippy-arrow:after{border-bottom-color:#dee2e6;border-width:0 7px 7px;bottom:17px;left:1px}.tippy-box[data-theme~=quarto][data-placement^=bottom]>.tippy-svg-arrow>svg{bottom:15px}.tippy-box[data-theme~=quarto][data-placement^=bottom]>.tippy-svg-arrow:after{bottom:17px}.tippy-box[data-theme~=quarto][data-placement^=left]>.tippy-arrow:before{border-left-color:#fff}.tippy-box[data-theme~=quarto][data-placement^=left]>.tippy-arrow:after{border-left-color:#dee2e6;border-width:7px 0 7px 7px;left:17px;top:1px}.tippy-box[data-theme~=quarto][data-placement^=left]>.tippy-svg-arrow>svg{left:11px}.tippy-box[data-theme~=quarto][data-placement^=left]>.tippy-svg-arrow:after{left:12px}.tippy-box[data-theme~=quarto][data-placement^=right]>.tippy-arrow:before{border-right-color:#fff;right:16px}.tippy-box[data-theme~=quarto][data-placement^=right]>.tippy-arrow:after{border-width:7px 7px 7px 0;right:17px;top:1px;border-right-color:#dee2e6}.tippy-box[data-theme~=quarto][data-placement^=right]>.tippy-svg-arrow>svg{right:11px}.tippy-box[data-theme~=quarto][data-placement^=right]>.tippy-svg-arrow:after{right:12px}.tippy-box[data-theme~=quarto]>.tippy-svg-arrow{fill:#212529}.tippy-box[data-theme~=quarto]>.tippy-svg-arrow:after{background-image:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iNiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMCA2czEuNzk2LS4wMTMgNC42Ny0zLjYxNUM1Ljg1MS45IDYuOTMuMDA2IDggMGMxLjA3LS4wMDYgMi4xNDguODg3IDMuMzQzIDIuMzg1QzE0LjIzMyA2LjAwNSAxNiA2IDE2IDZIMHoiIGZpbGw9InJnYmEoMCwgOCwgMTYsIDAuMikiLz48L3N2Zz4=);background-size:16px 6px;width:16px;height:6px}.top-right{position:absolute;top:1em;right:1em}.visually-hidden{border:0;clip:rect(0 0 0 0);height:auto;margin:0;overflow:hidden;padding:0;position:absolute;width:1px;white-space:nowrap}.hidden{display:none !important}.zindex-bottom{z-index:-1 !important}figure.figure{display:block}.quarto-layout-panel{margin-bottom:1em}.quarto-layout-panel>figure{width:100%}.quarto-layout-panel>figure>figcaption,.quarto-layout-panel>.panel-caption{margin-top:10pt}.quarto-layout-panel>.table-caption{margin-top:0px}.table-caption p{margin-bottom:.5em}.quarto-layout-row{display:flex;flex-direction:row;align-items:flex-start}.quarto-layout-valign-top{align-items:flex-start}.quarto-layout-valign-bottom{align-items:flex-end}.quarto-layout-valign-center{align-items:center}.quarto-layout-cell{position:relative;margin-right:20px}.quarto-layout-cell:last-child{margin-right:0}.quarto-layout-cell figure,.quarto-layout-cell>p{margin:.2em}.quarto-layout-cell img{max-width:100%}.quarto-layout-cell .html-widget{width:100% !important}.quarto-layout-cell div figure p{margin:0}.quarto-layout-cell figure{display:block;margin-inline-start:0;margin-inline-end:0}.quarto-layout-cell table{display:inline-table}.quarto-layout-cell-subref figcaption,figure .quarto-layout-row figure figcaption{text-align:center;font-style:italic}.quarto-figure{position:relative;margin-bottom:1em}.quarto-figure>figure{width:100%;margin-bottom:0}.quarto-figure-left>figure>p,.quarto-figure-left>figure>div{text-align:left}.quarto-figure-center>figure>p,.quarto-figure-center>figure>div{text-align:center}.quarto-figure-right>figure>p,.quarto-figure-right>figure>div{text-align:right}.quarto-figure>figure>div.cell-annotation,.quarto-figure>figure>div code{text-align:left}figure>p:empty{display:none}figure>p:first-child{margin-top:0;margin-bottom:0}figure>figcaption.quarto-float-caption-bottom{margin-bottom:.5em}figure>figcaption.quarto-float-caption-top{margin-top:.5em}div[id^=tbl-]{position:relative}.quarto-figure>.anchorjs-link{position:absolute;top:.6em;right:.5em}div[id^=tbl-]>.anchorjs-link{position:absolute;top:.7em;right:.3em}.quarto-figure:hover>.anchorjs-link,div[id^=tbl-]:hover>.anchorjs-link,h2:hover>.anchorjs-link,.h2:hover>.anchorjs-link,h3:hover>.anchorjs-link,.h3:hover>.anchorjs-link,h4:hover>.anchorjs-link,.h4:hover>.anchorjs-link,h5:hover>.anchorjs-link,.h5:hover>.anchorjs-link,h6:hover>.anchorjs-link,.h6:hover>.anchorjs-link,.reveal-anchorjs-link>.anchorjs-link{opacity:1}#title-block-header{margin-block-end:1rem;position:relative;margin-top:-1px}#title-block-header .abstract{margin-block-start:1rem}#title-block-header .abstract .abstract-title{font-weight:600}#title-block-header a{text-decoration:none}#title-block-header .author,#title-block-header .date,#title-block-header .doi{margin-block-end:.2rem}#title-block-header .quarto-title-block>div{display:flex}#title-block-header .quarto-title-block>div>h1,#title-block-header .quarto-title-block>div>.h1{flex-grow:1}#title-block-header .quarto-title-block>div>button{flex-shrink:0;height:2.25rem;margin-top:0}@media(min-width: 992px){#title-block-header .quarto-title-block>div>button{margin-top:5px}}tr.header>th>p:last-of-type{margin-bottom:0px}table,table.table{margin-top:.5rem;margin-bottom:.5rem}caption,.table-caption{padding-top:.5rem;padding-bottom:.5rem;text-align:center}figure.quarto-float-tbl figcaption.quarto-float-caption-top{margin-top:.5rem;margin-bottom:.25rem;text-align:center}figure.quarto-float-tbl figcaption.quarto-float-caption-bottom{padding-top:.25rem;margin-bottom:.5rem;text-align:center}.utterances{max-width:none;margin-left:-8px}iframe{margin-bottom:1em}details{margin-bottom:1em}details[show]{margin-bottom:0}details>summary{color:rgba(33,37,41,.75)}details>summary>p:only-child{display:inline}pre.sourceCode,code.sourceCode{position:relative}dd code:not(.sourceCode),p code:not(.sourceCode){white-space:pre-wrap}code{white-space:pre}@media print{code{white-space:pre-wrap}}pre>code{display:block}pre>code.sourceCode{white-space:pre}pre>code.sourceCode>span>a:first-child::before{text-decoration:none}pre.code-overflow-wrap>code.sourceCode{white-space:pre-wrap}pre.code-overflow-scroll>code.sourceCode{white-space:pre}code a:any-link{color:inherit;text-decoration:none}code a:hover{color:inherit;text-decoration:underline}ul.task-list{padding-left:1em}[data-tippy-root]{display:inline-block}.tippy-content .footnote-back{display:none}.footnote-back{margin-left:.2em}.tippy-content{overflow-x:auto}.quarto-embedded-source-code{display:none}.quarto-unresolved-ref{font-weight:600}.quarto-cover-image{max-width:35%;float:right;margin-left:30px}.cell-output-display .widget-subarea{margin-bottom:1em}.cell-output-display:not(.no-overflow-x),.knitsql-table:not(.no-overflow-x){overflow-x:auto}.panel-input{margin-bottom:1em}.panel-input>div,.panel-input>div>div{display:inline-block;vertical-align:top;padding-right:12px}.panel-input>p:last-child{margin-bottom:0}.layout-sidebar{margin-bottom:1em}.layout-sidebar .tab-content{border:none}.tab-content>.page-columns.active{display:grid}div.sourceCode>iframe{width:100%;height:300px;margin-bottom:-0.5em}a{text-underline-offset:3px}div.ansi-escaped-output{font-family:monospace;display:block}/*! -* -* ansi colors from IPython notebook's -* -* we also add `bright-[color]-` synonyms for the `-[color]-intense` classes since -* that seems to be what ansi_up emits -* -*/.ansi-black-fg{color:#3e424d}.ansi-black-bg{background-color:#3e424d}.ansi-black-intense-black,.ansi-bright-black-fg{color:#282c36}.ansi-black-intense-black,.ansi-bright-black-bg{background-color:#282c36}.ansi-red-fg{color:#e75c58}.ansi-red-bg{background-color:#e75c58}.ansi-red-intense-red,.ansi-bright-red-fg{color:#b22b31}.ansi-red-intense-red,.ansi-bright-red-bg{background-color:#b22b31}.ansi-green-fg{color:#00a250}.ansi-green-bg{background-color:#00a250}.ansi-green-intense-green,.ansi-bright-green-fg{color:#007427}.ansi-green-intense-green,.ansi-bright-green-bg{background-color:#007427}.ansi-yellow-fg{color:#ddb62b}.ansi-yellow-bg{background-color:#ddb62b}.ansi-yellow-intense-yellow,.ansi-bright-yellow-fg{color:#b27d12}.ansi-yellow-intense-yellow,.ansi-bright-yellow-bg{background-color:#b27d12}.ansi-blue-fg{color:#208ffb}.ansi-blue-bg{background-color:#208ffb}.ansi-blue-intense-blue,.ansi-bright-blue-fg{color:#0065ca}.ansi-blue-intense-blue,.ansi-bright-blue-bg{background-color:#0065ca}.ansi-magenta-fg{color:#d160c4}.ansi-magenta-bg{background-color:#d160c4}.ansi-magenta-intense-magenta,.ansi-bright-magenta-fg{color:#a03196}.ansi-magenta-intense-magenta,.ansi-bright-magenta-bg{background-color:#a03196}.ansi-cyan-fg{color:#60c6c8}.ansi-cyan-bg{background-color:#60c6c8}.ansi-cyan-intense-cyan,.ansi-bright-cyan-fg{color:#258f8f}.ansi-cyan-intense-cyan,.ansi-bright-cyan-bg{background-color:#258f8f}.ansi-white-fg{color:#c5c1b4}.ansi-white-bg{background-color:#c5c1b4}.ansi-white-intense-white,.ansi-bright-white-fg{color:#a1a6b2}.ansi-white-intense-white,.ansi-bright-white-bg{background-color:#a1a6b2}.ansi-default-inverse-fg{color:#fff}.ansi-default-inverse-bg{background-color:#000}.ansi-bold{font-weight:bold}.ansi-underline{text-decoration:underline}:root{--quarto-body-bg: #ffffff;--quarto-body-color: #212529;--quarto-text-muted: rgba(33, 37, 41, 0.75);--quarto-border-color: #dee2e6;--quarto-border-width: 1px;--quarto-border-radius: 0.375rem}table.gt_table{color:var(--quarto-body-color);font-size:1em;width:100%;background-color:rgba(0,0,0,0);border-top-width:inherit;border-bottom-width:inherit;border-color:var(--quarto-border-color)}table.gt_table th.gt_column_spanner_outer{color:var(--quarto-body-color);background-color:rgba(0,0,0,0);border-top-width:inherit;border-bottom-width:inherit;border-color:var(--quarto-border-color)}table.gt_table th.gt_col_heading{color:var(--quarto-body-color);font-weight:bold;background-color:rgba(0,0,0,0)}table.gt_table thead.gt_col_headings{border-bottom:1px solid currentColor;border-top-width:inherit;border-top-color:var(--quarto-border-color)}table.gt_table thead.gt_col_headings:not(:first-child){border-top-width:1px;border-top-color:var(--quarto-border-color)}table.gt_table td.gt_row{border-bottom-width:1px;border-bottom-color:var(--quarto-border-color);border-top-width:0px}table.gt_table tbody.gt_table_body{border-top-width:1px;border-bottom-width:1px;border-bottom-color:var(--quarto-border-color);border-top-color:currentColor}div.columns{display:initial;gap:initial}div.column{display:inline-block;overflow-x:initial;vertical-align:top;width:50%}.code-annotation-tip-content{word-wrap:break-word}.code-annotation-container-hidden{display:none !important}dl.code-annotation-container-grid{display:grid;grid-template-columns:min-content auto}dl.code-annotation-container-grid dt{grid-column:1}dl.code-annotation-container-grid dd{grid-column:2}pre.sourceCode.code-annotation-code{padding-right:0}code.sourceCode .code-annotation-anchor{z-index:100;position:relative;float:right;background-color:rgba(0,0,0,0)}input[type=checkbox]{margin-right:.5ch}:root{--mermaid-bg-color: #ffffff;--mermaid-edge-color: #6c757d;--mermaid-node-fg-color: #212529;--mermaid-fg-color: #212529;--mermaid-fg-color--lighter: #383f45;--mermaid-fg-color--lightest: #4e5862;--mermaid-font-family: system-ui, -apple-system, Segoe UI, Roboto, Helvetica Neue, Noto Sans, Liberation Sans, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol, Noto Color Emoji;--mermaid-label-bg-color: #ffffff;--mermaid-label-fg-color: #0d6efd;--mermaid-node-bg-color: rgba(13, 110, 253, 0.1);--mermaid-node-fg-color: #212529}@media print{:root{font-size:11pt}#quarto-sidebar,#TOC,.nav-page{display:none}.page-columns .content{grid-column-start:page-start}.fixed-top{position:relative}.panel-caption,.figure-caption,figcaption{color:#666}}.code-copy-button{position:absolute;top:0;right:0;border:0;margin-top:5px;margin-right:5px;background-color:rgba(0,0,0,0);z-index:3}.code-copy-button:focus{outline:none}.code-copy-button-tooltip{font-size:.75em}pre.sourceCode:hover>.code-copy-button>.bi::before{display:inline-block;height:1rem;width:1rem;content:"";vertical-align:-0.125em;background-image:url('data:image/svg+xml,');background-repeat:no-repeat;background-size:1rem 1rem}pre.sourceCode:hover>.code-copy-button-checked>.bi::before{background-image:url('data:image/svg+xml,')}pre.sourceCode:hover>.code-copy-button:hover>.bi::before{background-image:url('data:image/svg+xml,')}pre.sourceCode:hover>.code-copy-button-checked:hover>.bi::before{background-image:url('data:image/svg+xml,')}main ol ol,main ul ul,main ol ul,main ul ol{margin-bottom:1em}ul>li:not(:has(>p))>ul,ol>li:not(:has(>p))>ul,ul>li:not(:has(>p))>ol,ol>li:not(:has(>p))>ol{margin-bottom:0}ul>li:not(:has(>p))>ul>li:has(>p),ol>li:not(:has(>p))>ul>li:has(>p),ul>li:not(:has(>p))>ol>li:has(>p),ol>li:not(:has(>p))>ol>li:has(>p){margin-top:1rem}body{margin:0}main.page-columns>header>h1.title,main.page-columns>header>.title.h1{margin-bottom:0}@media(min-width: 992px){body .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset] 35px [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(500px, calc(850px - 3em)) [body-content-end] 1.5em [body-end] 35px [body-end-outset] minmax(75px, 145px) [page-end-inset] 35px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.fullcontent:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset] 35px [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(500px, calc(850px - 3em)) [body-content-end] 1.5em [body-end] 35px [body-end-outset] 35px [page-end-inset page-end] 5fr [screen-end-inset] 1.5em}body.slimcontent:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset] 35px [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(500px, calc(850px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(0px, 200px) [page-end-inset] 35px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.listing:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start] minmax(50px, 100px) [page-start-inset] 50px [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(500px, calc(850px - 3em)) [body-content-end] 3em [body-end] 50px [body-end-outset] minmax(0px, 250px) [page-end-inset] minmax(50px, 100px) [page-end] 1fr [screen-end-inset] 1.5em [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] 35px [page-start-inset] minmax(0px, 175px) [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(450px, calc(800px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(0px, 200px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] 35px [page-start-inset] minmax(0px, 175px) [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(450px, calc(800px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(0px, 200px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] minmax(25px, 50px) [page-start-inset] minmax(50px, 150px) [body-start-outset] minmax(25px, 50px) [body-start] 1.5em [body-content-start] minmax(500px, calc(800px - 3em)) [body-content-end] 1.5em [body-end] minmax(25px, 50px) [body-end-outset] minmax(50px, 150px) [page-end-inset] minmax(25px, 50px) [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start] minmax(50px, 100px) [page-start-inset] 50px [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(500px, calc(1000px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(50px, 100px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked.fullcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start] minmax(50px, 100px) [page-start-inset] 50px [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(500px, calc(1000px - 3em)) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating.fullcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] 50px [page-start-inset] minmax(50px, 150px) [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(500px, calc(800px - 3em)) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked.slimcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start] minmax(50px, 100px) [page-start-inset] 50px [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(450px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(0px, 200px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked.listing .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start] minmax(50px, 100px) [page-start-inset] 50px [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(500px, calc(1000px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(0px, 200px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating.slimcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] 50px [page-start-inset] minmax(50px, 150px) [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(450px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(50px, 150px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating.listing .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] minmax(25px, 50px) [page-start-inset] minmax(50px, 150px) [body-start-outset] minmax(25px, 50px) [body-start] 1.5em [body-content-start] minmax(500px, calc(800px - 3em)) [body-content-end] 1.5em [body-end] minmax(25px, 50px) [body-end-outset] minmax(50px, 150px) [page-end-inset] minmax(25px, 50px) [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}}@media(max-width: 991.98px){body .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset] 5fr [body-start] 1.5em [body-content-start] minmax(500px, calc(800px - 3em)) [body-content-end] 1.5em [body-end] 35px [body-end-outset] minmax(75px, 145px) [page-end-inset] 35px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.fullcontent:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset] 5fr [body-start] 1.5em [body-content-start] minmax(500px, calc(800px - 3em)) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.slimcontent:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset] 5fr [body-start] 1.5em [body-content-start] minmax(500px, calc(800px - 3em)) [body-content-end] 1.5em [body-end] 35px [body-end-outset] minmax(75px, 145px) [page-end-inset] 35px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.listing:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset] 5fr [body-start] 1.5em [body-content-start] minmax(500px, calc(1250px - 3em)) [body-content-end body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] 35px [page-start-inset] minmax(0px, 145px) [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(450px, calc(800px - 3em)) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] 35px [page-start-inset] minmax(0px, 145px) [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(450px, calc(800px - 3em)) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset body-start-outset body-start] 1.5em [body-content-start] minmax(500px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(75px, 150px) [page-end-inset] 25px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(500px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(25px, 50px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked.fullcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(500px, calc(1000px - 3em)) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating.fullcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset body-start-outset body-start] 1em [body-content-start] minmax(500px, calc(800px - 3em)) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 4fr [screen-end-inset] 1.5em [screen-end]}body.docked.slimcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(500px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(25px, 50px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked.listing .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(500px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(25px, 50px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating.slimcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset body-start-outset body-start] 1em [body-content-start] minmax(500px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 35px [body-end-outset] minmax(75px, 145px) [page-end-inset] 35px [page-end] 4fr [screen-end-inset] 1.5em [screen-end]}body.floating.listing .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset body-start-outset body-start] 1em [body-content-start] minmax(500px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(75px, 150px) [page-end-inset] 25px [page-end] 4fr [screen-end-inset] 1.5em [screen-end]}}@media(max-width: 767.98px){body .page-columns,body.fullcontent:not(.floating):not(.docked) .page-columns,body.slimcontent:not(.floating):not(.docked) .page-columns,body.docked .page-columns,body.docked.slimcontent .page-columns,body.docked.fullcontent .page-columns,body.floating .page-columns,body.floating.slimcontent .page-columns,body.floating.fullcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(0px, 1fr) [body-content-end body-end body-end-outset page-end-inset page-end screen-end-inset] 1.5em [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(0px, 1fr) [body-content-end body-end body-end-outset page-end-inset page-end screen-end-inset] 1.5em [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(0px, 1fr) [body-content-end body-end body-end-outset page-end-inset page-end screen-end-inset] 1.5em [screen-end]}nav[role=doc-toc]{display:none}}body,.page-row-navigation{grid-template-rows:[page-top] max-content [contents-top] max-content [contents-bottom] max-content [page-bottom]}.page-rows-contents{grid-template-rows:[content-top] minmax(max-content, 1fr) [content-bottom] minmax(60px, max-content) [page-bottom]}.page-full{grid-column:screen-start/screen-end !important}.page-columns>*{grid-column:body-content-start/body-content-end}.page-columns.column-page>*{grid-column:page-start/page-end}.page-columns.column-page-left .page-columns.page-full>*,.page-columns.column-page-left>*{grid-column:page-start/body-content-end}.page-columns.column-page-right .page-columns.page-full>*,.page-columns.column-page-right>*{grid-column:body-content-start/page-end}.page-rows{grid-auto-rows:auto}.header{grid-column:screen-start/screen-end;grid-row:page-top/contents-top}#quarto-content{padding:0;grid-column:screen-start/screen-end;grid-row:contents-top/contents-bottom}body.floating .sidebar.sidebar-navigation{grid-column:page-start/body-start;grid-row:content-top/page-bottom}body.docked .sidebar.sidebar-navigation{grid-column:screen-start/body-start;grid-row:content-top/page-bottom}.sidebar.toc-left{grid-column:page-start/body-start;grid-row:content-top/page-bottom}.sidebar.margin-sidebar{grid-column:body-end/page-end;grid-row:content-top/page-bottom}.page-columns .content{grid-column:body-content-start/body-content-end;grid-row:content-top/content-bottom;align-content:flex-start}.page-columns .page-navigation{grid-column:body-content-start/body-content-end;grid-row:content-bottom/page-bottom}.page-columns .footer{grid-column:screen-start/screen-end;grid-row:contents-bottom/page-bottom}.page-columns .column-body{grid-column:body-content-start/body-content-end}.page-columns .column-body-fullbleed{grid-column:body-start/body-end}.page-columns .column-body-outset{grid-column:body-start-outset/body-end-outset;z-index:998;opacity:.999}.page-columns .column-body-outset table{background:#fff}.page-columns .column-body-outset-left{grid-column:body-start-outset/body-content-end;z-index:998;opacity:.999}.page-columns .column-body-outset-left table{background:#fff}.page-columns .column-body-outset-right{grid-column:body-content-start/body-end-outset;z-index:998;opacity:.999}.page-columns .column-body-outset-right table{background:#fff}.page-columns .column-page{grid-column:page-start/page-end;z-index:998;opacity:.999}.page-columns .column-page table{background:#fff}.page-columns .column-page-inset{grid-column:page-start-inset/page-end-inset;z-index:998;opacity:.999}.page-columns .column-page-inset table{background:#fff}.page-columns .column-page-inset-left{grid-column:page-start-inset/body-content-end;z-index:998;opacity:.999}.page-columns .column-page-inset-left table{background:#fff}.page-columns .column-page-inset-right{grid-column:body-content-start/page-end-inset;z-index:998;opacity:.999}.page-columns .column-page-inset-right figcaption table{background:#fff}.page-columns .column-page-left{grid-column:page-start/body-content-end;z-index:998;opacity:.999}.page-columns .column-page-left table{background:#fff}.page-columns .column-page-right{grid-column:body-content-start/page-end;z-index:998;opacity:.999}.page-columns .column-page-right figcaption table{background:#fff}#quarto-content.page-columns #quarto-margin-sidebar,#quarto-content.page-columns #quarto-sidebar{z-index:1}@media(max-width: 991.98px){#quarto-content.page-columns #quarto-margin-sidebar.collapse,#quarto-content.page-columns #quarto-sidebar.collapse,#quarto-content.page-columns #quarto-margin-sidebar.collapsing,#quarto-content.page-columns #quarto-sidebar.collapsing{z-index:1055}}#quarto-content.page-columns main.column-page,#quarto-content.page-columns main.column-page-right,#quarto-content.page-columns main.column-page-left{z-index:0}.page-columns .column-screen-inset{grid-column:screen-start-inset/screen-end-inset;z-index:998;opacity:.999}.page-columns .column-screen-inset table{background:#fff}.page-columns .column-screen-inset-left{grid-column:screen-start-inset/body-content-end;z-index:998;opacity:.999}.page-columns .column-screen-inset-left table{background:#fff}.page-columns .column-screen-inset-right{grid-column:body-content-start/screen-end-inset;z-index:998;opacity:.999}.page-columns .column-screen-inset-right table{background:#fff}.page-columns .column-screen{grid-column:screen-start/screen-end;z-index:998;opacity:.999}.page-columns .column-screen table{background:#fff}.page-columns .column-screen-left{grid-column:screen-start/body-content-end;z-index:998;opacity:.999}.page-columns .column-screen-left table{background:#fff}.page-columns .column-screen-right{grid-column:body-content-start/screen-end;z-index:998;opacity:.999}.page-columns .column-screen-right table{background:#fff}.page-columns .column-screen-inset-shaded{grid-column:screen-start/screen-end;padding:1em;background:#f8f9fa;z-index:998;opacity:.999;margin-bottom:1em}.zindex-content{z-index:998;opacity:.999}.zindex-modal{z-index:1055;opacity:.999}.zindex-over-content{z-index:999;opacity:.999}img.img-fluid.column-screen,img.img-fluid.column-screen-inset-shaded,img.img-fluid.column-screen-inset,img.img-fluid.column-screen-inset-left,img.img-fluid.column-screen-inset-right,img.img-fluid.column-screen-left,img.img-fluid.column-screen-right{width:100%}@media(min-width: 992px){.margin-caption,div.aside,aside:not(.footnotes):not(.sidebar),.column-margin{grid-column:body-end/page-end !important;z-index:998}.column-sidebar{grid-column:page-start/body-start !important;z-index:998}.column-leftmargin{grid-column:screen-start-inset/body-start !important;z-index:998}.no-row-height{height:1em;overflow:visible}}@media(max-width: 991.98px){.margin-caption,div.aside,aside:not(.footnotes):not(.sidebar),.column-margin{grid-column:body-end/page-end !important;z-index:998}.no-row-height{height:1em;overflow:visible}.page-columns.page-full{overflow:visible}.page-columns.toc-left .margin-caption,.page-columns.toc-left div.aside,.page-columns.toc-left aside:not(.footnotes):not(.sidebar),.page-columns.toc-left .column-margin{grid-column:body-content-start/body-content-end !important;z-index:998;opacity:.999}.page-columns.toc-left .no-row-height{height:initial;overflow:initial}}@media(max-width: 767.98px){.margin-caption,div.aside,aside:not(.footnotes):not(.sidebar),.column-margin{grid-column:body-content-start/body-content-end !important;z-index:998;opacity:.999}.no-row-height{height:initial;overflow:initial}#quarto-margin-sidebar{display:none}#quarto-sidebar-toc-left{display:none}.hidden-sm{display:none}}.panel-grid{display:grid;grid-template-rows:repeat(1, 1fr);grid-template-columns:repeat(24, 1fr);gap:1em}.panel-grid .g-col-1{grid-column:auto/span 1}.panel-grid .g-col-2{grid-column:auto/span 2}.panel-grid .g-col-3{grid-column:auto/span 3}.panel-grid .g-col-4{grid-column:auto/span 4}.panel-grid .g-col-5{grid-column:auto/span 5}.panel-grid .g-col-6{grid-column:auto/span 6}.panel-grid .g-col-7{grid-column:auto/span 7}.panel-grid .g-col-8{grid-column:auto/span 8}.panel-grid .g-col-9{grid-column:auto/span 9}.panel-grid .g-col-10{grid-column:auto/span 10}.panel-grid .g-col-11{grid-column:auto/span 11}.panel-grid .g-col-12{grid-column:auto/span 12}.panel-grid .g-col-13{grid-column:auto/span 13}.panel-grid .g-col-14{grid-column:auto/span 14}.panel-grid .g-col-15{grid-column:auto/span 15}.panel-grid .g-col-16{grid-column:auto/span 16}.panel-grid .g-col-17{grid-column:auto/span 17}.panel-grid .g-col-18{grid-column:auto/span 18}.panel-grid .g-col-19{grid-column:auto/span 19}.panel-grid .g-col-20{grid-column:auto/span 20}.panel-grid .g-col-21{grid-column:auto/span 21}.panel-grid .g-col-22{grid-column:auto/span 22}.panel-grid .g-col-23{grid-column:auto/span 23}.panel-grid .g-col-24{grid-column:auto/span 24}.panel-grid .g-start-1{grid-column-start:1}.panel-grid .g-start-2{grid-column-start:2}.panel-grid .g-start-3{grid-column-start:3}.panel-grid .g-start-4{grid-column-start:4}.panel-grid .g-start-5{grid-column-start:5}.panel-grid .g-start-6{grid-column-start:6}.panel-grid .g-start-7{grid-column-start:7}.panel-grid .g-start-8{grid-column-start:8}.panel-grid .g-start-9{grid-column-start:9}.panel-grid .g-start-10{grid-column-start:10}.panel-grid .g-start-11{grid-column-start:11}.panel-grid .g-start-12{grid-column-start:12}.panel-grid .g-start-13{grid-column-start:13}.panel-grid .g-start-14{grid-column-start:14}.panel-grid .g-start-15{grid-column-start:15}.panel-grid .g-start-16{grid-column-start:16}.panel-grid .g-start-17{grid-column-start:17}.panel-grid .g-start-18{grid-column-start:18}.panel-grid .g-start-19{grid-column-start:19}.panel-grid .g-start-20{grid-column-start:20}.panel-grid .g-start-21{grid-column-start:21}.panel-grid .g-start-22{grid-column-start:22}.panel-grid .g-start-23{grid-column-start:23}@media(min-width: 576px){.panel-grid .g-col-sm-1{grid-column:auto/span 1}.panel-grid .g-col-sm-2{grid-column:auto/span 2}.panel-grid .g-col-sm-3{grid-column:auto/span 3}.panel-grid .g-col-sm-4{grid-column:auto/span 4}.panel-grid .g-col-sm-5{grid-column:auto/span 5}.panel-grid .g-col-sm-6{grid-column:auto/span 6}.panel-grid .g-col-sm-7{grid-column:auto/span 7}.panel-grid .g-col-sm-8{grid-column:auto/span 8}.panel-grid .g-col-sm-9{grid-column:auto/span 9}.panel-grid .g-col-sm-10{grid-column:auto/span 10}.panel-grid .g-col-sm-11{grid-column:auto/span 11}.panel-grid .g-col-sm-12{grid-column:auto/span 12}.panel-grid .g-col-sm-13{grid-column:auto/span 13}.panel-grid .g-col-sm-14{grid-column:auto/span 14}.panel-grid .g-col-sm-15{grid-column:auto/span 15}.panel-grid .g-col-sm-16{grid-column:auto/span 16}.panel-grid .g-col-sm-17{grid-column:auto/span 17}.panel-grid .g-col-sm-18{grid-column:auto/span 18}.panel-grid .g-col-sm-19{grid-column:auto/span 19}.panel-grid .g-col-sm-20{grid-column:auto/span 20}.panel-grid .g-col-sm-21{grid-column:auto/span 21}.panel-grid .g-col-sm-22{grid-column:auto/span 22}.panel-grid .g-col-sm-23{grid-column:auto/span 23}.panel-grid .g-col-sm-24{grid-column:auto/span 24}.panel-grid .g-start-sm-1{grid-column-start:1}.panel-grid .g-start-sm-2{grid-column-start:2}.panel-grid .g-start-sm-3{grid-column-start:3}.panel-grid .g-start-sm-4{grid-column-start:4}.panel-grid .g-start-sm-5{grid-column-start:5}.panel-grid .g-start-sm-6{grid-column-start:6}.panel-grid .g-start-sm-7{grid-column-start:7}.panel-grid .g-start-sm-8{grid-column-start:8}.panel-grid .g-start-sm-9{grid-column-start:9}.panel-grid .g-start-sm-10{grid-column-start:10}.panel-grid .g-start-sm-11{grid-column-start:11}.panel-grid .g-start-sm-12{grid-column-start:12}.panel-grid .g-start-sm-13{grid-column-start:13}.panel-grid .g-start-sm-14{grid-column-start:14}.panel-grid .g-start-sm-15{grid-column-start:15}.panel-grid .g-start-sm-16{grid-column-start:16}.panel-grid .g-start-sm-17{grid-column-start:17}.panel-grid .g-start-sm-18{grid-column-start:18}.panel-grid .g-start-sm-19{grid-column-start:19}.panel-grid .g-start-sm-20{grid-column-start:20}.panel-grid .g-start-sm-21{grid-column-start:21}.panel-grid .g-start-sm-22{grid-column-start:22}.panel-grid .g-start-sm-23{grid-column-start:23}}@media(min-width: 768px){.panel-grid .g-col-md-1{grid-column:auto/span 1}.panel-grid .g-col-md-2{grid-column:auto/span 2}.panel-grid .g-col-md-3{grid-column:auto/span 3}.panel-grid .g-col-md-4{grid-column:auto/span 4}.panel-grid .g-col-md-5{grid-column:auto/span 5}.panel-grid .g-col-md-6{grid-column:auto/span 6}.panel-grid .g-col-md-7{grid-column:auto/span 7}.panel-grid .g-col-md-8{grid-column:auto/span 8}.panel-grid .g-col-md-9{grid-column:auto/span 9}.panel-grid .g-col-md-10{grid-column:auto/span 10}.panel-grid .g-col-md-11{grid-column:auto/span 11}.panel-grid .g-col-md-12{grid-column:auto/span 12}.panel-grid .g-col-md-13{grid-column:auto/span 13}.panel-grid .g-col-md-14{grid-column:auto/span 14}.panel-grid .g-col-md-15{grid-column:auto/span 15}.panel-grid .g-col-md-16{grid-column:auto/span 16}.panel-grid .g-col-md-17{grid-column:auto/span 17}.panel-grid .g-col-md-18{grid-column:auto/span 18}.panel-grid .g-col-md-19{grid-column:auto/span 19}.panel-grid .g-col-md-20{grid-column:auto/span 20}.panel-grid .g-col-md-21{grid-column:auto/span 21}.panel-grid .g-col-md-22{grid-column:auto/span 22}.panel-grid .g-col-md-23{grid-column:auto/span 23}.panel-grid .g-col-md-24{grid-column:auto/span 24}.panel-grid .g-start-md-1{grid-column-start:1}.panel-grid .g-start-md-2{grid-column-start:2}.panel-grid .g-start-md-3{grid-column-start:3}.panel-grid .g-start-md-4{grid-column-start:4}.panel-grid .g-start-md-5{grid-column-start:5}.panel-grid .g-start-md-6{grid-column-start:6}.panel-grid .g-start-md-7{grid-column-start:7}.panel-grid .g-start-md-8{grid-column-start:8}.panel-grid .g-start-md-9{grid-column-start:9}.panel-grid .g-start-md-10{grid-column-start:10}.panel-grid .g-start-md-11{grid-column-start:11}.panel-grid .g-start-md-12{grid-column-start:12}.panel-grid .g-start-md-13{grid-column-start:13}.panel-grid .g-start-md-14{grid-column-start:14}.panel-grid .g-start-md-15{grid-column-start:15}.panel-grid .g-start-md-16{grid-column-start:16}.panel-grid .g-start-md-17{grid-column-start:17}.panel-grid .g-start-md-18{grid-column-start:18}.panel-grid .g-start-md-19{grid-column-start:19}.panel-grid .g-start-md-20{grid-column-start:20}.panel-grid .g-start-md-21{grid-column-start:21}.panel-grid .g-start-md-22{grid-column-start:22}.panel-grid .g-start-md-23{grid-column-start:23}}@media(min-width: 992px){.panel-grid .g-col-lg-1{grid-column:auto/span 1}.panel-grid .g-col-lg-2{grid-column:auto/span 2}.panel-grid .g-col-lg-3{grid-column:auto/span 3}.panel-grid .g-col-lg-4{grid-column:auto/span 4}.panel-grid .g-col-lg-5{grid-column:auto/span 5}.panel-grid .g-col-lg-6{grid-column:auto/span 6}.panel-grid .g-col-lg-7{grid-column:auto/span 7}.panel-grid .g-col-lg-8{grid-column:auto/span 8}.panel-grid .g-col-lg-9{grid-column:auto/span 9}.panel-grid .g-col-lg-10{grid-column:auto/span 10}.panel-grid .g-col-lg-11{grid-column:auto/span 11}.panel-grid .g-col-lg-12{grid-column:auto/span 12}.panel-grid .g-col-lg-13{grid-column:auto/span 13}.panel-grid .g-col-lg-14{grid-column:auto/span 14}.panel-grid .g-col-lg-15{grid-column:auto/span 15}.panel-grid .g-col-lg-16{grid-column:auto/span 16}.panel-grid .g-col-lg-17{grid-column:auto/span 17}.panel-grid .g-col-lg-18{grid-column:auto/span 18}.panel-grid .g-col-lg-19{grid-column:auto/span 19}.panel-grid .g-col-lg-20{grid-column:auto/span 20}.panel-grid .g-col-lg-21{grid-column:auto/span 21}.panel-grid .g-col-lg-22{grid-column:auto/span 22}.panel-grid .g-col-lg-23{grid-column:auto/span 23}.panel-grid .g-col-lg-24{grid-column:auto/span 24}.panel-grid .g-start-lg-1{grid-column-start:1}.panel-grid .g-start-lg-2{grid-column-start:2}.panel-grid .g-start-lg-3{grid-column-start:3}.panel-grid .g-start-lg-4{grid-column-start:4}.panel-grid .g-start-lg-5{grid-column-start:5}.panel-grid .g-start-lg-6{grid-column-start:6}.panel-grid .g-start-lg-7{grid-column-start:7}.panel-grid .g-start-lg-8{grid-column-start:8}.panel-grid .g-start-lg-9{grid-column-start:9}.panel-grid .g-start-lg-10{grid-column-start:10}.panel-grid .g-start-lg-11{grid-column-start:11}.panel-grid .g-start-lg-12{grid-column-start:12}.panel-grid .g-start-lg-13{grid-column-start:13}.panel-grid .g-start-lg-14{grid-column-start:14}.panel-grid .g-start-lg-15{grid-column-start:15}.panel-grid .g-start-lg-16{grid-column-start:16}.panel-grid .g-start-lg-17{grid-column-start:17}.panel-grid .g-start-lg-18{grid-column-start:18}.panel-grid .g-start-lg-19{grid-column-start:19}.panel-grid .g-start-lg-20{grid-column-start:20}.panel-grid .g-start-lg-21{grid-column-start:21}.panel-grid .g-start-lg-22{grid-column-start:22}.panel-grid .g-start-lg-23{grid-column-start:23}}@media(min-width: 1200px){.panel-grid .g-col-xl-1{grid-column:auto/span 1}.panel-grid .g-col-xl-2{grid-column:auto/span 2}.panel-grid .g-col-xl-3{grid-column:auto/span 3}.panel-grid .g-col-xl-4{grid-column:auto/span 4}.panel-grid .g-col-xl-5{grid-column:auto/span 5}.panel-grid .g-col-xl-6{grid-column:auto/span 6}.panel-grid .g-col-xl-7{grid-column:auto/span 7}.panel-grid .g-col-xl-8{grid-column:auto/span 8}.panel-grid .g-col-xl-9{grid-column:auto/span 9}.panel-grid .g-col-xl-10{grid-column:auto/span 10}.panel-grid .g-col-xl-11{grid-column:auto/span 11}.panel-grid .g-col-xl-12{grid-column:auto/span 12}.panel-grid .g-col-xl-13{grid-column:auto/span 13}.panel-grid .g-col-xl-14{grid-column:auto/span 14}.panel-grid .g-col-xl-15{grid-column:auto/span 15}.panel-grid .g-col-xl-16{grid-column:auto/span 16}.panel-grid .g-col-xl-17{grid-column:auto/span 17}.panel-grid .g-col-xl-18{grid-column:auto/span 18}.panel-grid .g-col-xl-19{grid-column:auto/span 19}.panel-grid .g-col-xl-20{grid-column:auto/span 20}.panel-grid .g-col-xl-21{grid-column:auto/span 21}.panel-grid .g-col-xl-22{grid-column:auto/span 22}.panel-grid .g-col-xl-23{grid-column:auto/span 23}.panel-grid .g-col-xl-24{grid-column:auto/span 24}.panel-grid .g-start-xl-1{grid-column-start:1}.panel-grid .g-start-xl-2{grid-column-start:2}.panel-grid .g-start-xl-3{grid-column-start:3}.panel-grid .g-start-xl-4{grid-column-start:4}.panel-grid .g-start-xl-5{grid-column-start:5}.panel-grid .g-start-xl-6{grid-column-start:6}.panel-grid .g-start-xl-7{grid-column-start:7}.panel-grid .g-start-xl-8{grid-column-start:8}.panel-grid .g-start-xl-9{grid-column-start:9}.panel-grid .g-start-xl-10{grid-column-start:10}.panel-grid .g-start-xl-11{grid-column-start:11}.panel-grid .g-start-xl-12{grid-column-start:12}.panel-grid .g-start-xl-13{grid-column-start:13}.panel-grid .g-start-xl-14{grid-column-start:14}.panel-grid .g-start-xl-15{grid-column-start:15}.panel-grid .g-start-xl-16{grid-column-start:16}.panel-grid .g-start-xl-17{grid-column-start:17}.panel-grid .g-start-xl-18{grid-column-start:18}.panel-grid .g-start-xl-19{grid-column-start:19}.panel-grid .g-start-xl-20{grid-column-start:20}.panel-grid .g-start-xl-21{grid-column-start:21}.panel-grid .g-start-xl-22{grid-column-start:22}.panel-grid .g-start-xl-23{grid-column-start:23}}@media(min-width: 1400px){.panel-grid .g-col-xxl-1{grid-column:auto/span 1}.panel-grid .g-col-xxl-2{grid-column:auto/span 2}.panel-grid .g-col-xxl-3{grid-column:auto/span 3}.panel-grid .g-col-xxl-4{grid-column:auto/span 4}.panel-grid .g-col-xxl-5{grid-column:auto/span 5}.panel-grid .g-col-xxl-6{grid-column:auto/span 6}.panel-grid .g-col-xxl-7{grid-column:auto/span 7}.panel-grid .g-col-xxl-8{grid-column:auto/span 8}.panel-grid .g-col-xxl-9{grid-column:auto/span 9}.panel-grid .g-col-xxl-10{grid-column:auto/span 10}.panel-grid .g-col-xxl-11{grid-column:auto/span 11}.panel-grid .g-col-xxl-12{grid-column:auto/span 12}.panel-grid .g-col-xxl-13{grid-column:auto/span 13}.panel-grid .g-col-xxl-14{grid-column:auto/span 14}.panel-grid .g-col-xxl-15{grid-column:auto/span 15}.panel-grid .g-col-xxl-16{grid-column:auto/span 16}.panel-grid .g-col-xxl-17{grid-column:auto/span 17}.panel-grid .g-col-xxl-18{grid-column:auto/span 18}.panel-grid .g-col-xxl-19{grid-column:auto/span 19}.panel-grid .g-col-xxl-20{grid-column:auto/span 20}.panel-grid .g-col-xxl-21{grid-column:auto/span 21}.panel-grid .g-col-xxl-22{grid-column:auto/span 22}.panel-grid .g-col-xxl-23{grid-column:auto/span 23}.panel-grid .g-col-xxl-24{grid-column:auto/span 24}.panel-grid .g-start-xxl-1{grid-column-start:1}.panel-grid .g-start-xxl-2{grid-column-start:2}.panel-grid .g-start-xxl-3{grid-column-start:3}.panel-grid .g-start-xxl-4{grid-column-start:4}.panel-grid .g-start-xxl-5{grid-column-start:5}.panel-grid .g-start-xxl-6{grid-column-start:6}.panel-grid .g-start-xxl-7{grid-column-start:7}.panel-grid .g-start-xxl-8{grid-column-start:8}.panel-grid .g-start-xxl-9{grid-column-start:9}.panel-grid .g-start-xxl-10{grid-column-start:10}.panel-grid .g-start-xxl-11{grid-column-start:11}.panel-grid .g-start-xxl-12{grid-column-start:12}.panel-grid .g-start-xxl-13{grid-column-start:13}.panel-grid .g-start-xxl-14{grid-column-start:14}.panel-grid .g-start-xxl-15{grid-column-start:15}.panel-grid .g-start-xxl-16{grid-column-start:16}.panel-grid .g-start-xxl-17{grid-column-start:17}.panel-grid .g-start-xxl-18{grid-column-start:18}.panel-grid .g-start-xxl-19{grid-column-start:19}.panel-grid .g-start-xxl-20{grid-column-start:20}.panel-grid .g-start-xxl-21{grid-column-start:21}.panel-grid .g-start-xxl-22{grid-column-start:22}.panel-grid .g-start-xxl-23{grid-column-start:23}}main{margin-top:1em;margin-bottom:1em}h1,.h1,h2,.h2{color:inherit;margin-top:2rem;margin-bottom:1rem;font-weight:600}h1.title,.title.h1{margin-top:0}main.content>section:first-of-type>h2:first-child,main.content>section:first-of-type>.h2:first-child{margin-top:0}h2,.h2{border-bottom:1px solid #dee2e6;padding-bottom:.5rem}h3,.h3{font-weight:600}h3,.h3,h4,.h4{opacity:.9;margin-top:1.5rem}h5,.h5,h6,.h6{opacity:.9}.header-section-number{color:#5a6570}.nav-link.active .header-section-number{color:inherit}mark,.mark{padding:0em}.panel-caption,.figure-caption,.subfigure-caption,.table-caption,figcaption,caption{font-size:.9rem;color:#5a6570}.quarto-layout-cell[data-ref-parent] caption{color:#5a6570}.column-margin figcaption,.margin-caption,div.aside,aside,.column-margin{color:#5a6570;font-size:.825rem}.panel-caption.margin-caption{text-align:inherit}.column-margin.column-container p{margin-bottom:0}.column-margin.column-container>*:not(.collapse):first-child{padding-bottom:.5em;display:block}.column-margin.column-container>*:not(.collapse):not(:first-child){padding-top:.5em;padding-bottom:.5em;display:block}.column-margin.column-container>*.collapse:not(.show){display:none}@media(min-width: 768px){.column-margin.column-container .callout-margin-content:first-child{margin-top:4.5em}.column-margin.column-container .callout-margin-content-simple:first-child{margin-top:3.5em}}.margin-caption>*{padding-top:.5em;padding-bottom:.5em}@media(max-width: 767.98px){.quarto-layout-row{flex-direction:column}}.nav-tabs .nav-item{margin-top:1px;cursor:pointer}.tab-content{margin-top:0px;border-left:#dee2e6 1px solid;border-right:#dee2e6 1px solid;border-bottom:#dee2e6 1px solid;margin-left:0;padding:1em;margin-bottom:1em}@media(max-width: 767.98px){.layout-sidebar{margin-left:0;margin-right:0}}.panel-sidebar,.panel-sidebar .form-control,.panel-input,.panel-input .form-control,.selectize-dropdown{font-size:.9rem}.panel-sidebar .form-control,.panel-input .form-control{padding-top:.1rem}.tab-pane div.sourceCode{margin-top:0px}.tab-pane>p{padding-top:0}.tab-pane>p:nth-child(1){padding-top:0}.tab-pane>p:last-child{margin-bottom:0}.tab-pane>pre:last-child{margin-bottom:0}.tab-content>.tab-pane:not(.active){display:none !important}div.sourceCode{background-color:rgba(233,236,239,.65);border:1px solid rgba(233,236,239,.65);border-radius:.375rem}pre.sourceCode{background-color:rgba(0,0,0,0)}pre.sourceCode{border:none;font-size:.875em;overflow:visible !important;padding:.4em}.callout pre.sourceCode{padding-left:0}div.sourceCode{overflow-y:hidden}.callout div.sourceCode{margin-left:initial}.blockquote{font-size:inherit;padding-left:1rem;padding-right:1.5rem;color:#5a6570}.blockquote h1:first-child,.blockquote .h1:first-child,.blockquote h2:first-child,.blockquote .h2:first-child,.blockquote h3:first-child,.blockquote .h3:first-child,.blockquote h4:first-child,.blockquote .h4:first-child,.blockquote h5:first-child,.blockquote .h5:first-child{margin-top:0}pre{background-color:initial;padding:initial;border:initial}p pre code:not(.sourceCode),li pre code:not(.sourceCode),pre code:not(.sourceCode){background-color:initial}p code:not(.sourceCode),li code:not(.sourceCode),td code:not(.sourceCode){background-color:#f8f9fa;padding:.2em}nav p code:not(.sourceCode),nav li code:not(.sourceCode),nav td code:not(.sourceCode){background-color:rgba(0,0,0,0);padding:0}td code:not(.sourceCode){white-space:pre-wrap}#quarto-embedded-source-code-modal>.modal-dialog{max-width:1000px;padding-left:1.75rem;padding-right:1.75rem}#quarto-embedded-source-code-modal>.modal-dialog>.modal-content>.modal-body{padding:0}#quarto-embedded-source-code-modal>.modal-dialog>.modal-content>.modal-body div.sourceCode{margin:0;padding:.2rem .2rem;border-radius:0px;border:none}#quarto-embedded-source-code-modal>.modal-dialog>.modal-content>.modal-header{padding:.7rem}.code-tools-button{font-size:1rem;padding:.15rem .15rem;margin-left:5px;color:rgba(33,37,41,.75);background-color:rgba(0,0,0,0);transition:initial;cursor:pointer}.code-tools-button>.bi::before{display:inline-block;height:1rem;width:1rem;content:"";vertical-align:-0.125em;background-image:url('data:image/svg+xml,');background-repeat:no-repeat;background-size:1rem 1rem}.code-tools-button:hover>.bi::before{background-image:url('data:image/svg+xml,')}#quarto-embedded-source-code-modal .code-copy-button>.bi::before{background-image:url('data:image/svg+xml,')}#quarto-embedded-source-code-modal .code-copy-button-checked>.bi::before{background-image:url('data:image/svg+xml,')}.sidebar{will-change:top;transition:top 200ms linear;position:sticky;overflow-y:auto;padding-top:1.2em;max-height:100vh}.sidebar.toc-left,.sidebar.margin-sidebar{top:0px;padding-top:1em}.sidebar.quarto-banner-title-block-sidebar>*{padding-top:1.65em}figure .quarto-notebook-link{margin-top:.5em}.quarto-notebook-link{font-size:.75em;color:rgba(33,37,41,.75);margin-bottom:1em;text-decoration:none;display:block}.quarto-notebook-link:hover{text-decoration:underline;color:#0d6efd}.quarto-notebook-link::before{display:inline-block;height:.75rem;width:.75rem;margin-bottom:0em;margin-right:.25em;content:"";vertical-align:-0.125em;background-image:url('data:image/svg+xml,');background-repeat:no-repeat;background-size:.75rem .75rem}.toc-actions i.bi,.quarto-code-links i.bi,.quarto-other-links i.bi,.quarto-alternate-notebooks i.bi,.quarto-alternate-formats i.bi{margin-right:.4em;font-size:.8rem}.quarto-other-links-text-target .quarto-code-links i.bi,.quarto-other-links-text-target .quarto-other-links i.bi{margin-right:.2em}.quarto-other-formats-text-target .quarto-alternate-formats i.bi{margin-right:.1em}.toc-actions i.bi.empty,.quarto-code-links i.bi.empty,.quarto-other-links i.bi.empty,.quarto-alternate-notebooks i.bi.empty,.quarto-alternate-formats i.bi.empty{padding-left:1em}.quarto-notebook h2,.quarto-notebook .h2{border-bottom:none}.quarto-notebook .cell-container{display:flex}.quarto-notebook .cell-container .cell{flex-grow:4}.quarto-notebook .cell-container .cell-decorator{padding-top:1.5em;padding-right:1em;text-align:right}.quarto-notebook .cell-container.code-fold .cell-decorator{padding-top:3em}.quarto-notebook .cell-code code{white-space:pre-wrap}.quarto-notebook .cell .cell-output-stderr pre code,.quarto-notebook .cell .cell-output-stdout pre code{white-space:pre-wrap;overflow-wrap:anywhere}.toc-actions,.quarto-alternate-formats,.quarto-other-links,.quarto-code-links,.quarto-alternate-notebooks{padding-left:0em}.sidebar .toc-actions a,.sidebar .quarto-alternate-formats a,.sidebar .quarto-other-links a,.sidebar .quarto-code-links a,.sidebar .quarto-alternate-notebooks a,.sidebar nav[role=doc-toc] a{text-decoration:none}.sidebar .toc-actions a:hover,.sidebar .quarto-other-links a:hover,.sidebar .quarto-code-links a:hover,.sidebar .quarto-alternate-formats a:hover,.sidebar .quarto-alternate-notebooks a:hover{color:#0d6efd}.sidebar .toc-actions h2,.sidebar .toc-actions .h2,.sidebar .quarto-code-links h2,.sidebar .quarto-code-links .h2,.sidebar .quarto-other-links h2,.sidebar .quarto-other-links .h2,.sidebar .quarto-alternate-notebooks h2,.sidebar .quarto-alternate-notebooks .h2,.sidebar .quarto-alternate-formats h2,.sidebar .quarto-alternate-formats .h2,.sidebar nav[role=doc-toc]>h2,.sidebar nav[role=doc-toc]>.h2{font-weight:500;margin-bottom:.2rem;margin-top:.3rem;font-family:inherit;border-bottom:0;padding-bottom:0;padding-top:0px}.sidebar .toc-actions>h2,.sidebar .toc-actions>.h2,.sidebar .quarto-code-links>h2,.sidebar .quarto-code-links>.h2,.sidebar .quarto-other-links>h2,.sidebar .quarto-other-links>.h2,.sidebar .quarto-alternate-notebooks>h2,.sidebar .quarto-alternate-notebooks>.h2,.sidebar .quarto-alternate-formats>h2,.sidebar .quarto-alternate-formats>.h2{font-size:.8rem}.sidebar nav[role=doc-toc]>h2,.sidebar nav[role=doc-toc]>.h2{font-size:.875rem}.sidebar nav[role=doc-toc]>ul a{border-left:1px solid #e9ecef;padding-left:.6rem}.sidebar .toc-actions h2>ul a,.sidebar .toc-actions .h2>ul a,.sidebar .quarto-code-links h2>ul a,.sidebar .quarto-code-links .h2>ul a,.sidebar .quarto-other-links h2>ul a,.sidebar .quarto-other-links .h2>ul a,.sidebar .quarto-alternate-notebooks h2>ul a,.sidebar .quarto-alternate-notebooks .h2>ul a,.sidebar .quarto-alternate-formats h2>ul a,.sidebar .quarto-alternate-formats .h2>ul a{border-left:none;padding-left:.6rem}.sidebar .toc-actions ul a:empty,.sidebar .quarto-code-links ul a:empty,.sidebar .quarto-other-links ul a:empty,.sidebar .quarto-alternate-notebooks ul a:empty,.sidebar .quarto-alternate-formats ul a:empty,.sidebar nav[role=doc-toc]>ul a:empty{display:none}.sidebar .toc-actions ul,.sidebar .quarto-code-links ul,.sidebar .quarto-other-links ul,.sidebar .quarto-alternate-notebooks ul,.sidebar .quarto-alternate-formats ul{padding-left:0;list-style:none}.sidebar nav[role=doc-toc] ul{list-style:none;padding-left:0;list-style:none}.sidebar nav[role=doc-toc]>ul{margin-left:.45em}.quarto-margin-sidebar nav[role=doc-toc]{padding-left:.5em}.sidebar .toc-actions>ul,.sidebar .quarto-code-links>ul,.sidebar .quarto-other-links>ul,.sidebar .quarto-alternate-notebooks>ul,.sidebar .quarto-alternate-formats>ul{font-size:.8rem}.sidebar nav[role=doc-toc]>ul{font-size:.875rem}.sidebar .toc-actions ul li a,.sidebar .quarto-code-links ul li a,.sidebar .quarto-other-links ul li a,.sidebar .quarto-alternate-notebooks ul li a,.sidebar .quarto-alternate-formats ul li a,.sidebar nav[role=doc-toc]>ul li a{line-height:1.1rem;padding-bottom:.2rem;padding-top:.2rem;color:inherit}.sidebar nav[role=doc-toc] ul>li>ul>li>a{padding-left:1.2em}.sidebar nav[role=doc-toc] ul>li>ul>li>ul>li>a{padding-left:2.4em}.sidebar nav[role=doc-toc] ul>li>ul>li>ul>li>ul>li>a{padding-left:3.6em}.sidebar nav[role=doc-toc] ul>li>ul>li>ul>li>ul>li>ul>li>a{padding-left:4.8em}.sidebar nav[role=doc-toc] ul>li>ul>li>ul>li>ul>li>ul>li>ul>li>a{padding-left:6em}.sidebar nav[role=doc-toc] ul>li>a.active,.sidebar nav[role=doc-toc] ul>li>ul>li>a.active{border-left:1px solid #0d6efd;color:#0d6efd !important}.sidebar nav[role=doc-toc] ul>li>a:hover,.sidebar nav[role=doc-toc] ul>li>ul>li>a:hover{color:#0d6efd !important}kbd,.kbd{color:#212529;background-color:#f8f9fa;border:1px solid;border-radius:5px;border-color:#dee2e6}.quarto-appendix-contents div.hanging-indent{margin-left:0em}.quarto-appendix-contents div.hanging-indent div.csl-entry{margin-left:1em;text-indent:-1em}.citation a,.footnote-ref{text-decoration:none}.footnotes ol{padding-left:1em}.tippy-content>*{margin-bottom:.7em}.tippy-content>*:last-child{margin-bottom:0}.callout{margin-top:1.25rem;margin-bottom:1.25rem;border-radius:.375rem;overflow-wrap:break-word}.callout .callout-title-container{overflow-wrap:anywhere}.callout.callout-style-simple{padding:.4em .7em;border-left:5px solid;border-right:1px solid #dee2e6;border-top:1px solid #dee2e6;border-bottom:1px solid #dee2e6}.callout.callout-style-default{border-left:5px solid;border-right:1px solid #dee2e6;border-top:1px solid #dee2e6;border-bottom:1px solid #dee2e6}.callout .callout-body-container{flex-grow:1}.callout.callout-style-simple .callout-body{font-size:.9rem;font-weight:400}.callout.callout-style-default .callout-body{font-size:.9rem;font-weight:400}.callout:not(.no-icon).callout-titled.callout-style-simple .callout-body{padding-left:1.6em}.callout.callout-titled>.callout-header{padding-top:.2em;margin-bottom:-0.2em}.callout.callout-style-simple>div.callout-header{border-bottom:none;font-size:.9rem;font-weight:600;opacity:75%}.callout.callout-style-default>div.callout-header{border-bottom:none;font-weight:600;opacity:85%;font-size:.9rem;padding-left:.5em;padding-right:.5em}.callout.callout-style-default .callout-body{padding-left:.5em;padding-right:.5em}.callout.callout-style-default .callout-body>:first-child{padding-top:.5rem;margin-top:0}.callout>div.callout-header[data-bs-toggle=collapse]{cursor:pointer}.callout.callout-style-default .callout-header[aria-expanded=false],.callout.callout-style-default .callout-header[aria-expanded=true]{padding-top:0px;margin-bottom:0px;align-items:center}.callout.callout-titled .callout-body>:last-child:not(.sourceCode),.callout.callout-titled .callout-body>div>:last-child:not(.sourceCode){padding-bottom:.5rem;margin-bottom:0}.callout:not(.callout-titled) .callout-body>:first-child,.callout:not(.callout-titled) .callout-body>div>:first-child{margin-top:.25rem}.callout:not(.callout-titled) .callout-body>:last-child,.callout:not(.callout-titled) .callout-body>div>:last-child{margin-bottom:.2rem}.callout.callout-style-simple .callout-icon::before,.callout.callout-style-simple .callout-toggle::before{height:1rem;width:1rem;display:inline-block;content:"";background-repeat:no-repeat;background-size:1rem 1rem}.callout.callout-style-default .callout-icon::before,.callout.callout-style-default .callout-toggle::before{height:.9rem;width:.9rem;display:inline-block;content:"";background-repeat:no-repeat;background-size:.9rem .9rem}.callout.callout-style-default .callout-toggle::before{margin-top:5px}.callout .callout-btn-toggle .callout-toggle::before{transition:transform .2s linear}.callout .callout-header[aria-expanded=false] .callout-toggle::before{transform:rotate(-90deg)}.callout .callout-header[aria-expanded=true] .callout-toggle::before{transform:none}.callout.callout-style-simple:not(.no-icon) div.callout-icon-container{padding-top:.2em;padding-right:.55em}.callout.callout-style-default:not(.no-icon) div.callout-icon-container{padding-top:.1em;padding-right:.35em}.callout.callout-style-default:not(.no-icon) div.callout-title-container{margin-top:-1px}.callout.callout-style-default.callout-caution:not(.no-icon) div.callout-icon-container{padding-top:.3em;padding-right:.35em}.callout>.callout-body>.callout-icon-container>.no-icon,.callout>.callout-header>.callout-icon-container>.no-icon{display:none}div.callout.callout{border-left-color:rgba(33,37,41,.75)}div.callout.callout-style-default>.callout-header{background-color:rgba(33,37,41,.75)}div.callout-note.callout{border-left-color:#0d6efd}div.callout-note.callout-style-default>.callout-header{background-color:#e7f1ff}div.callout-note:not(.callout-titled) .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-note.callout-titled .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-note .callout-toggle::before{background-image:url('data:image/svg+xml,')}div.callout-tip.callout{border-left-color:#198754}div.callout-tip.callout-style-default>.callout-header{background-color:#e8f3ee}div.callout-tip:not(.callout-titled) .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-tip.callout-titled .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-tip .callout-toggle::before{background-image:url('data:image/svg+xml,')}div.callout-warning.callout{border-left-color:#ffc107}div.callout-warning.callout-style-default>.callout-header{background-color:#fff9e6}div.callout-warning:not(.callout-titled) .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-warning.callout-titled .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-warning .callout-toggle::before{background-image:url('data:image/svg+xml,')}div.callout-caution.callout{border-left-color:#fd7e14}div.callout-caution.callout-style-default>.callout-header{background-color:#fff2e8}div.callout-caution:not(.callout-titled) .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-caution.callout-titled .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-caution .callout-toggle::before{background-image:url('data:image/svg+xml,')}div.callout-important.callout{border-left-color:#dc3545}div.callout-important.callout-style-default>.callout-header{background-color:#fcebec}div.callout-important:not(.callout-titled) .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-important.callout-titled .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-important .callout-toggle::before{background-image:url('data:image/svg+xml,')}.quarto-toggle-container{display:flex;align-items:center}.quarto-reader-toggle .bi::before,.quarto-color-scheme-toggle .bi::before{display:inline-block;height:1rem;width:1rem;content:"";background-repeat:no-repeat;background-size:1rem 1rem}.sidebar-navigation{padding-left:20px}.navbar{background-color:#517699;color:#fdfefe}.navbar .quarto-color-scheme-toggle:not(.alternate) .bi::before{background-image:url('data:image/svg+xml,')}.navbar .quarto-color-scheme-toggle.alternate .bi::before{background-image:url('data:image/svg+xml,')}.sidebar-navigation .quarto-color-scheme-toggle:not(.alternate) .bi::before{background-image:url('data:image/svg+xml,')}.sidebar-navigation .quarto-color-scheme-toggle.alternate .bi::before{background-image:url('data:image/svg+xml,')}.quarto-sidebar-toggle{border-color:#dee2e6;border-bottom-left-radius:.375rem;border-bottom-right-radius:.375rem;border-style:solid;border-width:1px;overflow:hidden;border-top-width:0px;padding-top:0px !important}.quarto-sidebar-toggle-title{cursor:pointer;padding-bottom:2px;margin-left:.25em;text-align:center;font-weight:400;font-size:.775em}#quarto-content .quarto-sidebar-toggle{background:#fafafa}#quarto-content .quarto-sidebar-toggle-title{color:#212529}.quarto-sidebar-toggle-icon{color:#dee2e6;margin-right:.5em;float:right;transition:transform .2s ease}.quarto-sidebar-toggle-icon::before{padding-top:5px}.quarto-sidebar-toggle.expanded .quarto-sidebar-toggle-icon{transform:rotate(-180deg)}.quarto-sidebar-toggle.expanded .quarto-sidebar-toggle-title{border-bottom:solid #dee2e6 1px}.quarto-sidebar-toggle-contents{background-color:#fff;padding-right:10px;padding-left:10px;margin-top:0px !important;transition:max-height .5s ease}.quarto-sidebar-toggle.expanded .quarto-sidebar-toggle-contents{padding-top:1em;padding-bottom:10px}@media(max-width: 767.98px){.sidebar-menu-container{padding-bottom:5em}}.quarto-sidebar-toggle:not(.expanded) .quarto-sidebar-toggle-contents{padding-top:0px !important;padding-bottom:0px}nav[role=doc-toc]{z-index:1020}#quarto-sidebar>*,nav[role=doc-toc]>*{transition:opacity .1s ease,border .1s ease}#quarto-sidebar.slow>*,nav[role=doc-toc].slow>*{transition:opacity .4s ease,border .4s ease}.quarto-color-scheme-toggle:not(.alternate).top-right .bi::before{background-image:url('data:image/svg+xml,')}.quarto-color-scheme-toggle.alternate.top-right .bi::before{background-image:url('data:image/svg+xml,')}#quarto-appendix.default{border-top:1px solid #dee2e6}#quarto-appendix.default{background-color:#fff;padding-top:1.5em;margin-top:2em;z-index:998}#quarto-appendix.default .quarto-appendix-heading{margin-top:0;line-height:1.4em;font-weight:600;opacity:.9;border-bottom:none;margin-bottom:0}#quarto-appendix.default .footnotes ol,#quarto-appendix.default .footnotes ol li>p:last-of-type,#quarto-appendix.default .quarto-appendix-contents>p:last-of-type{margin-bottom:0}#quarto-appendix.default .footnotes ol{margin-left:.5em}#quarto-appendix.default .quarto-appendix-secondary-label{margin-bottom:.4em}#quarto-appendix.default .quarto-appendix-bibtex{font-size:.7em;padding:1em;border:solid 1px #dee2e6;margin-bottom:1em}#quarto-appendix.default .quarto-appendix-bibtex code.sourceCode{white-space:pre-wrap}#quarto-appendix.default .quarto-appendix-citeas{font-size:.9em;padding:1em;border:solid 1px #dee2e6;margin-bottom:1em}#quarto-appendix.default .quarto-appendix-heading{font-size:1em !important}#quarto-appendix.default *[role=doc-endnotes]>ol,#quarto-appendix.default .quarto-appendix-contents>*:not(h2):not(.h2){font-size:.9em}#quarto-appendix.default section{padding-bottom:1.5em}#quarto-appendix.default section *[role=doc-endnotes],#quarto-appendix.default section>*:not(a){opacity:.9;word-wrap:break-word}.btn.btn-quarto,div.cell-output-display .btn-quarto{--bs-btn-color: #fefefe;--bs-btn-bg: #6c757d;--bs-btn-border-color: #6c757d;--bs-btn-hover-color: #fefefe;--bs-btn-hover-bg: #828a91;--bs-btn-hover-border-color: #7b838a;--bs-btn-focus-shadow-rgb: 130, 138, 144;--bs-btn-active-color: #000;--bs-btn-active-bg: #899197;--bs-btn-active-border-color: #7b838a;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #ffffff;--bs-btn-disabled-bg: #6c757d;--bs-btn-disabled-border-color: #6c757d}nav.quarto-secondary-nav.color-navbar{background-color:#517699;color:#fdfefe}nav.quarto-secondary-nav.color-navbar h1,nav.quarto-secondary-nav.color-navbar .h1,nav.quarto-secondary-nav.color-navbar .quarto-btn-toggle{color:#fdfefe}@media(max-width: 991.98px){body.nav-sidebar .quarto-title-banner{margin-bottom:0;padding-bottom:1em}body.nav-sidebar #title-block-header{margin-block-end:0}}p.subtitle{margin-top:.25em;margin-bottom:.5em}code a:any-link{color:inherit;text-decoration-color:#6c757d}/*! light */div.observablehq table thead tr th{background-color:var(--bs-body-bg)}input,button,select,optgroup,textarea{background-color:var(--bs-body-bg)}.code-annotated .code-copy-button{margin-right:1.25em;margin-top:0;padding-bottom:0;padding-top:3px}.code-annotation-gutter-bg{background-color:#fff}.code-annotation-gutter{background-color:rgba(233,236,239,.65)}.code-annotation-gutter,.code-annotation-gutter-bg{height:100%;width:calc(20px + .5em);position:absolute;top:0;right:0}dl.code-annotation-container-grid dt{margin-right:1em;margin-top:.25rem}dl.code-annotation-container-grid dt{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;color:#383f45;border:solid #383f45 1px;border-radius:50%;height:22px;width:22px;line-height:22px;font-size:11px;text-align:center;vertical-align:middle;text-decoration:none}dl.code-annotation-container-grid dt[data-target-cell]{cursor:pointer}dl.code-annotation-container-grid dt[data-target-cell].code-annotation-active{color:#fff;border:solid #aaa 1px;background-color:#aaa}pre.code-annotation-code{padding-top:0;padding-bottom:0}pre.code-annotation-code code{z-index:3}#code-annotation-line-highlight-gutter{width:100%;border-top:solid rgba(170,170,170,.2666666667) 1px;border-bottom:solid rgba(170,170,170,.2666666667) 1px;z-index:2;background-color:rgba(170,170,170,.1333333333)}#code-annotation-line-highlight{margin-left:-4em;width:calc(100% + 4em);border-top:solid rgba(170,170,170,.2666666667) 1px;border-bottom:solid rgba(170,170,170,.2666666667) 1px;z-index:2;background-color:rgba(170,170,170,.1333333333)}code.sourceCode .code-annotation-anchor.code-annotation-active{background-color:var(--quarto-hl-normal-color, #aaaaaa);border:solid var(--quarto-hl-normal-color, #aaaaaa) 1px;color:#e9ecef;font-weight:bolder}code.sourceCode .code-annotation-anchor{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;color:var(--quarto-hl-co-color);border:solid var(--quarto-hl-co-color) 1px;border-radius:50%;height:18px;width:18px;font-size:9px;margin-top:2px}code.sourceCode button.code-annotation-anchor{padding:2px;user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none}code.sourceCode a.code-annotation-anchor{line-height:18px;text-align:center;vertical-align:middle;cursor:default;text-decoration:none}@media print{.page-columns .column-screen-inset{grid-column:page-start-inset/page-end-inset;z-index:998;opacity:.999}.page-columns .column-screen-inset table{background:#fff}.page-columns .column-screen-inset-left{grid-column:page-start-inset/body-content-end;z-index:998;opacity:.999}.page-columns .column-screen-inset-left table{background:#fff}.page-columns .column-screen-inset-right{grid-column:body-content-start/page-end-inset;z-index:998;opacity:.999}.page-columns .column-screen-inset-right table{background:#fff}.page-columns .column-screen{grid-column:page-start/page-end;z-index:998;opacity:.999}.page-columns .column-screen table{background:#fff}.page-columns .column-screen-left{grid-column:page-start/body-content-end;z-index:998;opacity:.999}.page-columns .column-screen-left table{background:#fff}.page-columns .column-screen-right{grid-column:body-content-start/page-end;z-index:998;opacity:.999}.page-columns .column-screen-right table{background:#fff}.page-columns .column-screen-inset-shaded{grid-column:page-start-inset/page-end-inset;padding:1em;background:#f8f9fa;z-index:998;opacity:.999;margin-bottom:1em}}.quarto-video{margin-bottom:1em}.table{border-top:1px solid #d3d8dc;border-bottom:1px solid #d3d8dc}.table>thead{border-top-width:0;border-bottom:1px solid #9ba5ae}.table a{word-break:break-word}.table>:not(caption)>*>*{background-color:unset;color:unset}#quarto-document-content .crosstalk-input .checkbox input[type=checkbox],#quarto-document-content .crosstalk-input .checkbox-inline input[type=checkbox]{position:unset;margin-top:unset;margin-left:unset}#quarto-document-content .row{margin-left:unset;margin-right:unset}.quarto-xref{white-space:nowrap}#quarto-draft-alert{margin-top:0px;margin-bottom:0px;padding:.3em;text-align:center;font-size:.9em}#quarto-draft-alert i{margin-right:.3em}a.external:after{content:"";background-image:url('data:image/svg+xml,');background-size:contain;background-repeat:no-repeat;background-position:center center;margin-left:.2em;padding-right:.75em}div.sourceCode code a.external:after{content:none}a.external:after:hover{cursor:pointer}.quarto-ext-icon{display:inline-block;font-size:.75em;padding-left:.3em}.code-with-filename .code-with-filename-file{margin-bottom:0;padding-bottom:2px;padding-top:2px;padding-left:.7em;border:var(--quarto-border-width) solid var(--quarto-border-color);border-radius:var(--quarto-border-radius);border-bottom:0;border-bottom-left-radius:0%;border-bottom-right-radius:0%}.code-with-filename div.sourceCode,.reveal .code-with-filename div.sourceCode{margin-top:0;border-top-left-radius:0%;border-top-right-radius:0%}.code-with-filename .code-with-filename-file pre{margin-bottom:0}.code-with-filename .code-with-filename-file{background-color:rgba(219,219,219,.8)}.quarto-dark .code-with-filename .code-with-filename-file{background-color:#555}.code-with-filename .code-with-filename-file strong{font-weight:400}.quarto-title-banner{margin-bottom:1em;color:#fdfefe;background:#517699}.quarto-title-banner a{color:#fdfefe}.quarto-title-banner h1,.quarto-title-banner .h1,.quarto-title-banner h2,.quarto-title-banner .h2{color:#fdfefe}.quarto-title-banner .code-tools-button{color:#b9dcdc}.quarto-title-banner .code-tools-button:hover{color:#fdfefe}.quarto-title-banner .code-tools-button>.bi::before{background-image:url('data:image/svg+xml,')}.quarto-title-banner .code-tools-button:hover>.bi::before{background-image:url('data:image/svg+xml,')}.quarto-title-banner .quarto-title .title{font-weight:600}.quarto-title-banner .quarto-categories{margin-top:.75em}@media(min-width: 992px){.quarto-title-banner{padding-top:2.5em;padding-bottom:2.5em}}@media(max-width: 991.98px){.quarto-title-banner{padding-top:1em;padding-bottom:1em}}@media(max-width: 767.98px){body.hypothesis-enabled #title-block-header>*{padding-right:20px}}main.quarto-banner-title-block>section:first-child>h2,main.quarto-banner-title-block>section:first-child>.h2,main.quarto-banner-title-block>section:first-child>h3,main.quarto-banner-title-block>section:first-child>.h3,main.quarto-banner-title-block>section:first-child>h4,main.quarto-banner-title-block>section:first-child>.h4{margin-top:0}.quarto-title .quarto-categories{display:flex;flex-wrap:wrap;row-gap:.5em;column-gap:.4em;padding-bottom:.5em;margin-top:.75em}.quarto-title .quarto-categories .quarto-category{padding:.25em .75em;font-size:.65em;text-transform:uppercase;border:solid 1px;border-radius:.375rem;opacity:.6}.quarto-title .quarto-categories .quarto-category a{color:inherit}.quarto-title-meta-container{display:grid;grid-template-columns:1fr auto}.quarto-title-meta-column-end{display:flex;flex-direction:column;padding-left:1em}.quarto-title-meta-column-end a .bi{margin-right:.3em}#title-block-header.quarto-title-block.default .quarto-title-meta{display:grid;grid-template-columns:repeat(2, 1fr);grid-column-gap:1em}#title-block-header.quarto-title-block.default .quarto-title .title{margin-bottom:0}#title-block-header.quarto-title-block.default .quarto-title-author-orcid img{margin-top:-0.2em;height:.8em;width:.8em}#title-block-header.quarto-title-block.default .quarto-title-author-email{opacity:.7}#title-block-header.quarto-title-block.default .quarto-description p:last-of-type{margin-bottom:0}#title-block-header.quarto-title-block.default .quarto-title-meta-contents p,#title-block-header.quarto-title-block.default .quarto-title-authors p,#title-block-header.quarto-title-block.default .quarto-title-affiliations p{margin-bottom:.1em}#title-block-header.quarto-title-block.default .quarto-title-meta-heading{text-transform:uppercase;margin-top:1em;font-size:.8em;opacity:.8;font-weight:400}#title-block-header.quarto-title-block.default .quarto-title-meta-contents{font-size:.9em}#title-block-header.quarto-title-block.default .quarto-title-meta-contents p.affiliation:last-of-type{margin-bottom:.1em}#title-block-header.quarto-title-block.default p.affiliation{margin-bottom:.1em}#title-block-header.quarto-title-block.default .keywords,#title-block-header.quarto-title-block.default .description,#title-block-header.quarto-title-block.default .abstract{margin-top:0}#title-block-header.quarto-title-block.default .keywords>p,#title-block-header.quarto-title-block.default .description>p,#title-block-header.quarto-title-block.default .abstract>p{font-size:.9em}#title-block-header.quarto-title-block.default .keywords>p:last-of-type,#title-block-header.quarto-title-block.default .description>p:last-of-type,#title-block-header.quarto-title-block.default .abstract>p:last-of-type{margin-bottom:0}#title-block-header.quarto-title-block.default .keywords .block-title,#title-block-header.quarto-title-block.default .description .block-title,#title-block-header.quarto-title-block.default .abstract .block-title{margin-top:1em;text-transform:uppercase;font-size:.8em;opacity:.8;font-weight:400}#title-block-header.quarto-title-block.default .quarto-title-meta-author{display:grid;grid-template-columns:minmax(max-content, 1fr) 1fr;grid-column-gap:1em}.quarto-title-tools-only{display:flex;justify-content:right} diff --git a/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/run_pecan_files/libs/bootstrap/bootstrap.min.js b/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/run_pecan_files/libs/bootstrap/bootstrap.min.js deleted file mode 100644 index e8f21f703..000000000 --- a/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/run_pecan_files/libs/bootstrap/bootstrap.min.js +++ /dev/null @@ -1,7 +0,0 @@ -/*! - * Bootstrap v5.3.1 (https://getbootstrap.com/) - * Copyright 2011-2023 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) - */ -!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).bootstrap=e()}(this,(function(){"use strict";const t=new Map,e={set(e,i,n){t.has(e)||t.set(e,new Map);const s=t.get(e);s.has(i)||0===s.size?s.set(i,n):console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(s.keys())[0]}.`)},get:(e,i)=>t.has(e)&&t.get(e).get(i)||null,remove(e,i){if(!t.has(e))return;const n=t.get(e);n.delete(i),0===n.size&&t.delete(e)}},i="transitionend",n=t=>(t&&window.CSS&&window.CSS.escape&&(t=t.replace(/#([^\s"#']+)/g,((t,e)=>`#${CSS.escape(e)}`))),t),s=t=>{t.dispatchEvent(new Event(i))},o=t=>!(!t||"object"!=typeof t)&&(void 0!==t.jquery&&(t=t[0]),void 0!==t.nodeType),r=t=>o(t)?t.jquery?t[0]:t:"string"==typeof t&&t.length>0?document.querySelector(n(t)):null,a=t=>{if(!o(t)||0===t.getClientRects().length)return!1;const e="visible"===getComputedStyle(t).getPropertyValue("visibility"),i=t.closest("details:not([open])");if(!i)return e;if(i!==t){const e=t.closest("summary");if(e&&e.parentNode!==i)return!1;if(null===e)return!1}return e},l=t=>!t||t.nodeType!==Node.ELEMENT_NODE||!!t.classList.contains("disabled")||(void 0!==t.disabled?t.disabled:t.hasAttribute("disabled")&&"false"!==t.getAttribute("disabled")),c=t=>{if(!document.documentElement.attachShadow)return null;if("function"==typeof t.getRootNode){const e=t.getRootNode();return e instanceof ShadowRoot?e:null}return t instanceof ShadowRoot?t:t.parentNode?c(t.parentNode):null},h=()=>{},d=t=>{t.offsetHeight},u=()=>window.jQuery&&!document.body.hasAttribute("data-bs-no-jquery")?window.jQuery:null,f=[],p=()=>"rtl"===document.documentElement.dir,m=t=>{var e;e=()=>{const e=u();if(e){const i=t.NAME,n=e.fn[i];e.fn[i]=t.jQueryInterface,e.fn[i].Constructor=t,e.fn[i].noConflict=()=>(e.fn[i]=n,t.jQueryInterface)}},"loading"===document.readyState?(f.length||document.addEventListener("DOMContentLoaded",(()=>{for(const t of f)t()})),f.push(e)):e()},g=(t,e=[],i=t)=>"function"==typeof t?t(...e):i,_=(t,e,n=!0)=>{if(!n)return void g(t);const o=(t=>{if(!t)return 0;let{transitionDuration:e,transitionDelay:i}=window.getComputedStyle(t);const n=Number.parseFloat(e),s=Number.parseFloat(i);return n||s?(e=e.split(",")[0],i=i.split(",")[0],1e3*(Number.parseFloat(e)+Number.parseFloat(i))):0})(e)+5;let r=!1;const a=({target:n})=>{n===e&&(r=!0,e.removeEventListener(i,a),g(t))};e.addEventListener(i,a),setTimeout((()=>{r||s(e)}),o)},b=(t,e,i,n)=>{const s=t.length;let o=t.indexOf(e);return-1===o?!i&&n?t[s-1]:t[0]:(o+=i?1:-1,n&&(o=(o+s)%s),t[Math.max(0,Math.min(o,s-1))])},v=/[^.]*(?=\..*)\.|.*/,y=/\..*/,w=/::\d+$/,A={};let E=1;const T={mouseenter:"mouseover",mouseleave:"mouseout"},C=new Set(["click","dblclick","mouseup","mousedown","contextmenu","mousewheel","DOMMouseScroll","mouseover","mouseout","mousemove","selectstart","selectend","keydown","keypress","keyup","orientationchange","touchstart","touchmove","touchend","touchcancel","pointerdown","pointermove","pointerup","pointerleave","pointercancel","gesturestart","gesturechange","gestureend","focus","blur","change","reset","select","submit","focusin","focusout","load","unload","beforeunload","resize","move","DOMContentLoaded","readystatechange","error","abort","scroll"]);function O(t,e){return e&&`${e}::${E++}`||t.uidEvent||E++}function x(t){const e=O(t);return t.uidEvent=e,A[e]=A[e]||{},A[e]}function k(t,e,i=null){return Object.values(t).find((t=>t.callable===e&&t.delegationSelector===i))}function L(t,e,i){const n="string"==typeof e,s=n?i:e||i;let o=I(t);return C.has(o)||(o=t),[n,s,o]}function S(t,e,i,n,s){if("string"!=typeof e||!t)return;let[o,r,a]=L(e,i,n);if(e in T){const t=t=>function(e){if(!e.relatedTarget||e.relatedTarget!==e.delegateTarget&&!e.delegateTarget.contains(e.relatedTarget))return t.call(this,e)};r=t(r)}const l=x(t),c=l[a]||(l[a]={}),h=k(c,r,o?i:null);if(h)return void(h.oneOff=h.oneOff&&s);const d=O(r,e.replace(v,"")),u=o?function(t,e,i){return function n(s){const o=t.querySelectorAll(e);for(let{target:r}=s;r&&r!==this;r=r.parentNode)for(const a of o)if(a===r)return P(s,{delegateTarget:r}),n.oneOff&&N.off(t,s.type,e,i),i.apply(r,[s])}}(t,i,r):function(t,e){return function i(n){return P(n,{delegateTarget:t}),i.oneOff&&N.off(t,n.type,e),e.apply(t,[n])}}(t,r);u.delegationSelector=o?i:null,u.callable=r,u.oneOff=s,u.uidEvent=d,c[d]=u,t.addEventListener(a,u,o)}function D(t,e,i,n,s){const o=k(e[i],n,s);o&&(t.removeEventListener(i,o,Boolean(s)),delete e[i][o.uidEvent])}function $(t,e,i,n){const s=e[i]||{};for(const[o,r]of Object.entries(s))o.includes(n)&&D(t,e,i,r.callable,r.delegationSelector)}function I(t){return t=t.replace(y,""),T[t]||t}const N={on(t,e,i,n){S(t,e,i,n,!1)},one(t,e,i,n){S(t,e,i,n,!0)},off(t,e,i,n){if("string"!=typeof e||!t)return;const[s,o,r]=L(e,i,n),a=r!==e,l=x(t),c=l[r]||{},h=e.startsWith(".");if(void 0===o){if(h)for(const i of Object.keys(l))$(t,l,i,e.slice(1));for(const[i,n]of Object.entries(c)){const s=i.replace(w,"");a&&!e.includes(s)||D(t,l,r,n.callable,n.delegationSelector)}}else{if(!Object.keys(c).length)return;D(t,l,r,o,s?i:null)}},trigger(t,e,i){if("string"!=typeof e||!t)return null;const n=u();let s=null,o=!0,r=!0,a=!1;e!==I(e)&&n&&(s=n.Event(e,i),n(t).trigger(s),o=!s.isPropagationStopped(),r=!s.isImmediatePropagationStopped(),a=s.isDefaultPrevented());const l=P(new Event(e,{bubbles:o,cancelable:!0}),i);return a&&l.preventDefault(),r&&t.dispatchEvent(l),l.defaultPrevented&&s&&s.preventDefault(),l}};function P(t,e={}){for(const[i,n]of Object.entries(e))try{t[i]=n}catch(e){Object.defineProperty(t,i,{configurable:!0,get:()=>n})}return t}function M(t){if("true"===t)return!0;if("false"===t)return!1;if(t===Number(t).toString())return Number(t);if(""===t||"null"===t)return null;if("string"!=typeof t)return t;try{return JSON.parse(decodeURIComponent(t))}catch(e){return t}}function j(t){return t.replace(/[A-Z]/g,(t=>`-${t.toLowerCase()}`))}const F={setDataAttribute(t,e,i){t.setAttribute(`data-bs-${j(e)}`,i)},removeDataAttribute(t,e){t.removeAttribute(`data-bs-${j(e)}`)},getDataAttributes(t){if(!t)return{};const e={},i=Object.keys(t.dataset).filter((t=>t.startsWith("bs")&&!t.startsWith("bsConfig")));for(const n of i){let i=n.replace(/^bs/,"");i=i.charAt(0).toLowerCase()+i.slice(1,i.length),e[i]=M(t.dataset[n])}return e},getDataAttribute:(t,e)=>M(t.getAttribute(`data-bs-${j(e)}`))};class H{static get Default(){return{}}static get DefaultType(){return{}}static get NAME(){throw new Error('You have to implement the static method "NAME", for each component!')}_getConfig(t){return t=this._mergeConfigObj(t),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}_configAfterMerge(t){return t}_mergeConfigObj(t,e){const i=o(e)?F.getDataAttribute(e,"config"):{};return{...this.constructor.Default,..."object"==typeof i?i:{},...o(e)?F.getDataAttributes(e):{},..."object"==typeof t?t:{}}}_typeCheckConfig(t,e=this.constructor.DefaultType){for(const[n,s]of Object.entries(e)){const e=t[n],r=o(e)?"element":null==(i=e)?`${i}`:Object.prototype.toString.call(i).match(/\s([a-z]+)/i)[1].toLowerCase();if(!new RegExp(s).test(r))throw new TypeError(`${this.constructor.NAME.toUpperCase()}: Option "${n}" provided type "${r}" but expected type "${s}".`)}var i}}class W extends H{constructor(t,i){super(),(t=r(t))&&(this._element=t,this._config=this._getConfig(i),e.set(this._element,this.constructor.DATA_KEY,this))}dispose(){e.remove(this._element,this.constructor.DATA_KEY),N.off(this._element,this.constructor.EVENT_KEY);for(const t of Object.getOwnPropertyNames(this))this[t]=null}_queueCallback(t,e,i=!0){_(t,e,i)}_getConfig(t){return t=this._mergeConfigObj(t,this._element),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}static getInstance(t){return e.get(r(t),this.DATA_KEY)}static getOrCreateInstance(t,e={}){return this.getInstance(t)||new this(t,"object"==typeof e?e:null)}static get VERSION(){return"5.3.1"}static get DATA_KEY(){return`bs.${this.NAME}`}static get EVENT_KEY(){return`.${this.DATA_KEY}`}static eventName(t){return`${t}${this.EVENT_KEY}`}}const B=t=>{let e=t.getAttribute("data-bs-target");if(!e||"#"===e){let i=t.getAttribute("href");if(!i||!i.includes("#")&&!i.startsWith("."))return null;i.includes("#")&&!i.startsWith("#")&&(i=`#${i.split("#")[1]}`),e=i&&"#"!==i?i.trim():null}return n(e)},z={find:(t,e=document.documentElement)=>[].concat(...Element.prototype.querySelectorAll.call(e,t)),findOne:(t,e=document.documentElement)=>Element.prototype.querySelector.call(e,t),children:(t,e)=>[].concat(...t.children).filter((t=>t.matches(e))),parents(t,e){const i=[];let n=t.parentNode.closest(e);for(;n;)i.push(n),n=n.parentNode.closest(e);return i},prev(t,e){let i=t.previousElementSibling;for(;i;){if(i.matches(e))return[i];i=i.previousElementSibling}return[]},next(t,e){let i=t.nextElementSibling;for(;i;){if(i.matches(e))return[i];i=i.nextElementSibling}return[]},focusableChildren(t){const e=["a","button","input","textarea","select","details","[tabindex]",'[contenteditable="true"]'].map((t=>`${t}:not([tabindex^="-"])`)).join(",");return this.find(e,t).filter((t=>!l(t)&&a(t)))},getSelectorFromElement(t){const e=B(t);return e&&z.findOne(e)?e:null},getElementFromSelector(t){const e=B(t);return e?z.findOne(e):null},getMultipleElementsFromSelector(t){const e=B(t);return e?z.find(e):[]}},R=(t,e="hide")=>{const i=`click.dismiss${t.EVENT_KEY}`,n=t.NAME;N.on(document,i,`[data-bs-dismiss="${n}"]`,(function(i){if(["A","AREA"].includes(this.tagName)&&i.preventDefault(),l(this))return;const s=z.getElementFromSelector(this)||this.closest(`.${n}`);t.getOrCreateInstance(s)[e]()}))},q=".bs.alert",V=`close${q}`,K=`closed${q}`;class Q extends W{static get NAME(){return"alert"}close(){if(N.trigger(this._element,V).defaultPrevented)return;this._element.classList.remove("show");const t=this._element.classList.contains("fade");this._queueCallback((()=>this._destroyElement()),this._element,t)}_destroyElement(){this._element.remove(),N.trigger(this._element,K),this.dispose()}static jQueryInterface(t){return this.each((function(){const e=Q.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}R(Q,"close"),m(Q);const X='[data-bs-toggle="button"]';class Y extends W{static get NAME(){return"button"}toggle(){this._element.setAttribute("aria-pressed",this._element.classList.toggle("active"))}static jQueryInterface(t){return this.each((function(){const e=Y.getOrCreateInstance(this);"toggle"===t&&e[t]()}))}}N.on(document,"click.bs.button.data-api",X,(t=>{t.preventDefault();const e=t.target.closest(X);Y.getOrCreateInstance(e).toggle()})),m(Y);const U=".bs.swipe",G=`touchstart${U}`,J=`touchmove${U}`,Z=`touchend${U}`,tt=`pointerdown${U}`,et=`pointerup${U}`,it={endCallback:null,leftCallback:null,rightCallback:null},nt={endCallback:"(function|null)",leftCallback:"(function|null)",rightCallback:"(function|null)"};class st extends H{constructor(t,e){super(),this._element=t,t&&st.isSupported()&&(this._config=this._getConfig(e),this._deltaX=0,this._supportPointerEvents=Boolean(window.PointerEvent),this._initEvents())}static get Default(){return it}static get DefaultType(){return nt}static get NAME(){return"swipe"}dispose(){N.off(this._element,U)}_start(t){this._supportPointerEvents?this._eventIsPointerPenTouch(t)&&(this._deltaX=t.clientX):this._deltaX=t.touches[0].clientX}_end(t){this._eventIsPointerPenTouch(t)&&(this._deltaX=t.clientX-this._deltaX),this._handleSwipe(),g(this._config.endCallback)}_move(t){this._deltaX=t.touches&&t.touches.length>1?0:t.touches[0].clientX-this._deltaX}_handleSwipe(){const t=Math.abs(this._deltaX);if(t<=40)return;const e=t/this._deltaX;this._deltaX=0,e&&g(e>0?this._config.rightCallback:this._config.leftCallback)}_initEvents(){this._supportPointerEvents?(N.on(this._element,tt,(t=>this._start(t))),N.on(this._element,et,(t=>this._end(t))),this._element.classList.add("pointer-event")):(N.on(this._element,G,(t=>this._start(t))),N.on(this._element,J,(t=>this._move(t))),N.on(this._element,Z,(t=>this._end(t))))}_eventIsPointerPenTouch(t){return this._supportPointerEvents&&("pen"===t.pointerType||"touch"===t.pointerType)}static isSupported(){return"ontouchstart"in document.documentElement||navigator.maxTouchPoints>0}}const ot=".bs.carousel",rt=".data-api",at="next",lt="prev",ct="left",ht="right",dt=`slide${ot}`,ut=`slid${ot}`,ft=`keydown${ot}`,pt=`mouseenter${ot}`,mt=`mouseleave${ot}`,gt=`dragstart${ot}`,_t=`load${ot}${rt}`,bt=`click${ot}${rt}`,vt="carousel",yt="active",wt=".active",At=".carousel-item",Et=wt+At,Tt={ArrowLeft:ht,ArrowRight:ct},Ct={interval:5e3,keyboard:!0,pause:"hover",ride:!1,touch:!0,wrap:!0},Ot={interval:"(number|boolean)",keyboard:"boolean",pause:"(string|boolean)",ride:"(boolean|string)",touch:"boolean",wrap:"boolean"};class xt extends W{constructor(t,e){super(t,e),this._interval=null,this._activeElement=null,this._isSliding=!1,this.touchTimeout=null,this._swipeHelper=null,this._indicatorsElement=z.findOne(".carousel-indicators",this._element),this._addEventListeners(),this._config.ride===vt&&this.cycle()}static get Default(){return Ct}static get DefaultType(){return Ot}static get NAME(){return"carousel"}next(){this._slide(at)}nextWhenVisible(){!document.hidden&&a(this._element)&&this.next()}prev(){this._slide(lt)}pause(){this._isSliding&&s(this._element),this._clearInterval()}cycle(){this._clearInterval(),this._updateInterval(),this._interval=setInterval((()=>this.nextWhenVisible()),this._config.interval)}_maybeEnableCycle(){this._config.ride&&(this._isSliding?N.one(this._element,ut,(()=>this.cycle())):this.cycle())}to(t){const e=this._getItems();if(t>e.length-1||t<0)return;if(this._isSliding)return void N.one(this._element,ut,(()=>this.to(t)));const i=this._getItemIndex(this._getActive());if(i===t)return;const n=t>i?at:lt;this._slide(n,e[t])}dispose(){this._swipeHelper&&this._swipeHelper.dispose(),super.dispose()}_configAfterMerge(t){return t.defaultInterval=t.interval,t}_addEventListeners(){this._config.keyboard&&N.on(this._element,ft,(t=>this._keydown(t))),"hover"===this._config.pause&&(N.on(this._element,pt,(()=>this.pause())),N.on(this._element,mt,(()=>this._maybeEnableCycle()))),this._config.touch&&st.isSupported()&&this._addTouchEventListeners()}_addTouchEventListeners(){for(const t of z.find(".carousel-item img",this._element))N.on(t,gt,(t=>t.preventDefault()));const t={leftCallback:()=>this._slide(this._directionToOrder(ct)),rightCallback:()=>this._slide(this._directionToOrder(ht)),endCallback:()=>{"hover"===this._config.pause&&(this.pause(),this.touchTimeout&&clearTimeout(this.touchTimeout),this.touchTimeout=setTimeout((()=>this._maybeEnableCycle()),500+this._config.interval))}};this._swipeHelper=new st(this._element,t)}_keydown(t){if(/input|textarea/i.test(t.target.tagName))return;const e=Tt[t.key];e&&(t.preventDefault(),this._slide(this._directionToOrder(e)))}_getItemIndex(t){return this._getItems().indexOf(t)}_setActiveIndicatorElement(t){if(!this._indicatorsElement)return;const e=z.findOne(wt,this._indicatorsElement);e.classList.remove(yt),e.removeAttribute("aria-current");const i=z.findOne(`[data-bs-slide-to="${t}"]`,this._indicatorsElement);i&&(i.classList.add(yt),i.setAttribute("aria-current","true"))}_updateInterval(){const t=this._activeElement||this._getActive();if(!t)return;const e=Number.parseInt(t.getAttribute("data-bs-interval"),10);this._config.interval=e||this._config.defaultInterval}_slide(t,e=null){if(this._isSliding)return;const i=this._getActive(),n=t===at,s=e||b(this._getItems(),i,n,this._config.wrap);if(s===i)return;const o=this._getItemIndex(s),r=e=>N.trigger(this._element,e,{relatedTarget:s,direction:this._orderToDirection(t),from:this._getItemIndex(i),to:o});if(r(dt).defaultPrevented)return;if(!i||!s)return;const a=Boolean(this._interval);this.pause(),this._isSliding=!0,this._setActiveIndicatorElement(o),this._activeElement=s;const l=n?"carousel-item-start":"carousel-item-end",c=n?"carousel-item-next":"carousel-item-prev";s.classList.add(c),d(s),i.classList.add(l),s.classList.add(l),this._queueCallback((()=>{s.classList.remove(l,c),s.classList.add(yt),i.classList.remove(yt,c,l),this._isSliding=!1,r(ut)}),i,this._isAnimated()),a&&this.cycle()}_isAnimated(){return this._element.classList.contains("slide")}_getActive(){return z.findOne(Et,this._element)}_getItems(){return z.find(At,this._element)}_clearInterval(){this._interval&&(clearInterval(this._interval),this._interval=null)}_directionToOrder(t){return p()?t===ct?lt:at:t===ct?at:lt}_orderToDirection(t){return p()?t===lt?ct:ht:t===lt?ht:ct}static jQueryInterface(t){return this.each((function(){const e=xt.getOrCreateInstance(this,t);if("number"!=typeof t){if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}else e.to(t)}))}}N.on(document,bt,"[data-bs-slide], [data-bs-slide-to]",(function(t){const e=z.getElementFromSelector(this);if(!e||!e.classList.contains(vt))return;t.preventDefault();const i=xt.getOrCreateInstance(e),n=this.getAttribute("data-bs-slide-to");return n?(i.to(n),void i._maybeEnableCycle()):"next"===F.getDataAttribute(this,"slide")?(i.next(),void i._maybeEnableCycle()):(i.prev(),void i._maybeEnableCycle())})),N.on(window,_t,(()=>{const t=z.find('[data-bs-ride="carousel"]');for(const e of t)xt.getOrCreateInstance(e)})),m(xt);const kt=".bs.collapse",Lt=`show${kt}`,St=`shown${kt}`,Dt=`hide${kt}`,$t=`hidden${kt}`,It=`click${kt}.data-api`,Nt="show",Pt="collapse",Mt="collapsing",jt=`:scope .${Pt} .${Pt}`,Ft='[data-bs-toggle="collapse"]',Ht={parent:null,toggle:!0},Wt={parent:"(null|element)",toggle:"boolean"};class Bt extends W{constructor(t,e){super(t,e),this._isTransitioning=!1,this._triggerArray=[];const i=z.find(Ft);for(const t of i){const e=z.getSelectorFromElement(t),i=z.find(e).filter((t=>t===this._element));null!==e&&i.length&&this._triggerArray.push(t)}this._initializeChildren(),this._config.parent||this._addAriaAndCollapsedClass(this._triggerArray,this._isShown()),this._config.toggle&&this.toggle()}static get Default(){return Ht}static get DefaultType(){return Wt}static get NAME(){return"collapse"}toggle(){this._isShown()?this.hide():this.show()}show(){if(this._isTransitioning||this._isShown())return;let t=[];if(this._config.parent&&(t=this._getFirstLevelChildren(".collapse.show, .collapse.collapsing").filter((t=>t!==this._element)).map((t=>Bt.getOrCreateInstance(t,{toggle:!1})))),t.length&&t[0]._isTransitioning)return;if(N.trigger(this._element,Lt).defaultPrevented)return;for(const e of t)e.hide();const e=this._getDimension();this._element.classList.remove(Pt),this._element.classList.add(Mt),this._element.style[e]=0,this._addAriaAndCollapsedClass(this._triggerArray,!0),this._isTransitioning=!0;const i=`scroll${e[0].toUpperCase()+e.slice(1)}`;this._queueCallback((()=>{this._isTransitioning=!1,this._element.classList.remove(Mt),this._element.classList.add(Pt,Nt),this._element.style[e]="",N.trigger(this._element,St)}),this._element,!0),this._element.style[e]=`${this._element[i]}px`}hide(){if(this._isTransitioning||!this._isShown())return;if(N.trigger(this._element,Dt).defaultPrevented)return;const t=this._getDimension();this._element.style[t]=`${this._element.getBoundingClientRect()[t]}px`,d(this._element),this._element.classList.add(Mt),this._element.classList.remove(Pt,Nt);for(const t of this._triggerArray){const e=z.getElementFromSelector(t);e&&!this._isShown(e)&&this._addAriaAndCollapsedClass([t],!1)}this._isTransitioning=!0,this._element.style[t]="",this._queueCallback((()=>{this._isTransitioning=!1,this._element.classList.remove(Mt),this._element.classList.add(Pt),N.trigger(this._element,$t)}),this._element,!0)}_isShown(t=this._element){return t.classList.contains(Nt)}_configAfterMerge(t){return t.toggle=Boolean(t.toggle),t.parent=r(t.parent),t}_getDimension(){return this._element.classList.contains("collapse-horizontal")?"width":"height"}_initializeChildren(){if(!this._config.parent)return;const t=this._getFirstLevelChildren(Ft);for(const e of t){const t=z.getElementFromSelector(e);t&&this._addAriaAndCollapsedClass([e],this._isShown(t))}}_getFirstLevelChildren(t){const e=z.find(jt,this._config.parent);return z.find(t,this._config.parent).filter((t=>!e.includes(t)))}_addAriaAndCollapsedClass(t,e){if(t.length)for(const i of t)i.classList.toggle("collapsed",!e),i.setAttribute("aria-expanded",e)}static jQueryInterface(t){const e={};return"string"==typeof t&&/show|hide/.test(t)&&(e.toggle=!1),this.each((function(){const i=Bt.getOrCreateInstance(this,e);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t]()}}))}}N.on(document,It,Ft,(function(t){("A"===t.target.tagName||t.delegateTarget&&"A"===t.delegateTarget.tagName)&&t.preventDefault();for(const t of z.getMultipleElementsFromSelector(this))Bt.getOrCreateInstance(t,{toggle:!1}).toggle()})),m(Bt);var zt="top",Rt="bottom",qt="right",Vt="left",Kt="auto",Qt=[zt,Rt,qt,Vt],Xt="start",Yt="end",Ut="clippingParents",Gt="viewport",Jt="popper",Zt="reference",te=Qt.reduce((function(t,e){return t.concat([e+"-"+Xt,e+"-"+Yt])}),[]),ee=[].concat(Qt,[Kt]).reduce((function(t,e){return t.concat([e,e+"-"+Xt,e+"-"+Yt])}),[]),ie="beforeRead",ne="read",se="afterRead",oe="beforeMain",re="main",ae="afterMain",le="beforeWrite",ce="write",he="afterWrite",de=[ie,ne,se,oe,re,ae,le,ce,he];function ue(t){return t?(t.nodeName||"").toLowerCase():null}function fe(t){if(null==t)return window;if("[object Window]"!==t.toString()){var e=t.ownerDocument;return e&&e.defaultView||window}return t}function pe(t){return t instanceof fe(t).Element||t instanceof Element}function me(t){return t instanceof fe(t).HTMLElement||t instanceof HTMLElement}function ge(t){return"undefined"!=typeof ShadowRoot&&(t instanceof fe(t).ShadowRoot||t instanceof ShadowRoot)}const _e={name:"applyStyles",enabled:!0,phase:"write",fn:function(t){var e=t.state;Object.keys(e.elements).forEach((function(t){var i=e.styles[t]||{},n=e.attributes[t]||{},s=e.elements[t];me(s)&&ue(s)&&(Object.assign(s.style,i),Object.keys(n).forEach((function(t){var e=n[t];!1===e?s.removeAttribute(t):s.setAttribute(t,!0===e?"":e)})))}))},effect:function(t){var e=t.state,i={popper:{position:e.options.strategy,left:"0",top:"0",margin:"0"},arrow:{position:"absolute"},reference:{}};return Object.assign(e.elements.popper.style,i.popper),e.styles=i,e.elements.arrow&&Object.assign(e.elements.arrow.style,i.arrow),function(){Object.keys(e.elements).forEach((function(t){var n=e.elements[t],s=e.attributes[t]||{},o=Object.keys(e.styles.hasOwnProperty(t)?e.styles[t]:i[t]).reduce((function(t,e){return t[e]="",t}),{});me(n)&&ue(n)&&(Object.assign(n.style,o),Object.keys(s).forEach((function(t){n.removeAttribute(t)})))}))}},requires:["computeStyles"]};function be(t){return t.split("-")[0]}var ve=Math.max,ye=Math.min,we=Math.round;function Ae(){var t=navigator.userAgentData;return null!=t&&t.brands&&Array.isArray(t.brands)?t.brands.map((function(t){return t.brand+"/"+t.version})).join(" "):navigator.userAgent}function Ee(){return!/^((?!chrome|android).)*safari/i.test(Ae())}function Te(t,e,i){void 0===e&&(e=!1),void 0===i&&(i=!1);var n=t.getBoundingClientRect(),s=1,o=1;e&&me(t)&&(s=t.offsetWidth>0&&we(n.width)/t.offsetWidth||1,o=t.offsetHeight>0&&we(n.height)/t.offsetHeight||1);var r=(pe(t)?fe(t):window).visualViewport,a=!Ee()&&i,l=(n.left+(a&&r?r.offsetLeft:0))/s,c=(n.top+(a&&r?r.offsetTop:0))/o,h=n.width/s,d=n.height/o;return{width:h,height:d,top:c,right:l+h,bottom:c+d,left:l,x:l,y:c}}function Ce(t){var e=Te(t),i=t.offsetWidth,n=t.offsetHeight;return Math.abs(e.width-i)<=1&&(i=e.width),Math.abs(e.height-n)<=1&&(n=e.height),{x:t.offsetLeft,y:t.offsetTop,width:i,height:n}}function Oe(t,e){var i=e.getRootNode&&e.getRootNode();if(t.contains(e))return!0;if(i&&ge(i)){var n=e;do{if(n&&t.isSameNode(n))return!0;n=n.parentNode||n.host}while(n)}return!1}function xe(t){return fe(t).getComputedStyle(t)}function ke(t){return["table","td","th"].indexOf(ue(t))>=0}function Le(t){return((pe(t)?t.ownerDocument:t.document)||window.document).documentElement}function Se(t){return"html"===ue(t)?t:t.assignedSlot||t.parentNode||(ge(t)?t.host:null)||Le(t)}function De(t){return me(t)&&"fixed"!==xe(t).position?t.offsetParent:null}function $e(t){for(var e=fe(t),i=De(t);i&&ke(i)&&"static"===xe(i).position;)i=De(i);return i&&("html"===ue(i)||"body"===ue(i)&&"static"===xe(i).position)?e:i||function(t){var e=/firefox/i.test(Ae());if(/Trident/i.test(Ae())&&me(t)&&"fixed"===xe(t).position)return null;var i=Se(t);for(ge(i)&&(i=i.host);me(i)&&["html","body"].indexOf(ue(i))<0;){var n=xe(i);if("none"!==n.transform||"none"!==n.perspective||"paint"===n.contain||-1!==["transform","perspective"].indexOf(n.willChange)||e&&"filter"===n.willChange||e&&n.filter&&"none"!==n.filter)return i;i=i.parentNode}return null}(t)||e}function Ie(t){return["top","bottom"].indexOf(t)>=0?"x":"y"}function Ne(t,e,i){return ve(t,ye(e,i))}function Pe(t){return Object.assign({},{top:0,right:0,bottom:0,left:0},t)}function Me(t,e){return e.reduce((function(e,i){return e[i]=t,e}),{})}const je={name:"arrow",enabled:!0,phase:"main",fn:function(t){var e,i=t.state,n=t.name,s=t.options,o=i.elements.arrow,r=i.modifiersData.popperOffsets,a=be(i.placement),l=Ie(a),c=[Vt,qt].indexOf(a)>=0?"height":"width";if(o&&r){var h=function(t,e){return Pe("number"!=typeof(t="function"==typeof t?t(Object.assign({},e.rects,{placement:e.placement})):t)?t:Me(t,Qt))}(s.padding,i),d=Ce(o),u="y"===l?zt:Vt,f="y"===l?Rt:qt,p=i.rects.reference[c]+i.rects.reference[l]-r[l]-i.rects.popper[c],m=r[l]-i.rects.reference[l],g=$e(o),_=g?"y"===l?g.clientHeight||0:g.clientWidth||0:0,b=p/2-m/2,v=h[u],y=_-d[c]-h[f],w=_/2-d[c]/2+b,A=Ne(v,w,y),E=l;i.modifiersData[n]=((e={})[E]=A,e.centerOffset=A-w,e)}},effect:function(t){var e=t.state,i=t.options.element,n=void 0===i?"[data-popper-arrow]":i;null!=n&&("string"!=typeof n||(n=e.elements.popper.querySelector(n)))&&Oe(e.elements.popper,n)&&(e.elements.arrow=n)},requires:["popperOffsets"],requiresIfExists:["preventOverflow"]};function Fe(t){return t.split("-")[1]}var He={top:"auto",right:"auto",bottom:"auto",left:"auto"};function We(t){var e,i=t.popper,n=t.popperRect,s=t.placement,o=t.variation,r=t.offsets,a=t.position,l=t.gpuAcceleration,c=t.adaptive,h=t.roundOffsets,d=t.isFixed,u=r.x,f=void 0===u?0:u,p=r.y,m=void 0===p?0:p,g="function"==typeof h?h({x:f,y:m}):{x:f,y:m};f=g.x,m=g.y;var _=r.hasOwnProperty("x"),b=r.hasOwnProperty("y"),v=Vt,y=zt,w=window;if(c){var A=$e(i),E="clientHeight",T="clientWidth";A===fe(i)&&"static"!==xe(A=Le(i)).position&&"absolute"===a&&(E="scrollHeight",T="scrollWidth"),(s===zt||(s===Vt||s===qt)&&o===Yt)&&(y=Rt,m-=(d&&A===w&&w.visualViewport?w.visualViewport.height:A[E])-n.height,m*=l?1:-1),s!==Vt&&(s!==zt&&s!==Rt||o!==Yt)||(v=qt,f-=(d&&A===w&&w.visualViewport?w.visualViewport.width:A[T])-n.width,f*=l?1:-1)}var C,O=Object.assign({position:a},c&&He),x=!0===h?function(t,e){var i=t.x,n=t.y,s=e.devicePixelRatio||1;return{x:we(i*s)/s||0,y:we(n*s)/s||0}}({x:f,y:m},fe(i)):{x:f,y:m};return f=x.x,m=x.y,l?Object.assign({},O,((C={})[y]=b?"0":"",C[v]=_?"0":"",C.transform=(w.devicePixelRatio||1)<=1?"translate("+f+"px, "+m+"px)":"translate3d("+f+"px, "+m+"px, 0)",C)):Object.assign({},O,((e={})[y]=b?m+"px":"",e[v]=_?f+"px":"",e.transform="",e))}const Be={name:"computeStyles",enabled:!0,phase:"beforeWrite",fn:function(t){var e=t.state,i=t.options,n=i.gpuAcceleration,s=void 0===n||n,o=i.adaptive,r=void 0===o||o,a=i.roundOffsets,l=void 0===a||a,c={placement:be(e.placement),variation:Fe(e.placement),popper:e.elements.popper,popperRect:e.rects.popper,gpuAcceleration:s,isFixed:"fixed"===e.options.strategy};null!=e.modifiersData.popperOffsets&&(e.styles.popper=Object.assign({},e.styles.popper,We(Object.assign({},c,{offsets:e.modifiersData.popperOffsets,position:e.options.strategy,adaptive:r,roundOffsets:l})))),null!=e.modifiersData.arrow&&(e.styles.arrow=Object.assign({},e.styles.arrow,We(Object.assign({},c,{offsets:e.modifiersData.arrow,position:"absolute",adaptive:!1,roundOffsets:l})))),e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-placement":e.placement})},data:{}};var ze={passive:!0};const Re={name:"eventListeners",enabled:!0,phase:"write",fn:function(){},effect:function(t){var e=t.state,i=t.instance,n=t.options,s=n.scroll,o=void 0===s||s,r=n.resize,a=void 0===r||r,l=fe(e.elements.popper),c=[].concat(e.scrollParents.reference,e.scrollParents.popper);return o&&c.forEach((function(t){t.addEventListener("scroll",i.update,ze)})),a&&l.addEventListener("resize",i.update,ze),function(){o&&c.forEach((function(t){t.removeEventListener("scroll",i.update,ze)})),a&&l.removeEventListener("resize",i.update,ze)}},data:{}};var qe={left:"right",right:"left",bottom:"top",top:"bottom"};function Ve(t){return t.replace(/left|right|bottom|top/g,(function(t){return qe[t]}))}var Ke={start:"end",end:"start"};function Qe(t){return t.replace(/start|end/g,(function(t){return Ke[t]}))}function Xe(t){var e=fe(t);return{scrollLeft:e.pageXOffset,scrollTop:e.pageYOffset}}function Ye(t){return Te(Le(t)).left+Xe(t).scrollLeft}function Ue(t){var e=xe(t),i=e.overflow,n=e.overflowX,s=e.overflowY;return/auto|scroll|overlay|hidden/.test(i+s+n)}function Ge(t){return["html","body","#document"].indexOf(ue(t))>=0?t.ownerDocument.body:me(t)&&Ue(t)?t:Ge(Se(t))}function Je(t,e){var i;void 0===e&&(e=[]);var n=Ge(t),s=n===(null==(i=t.ownerDocument)?void 0:i.body),o=fe(n),r=s?[o].concat(o.visualViewport||[],Ue(n)?n:[]):n,a=e.concat(r);return s?a:a.concat(Je(Se(r)))}function Ze(t){return Object.assign({},t,{left:t.x,top:t.y,right:t.x+t.width,bottom:t.y+t.height})}function ti(t,e,i){return e===Gt?Ze(function(t,e){var i=fe(t),n=Le(t),s=i.visualViewport,o=n.clientWidth,r=n.clientHeight,a=0,l=0;if(s){o=s.width,r=s.height;var c=Ee();(c||!c&&"fixed"===e)&&(a=s.offsetLeft,l=s.offsetTop)}return{width:o,height:r,x:a+Ye(t),y:l}}(t,i)):pe(e)?function(t,e){var i=Te(t,!1,"fixed"===e);return i.top=i.top+t.clientTop,i.left=i.left+t.clientLeft,i.bottom=i.top+t.clientHeight,i.right=i.left+t.clientWidth,i.width=t.clientWidth,i.height=t.clientHeight,i.x=i.left,i.y=i.top,i}(e,i):Ze(function(t){var e,i=Le(t),n=Xe(t),s=null==(e=t.ownerDocument)?void 0:e.body,o=ve(i.scrollWidth,i.clientWidth,s?s.scrollWidth:0,s?s.clientWidth:0),r=ve(i.scrollHeight,i.clientHeight,s?s.scrollHeight:0,s?s.clientHeight:0),a=-n.scrollLeft+Ye(t),l=-n.scrollTop;return"rtl"===xe(s||i).direction&&(a+=ve(i.clientWidth,s?s.clientWidth:0)-o),{width:o,height:r,x:a,y:l}}(Le(t)))}function ei(t){var e,i=t.reference,n=t.element,s=t.placement,o=s?be(s):null,r=s?Fe(s):null,a=i.x+i.width/2-n.width/2,l=i.y+i.height/2-n.height/2;switch(o){case zt:e={x:a,y:i.y-n.height};break;case Rt:e={x:a,y:i.y+i.height};break;case qt:e={x:i.x+i.width,y:l};break;case Vt:e={x:i.x-n.width,y:l};break;default:e={x:i.x,y:i.y}}var c=o?Ie(o):null;if(null!=c){var h="y"===c?"height":"width";switch(r){case Xt:e[c]=e[c]-(i[h]/2-n[h]/2);break;case Yt:e[c]=e[c]+(i[h]/2-n[h]/2)}}return e}function ii(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=void 0===n?t.placement:n,o=i.strategy,r=void 0===o?t.strategy:o,a=i.boundary,l=void 0===a?Ut:a,c=i.rootBoundary,h=void 0===c?Gt:c,d=i.elementContext,u=void 0===d?Jt:d,f=i.altBoundary,p=void 0!==f&&f,m=i.padding,g=void 0===m?0:m,_=Pe("number"!=typeof g?g:Me(g,Qt)),b=u===Jt?Zt:Jt,v=t.rects.popper,y=t.elements[p?b:u],w=function(t,e,i,n){var s="clippingParents"===e?function(t){var e=Je(Se(t)),i=["absolute","fixed"].indexOf(xe(t).position)>=0&&me(t)?$e(t):t;return pe(i)?e.filter((function(t){return pe(t)&&Oe(t,i)&&"body"!==ue(t)})):[]}(t):[].concat(e),o=[].concat(s,[i]),r=o[0],a=o.reduce((function(e,i){var s=ti(t,i,n);return e.top=ve(s.top,e.top),e.right=ye(s.right,e.right),e.bottom=ye(s.bottom,e.bottom),e.left=ve(s.left,e.left),e}),ti(t,r,n));return a.width=a.right-a.left,a.height=a.bottom-a.top,a.x=a.left,a.y=a.top,a}(pe(y)?y:y.contextElement||Le(t.elements.popper),l,h,r),A=Te(t.elements.reference),E=ei({reference:A,element:v,strategy:"absolute",placement:s}),T=Ze(Object.assign({},v,E)),C=u===Jt?T:A,O={top:w.top-C.top+_.top,bottom:C.bottom-w.bottom+_.bottom,left:w.left-C.left+_.left,right:C.right-w.right+_.right},x=t.modifiersData.offset;if(u===Jt&&x){var k=x[s];Object.keys(O).forEach((function(t){var e=[qt,Rt].indexOf(t)>=0?1:-1,i=[zt,Rt].indexOf(t)>=0?"y":"x";O[t]+=k[i]*e}))}return O}function ni(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=i.boundary,o=i.rootBoundary,r=i.padding,a=i.flipVariations,l=i.allowedAutoPlacements,c=void 0===l?ee:l,h=Fe(n),d=h?a?te:te.filter((function(t){return Fe(t)===h})):Qt,u=d.filter((function(t){return c.indexOf(t)>=0}));0===u.length&&(u=d);var f=u.reduce((function(e,i){return e[i]=ii(t,{placement:i,boundary:s,rootBoundary:o,padding:r})[be(i)],e}),{});return Object.keys(f).sort((function(t,e){return f[t]-f[e]}))}const si={name:"flip",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,n=t.name;if(!e.modifiersData[n]._skip){for(var s=i.mainAxis,o=void 0===s||s,r=i.altAxis,a=void 0===r||r,l=i.fallbackPlacements,c=i.padding,h=i.boundary,d=i.rootBoundary,u=i.altBoundary,f=i.flipVariations,p=void 0===f||f,m=i.allowedAutoPlacements,g=e.options.placement,_=be(g),b=l||(_!==g&&p?function(t){if(be(t)===Kt)return[];var e=Ve(t);return[Qe(t),e,Qe(e)]}(g):[Ve(g)]),v=[g].concat(b).reduce((function(t,i){return t.concat(be(i)===Kt?ni(e,{placement:i,boundary:h,rootBoundary:d,padding:c,flipVariations:p,allowedAutoPlacements:m}):i)}),[]),y=e.rects.reference,w=e.rects.popper,A=new Map,E=!0,T=v[0],C=0;C=0,S=L?"width":"height",D=ii(e,{placement:O,boundary:h,rootBoundary:d,altBoundary:u,padding:c}),$=L?k?qt:Vt:k?Rt:zt;y[S]>w[S]&&($=Ve($));var I=Ve($),N=[];if(o&&N.push(D[x]<=0),a&&N.push(D[$]<=0,D[I]<=0),N.every((function(t){return t}))){T=O,E=!1;break}A.set(O,N)}if(E)for(var P=function(t){var e=v.find((function(e){var i=A.get(e);if(i)return i.slice(0,t).every((function(t){return t}))}));if(e)return T=e,"break"},M=p?3:1;M>0&&"break"!==P(M);M--);e.placement!==T&&(e.modifiersData[n]._skip=!0,e.placement=T,e.reset=!0)}},requiresIfExists:["offset"],data:{_skip:!1}};function oi(t,e,i){return void 0===i&&(i={x:0,y:0}),{top:t.top-e.height-i.y,right:t.right-e.width+i.x,bottom:t.bottom-e.height+i.y,left:t.left-e.width-i.x}}function ri(t){return[zt,qt,Rt,Vt].some((function(e){return t[e]>=0}))}const ai={name:"hide",enabled:!0,phase:"main",requiresIfExists:["preventOverflow"],fn:function(t){var e=t.state,i=t.name,n=e.rects.reference,s=e.rects.popper,o=e.modifiersData.preventOverflow,r=ii(e,{elementContext:"reference"}),a=ii(e,{altBoundary:!0}),l=oi(r,n),c=oi(a,s,o),h=ri(l),d=ri(c);e.modifiersData[i]={referenceClippingOffsets:l,popperEscapeOffsets:c,isReferenceHidden:h,hasPopperEscaped:d},e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-reference-hidden":h,"data-popper-escaped":d})}},li={name:"offset",enabled:!0,phase:"main",requires:["popperOffsets"],fn:function(t){var e=t.state,i=t.options,n=t.name,s=i.offset,o=void 0===s?[0,0]:s,r=ee.reduce((function(t,i){return t[i]=function(t,e,i){var n=be(t),s=[Vt,zt].indexOf(n)>=0?-1:1,o="function"==typeof i?i(Object.assign({},e,{placement:t})):i,r=o[0],a=o[1];return r=r||0,a=(a||0)*s,[Vt,qt].indexOf(n)>=0?{x:a,y:r}:{x:r,y:a}}(i,e.rects,o),t}),{}),a=r[e.placement],l=a.x,c=a.y;null!=e.modifiersData.popperOffsets&&(e.modifiersData.popperOffsets.x+=l,e.modifiersData.popperOffsets.y+=c),e.modifiersData[n]=r}},ci={name:"popperOffsets",enabled:!0,phase:"read",fn:function(t){var e=t.state,i=t.name;e.modifiersData[i]=ei({reference:e.rects.reference,element:e.rects.popper,strategy:"absolute",placement:e.placement})},data:{}},hi={name:"preventOverflow",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,n=t.name,s=i.mainAxis,o=void 0===s||s,r=i.altAxis,a=void 0!==r&&r,l=i.boundary,c=i.rootBoundary,h=i.altBoundary,d=i.padding,u=i.tether,f=void 0===u||u,p=i.tetherOffset,m=void 0===p?0:p,g=ii(e,{boundary:l,rootBoundary:c,padding:d,altBoundary:h}),_=be(e.placement),b=Fe(e.placement),v=!b,y=Ie(_),w="x"===y?"y":"x",A=e.modifiersData.popperOffsets,E=e.rects.reference,T=e.rects.popper,C="function"==typeof m?m(Object.assign({},e.rects,{placement:e.placement})):m,O="number"==typeof C?{mainAxis:C,altAxis:C}:Object.assign({mainAxis:0,altAxis:0},C),x=e.modifiersData.offset?e.modifiersData.offset[e.placement]:null,k={x:0,y:0};if(A){if(o){var L,S="y"===y?zt:Vt,D="y"===y?Rt:qt,$="y"===y?"height":"width",I=A[y],N=I+g[S],P=I-g[D],M=f?-T[$]/2:0,j=b===Xt?E[$]:T[$],F=b===Xt?-T[$]:-E[$],H=e.elements.arrow,W=f&&H?Ce(H):{width:0,height:0},B=e.modifiersData["arrow#persistent"]?e.modifiersData["arrow#persistent"].padding:{top:0,right:0,bottom:0,left:0},z=B[S],R=B[D],q=Ne(0,E[$],W[$]),V=v?E[$]/2-M-q-z-O.mainAxis:j-q-z-O.mainAxis,K=v?-E[$]/2+M+q+R+O.mainAxis:F+q+R+O.mainAxis,Q=e.elements.arrow&&$e(e.elements.arrow),X=Q?"y"===y?Q.clientTop||0:Q.clientLeft||0:0,Y=null!=(L=null==x?void 0:x[y])?L:0,U=I+K-Y,G=Ne(f?ye(N,I+V-Y-X):N,I,f?ve(P,U):P);A[y]=G,k[y]=G-I}if(a){var J,Z="x"===y?zt:Vt,tt="x"===y?Rt:qt,et=A[w],it="y"===w?"height":"width",nt=et+g[Z],st=et-g[tt],ot=-1!==[zt,Vt].indexOf(_),rt=null!=(J=null==x?void 0:x[w])?J:0,at=ot?nt:et-E[it]-T[it]-rt+O.altAxis,lt=ot?et+E[it]+T[it]-rt-O.altAxis:st,ct=f&&ot?function(t,e,i){var n=Ne(t,e,i);return n>i?i:n}(at,et,lt):Ne(f?at:nt,et,f?lt:st);A[w]=ct,k[w]=ct-et}e.modifiersData[n]=k}},requiresIfExists:["offset"]};function di(t,e,i){void 0===i&&(i=!1);var n,s,o=me(e),r=me(e)&&function(t){var e=t.getBoundingClientRect(),i=we(e.width)/t.offsetWidth||1,n=we(e.height)/t.offsetHeight||1;return 1!==i||1!==n}(e),a=Le(e),l=Te(t,r,i),c={scrollLeft:0,scrollTop:0},h={x:0,y:0};return(o||!o&&!i)&&(("body"!==ue(e)||Ue(a))&&(c=(n=e)!==fe(n)&&me(n)?{scrollLeft:(s=n).scrollLeft,scrollTop:s.scrollTop}:Xe(n)),me(e)?((h=Te(e,!0)).x+=e.clientLeft,h.y+=e.clientTop):a&&(h.x=Ye(a))),{x:l.left+c.scrollLeft-h.x,y:l.top+c.scrollTop-h.y,width:l.width,height:l.height}}function ui(t){var e=new Map,i=new Set,n=[];function s(t){i.add(t.name),[].concat(t.requires||[],t.requiresIfExists||[]).forEach((function(t){if(!i.has(t)){var n=e.get(t);n&&s(n)}})),n.push(t)}return t.forEach((function(t){e.set(t.name,t)})),t.forEach((function(t){i.has(t.name)||s(t)})),n}var fi={placement:"bottom",modifiers:[],strategy:"absolute"};function pi(){for(var t=arguments.length,e=new Array(t),i=0;iNumber.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_getPopperConfig(){const t={placement:this._getPlacement(),modifiers:[{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"offset",options:{offset:this._getOffset()}}]};return(this._inNavbar||"static"===this._config.display)&&(F.setDataAttribute(this._menu,"popper","static"),t.modifiers=[{name:"applyStyles",enabled:!1}]),{...t,...g(this._config.popperConfig,[t])}}_selectMenuItem({key:t,target:e}){const i=z.find(".dropdown-menu .dropdown-item:not(.disabled):not(:disabled)",this._menu).filter((t=>a(t)));i.length&&b(i,e,t===Ti,!i.includes(e)).focus()}static jQueryInterface(t){return this.each((function(){const e=qi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}static clearMenus(t){if(2===t.button||"keyup"===t.type&&"Tab"!==t.key)return;const e=z.find(Ni);for(const i of e){const e=qi.getInstance(i);if(!e||!1===e._config.autoClose)continue;const n=t.composedPath(),s=n.includes(e._menu);if(n.includes(e._element)||"inside"===e._config.autoClose&&!s||"outside"===e._config.autoClose&&s)continue;if(e._menu.contains(t.target)&&("keyup"===t.type&&"Tab"===t.key||/input|select|option|textarea|form/i.test(t.target.tagName)))continue;const o={relatedTarget:e._element};"click"===t.type&&(o.clickEvent=t),e._completeHide(o)}}static dataApiKeydownHandler(t){const e=/input|textarea/i.test(t.target.tagName),i="Escape"===t.key,n=[Ei,Ti].includes(t.key);if(!n&&!i)return;if(e&&!i)return;t.preventDefault();const s=this.matches(Ii)?this:z.prev(this,Ii)[0]||z.next(this,Ii)[0]||z.findOne(Ii,t.delegateTarget.parentNode),o=qi.getOrCreateInstance(s);if(n)return t.stopPropagation(),o.show(),void o._selectMenuItem(t);o._isShown()&&(t.stopPropagation(),o.hide(),s.focus())}}N.on(document,Si,Ii,qi.dataApiKeydownHandler),N.on(document,Si,Pi,qi.dataApiKeydownHandler),N.on(document,Li,qi.clearMenus),N.on(document,Di,qi.clearMenus),N.on(document,Li,Ii,(function(t){t.preventDefault(),qi.getOrCreateInstance(this).toggle()})),m(qi);const Vi="backdrop",Ki="show",Qi=`mousedown.bs.${Vi}`,Xi={className:"modal-backdrop",clickCallback:null,isAnimated:!1,isVisible:!0,rootElement:"body"},Yi={className:"string",clickCallback:"(function|null)",isAnimated:"boolean",isVisible:"boolean",rootElement:"(element|string)"};class Ui extends H{constructor(t){super(),this._config=this._getConfig(t),this._isAppended=!1,this._element=null}static get Default(){return Xi}static get DefaultType(){return Yi}static get NAME(){return Vi}show(t){if(!this._config.isVisible)return void g(t);this._append();const e=this._getElement();this._config.isAnimated&&d(e),e.classList.add(Ki),this._emulateAnimation((()=>{g(t)}))}hide(t){this._config.isVisible?(this._getElement().classList.remove(Ki),this._emulateAnimation((()=>{this.dispose(),g(t)}))):g(t)}dispose(){this._isAppended&&(N.off(this._element,Qi),this._element.remove(),this._isAppended=!1)}_getElement(){if(!this._element){const t=document.createElement("div");t.className=this._config.className,this._config.isAnimated&&t.classList.add("fade"),this._element=t}return this._element}_configAfterMerge(t){return t.rootElement=r(t.rootElement),t}_append(){if(this._isAppended)return;const t=this._getElement();this._config.rootElement.append(t),N.on(t,Qi,(()=>{g(this._config.clickCallback)})),this._isAppended=!0}_emulateAnimation(t){_(t,this._getElement(),this._config.isAnimated)}}const Gi=".bs.focustrap",Ji=`focusin${Gi}`,Zi=`keydown.tab${Gi}`,tn="backward",en={autofocus:!0,trapElement:null},nn={autofocus:"boolean",trapElement:"element"};class sn extends H{constructor(t){super(),this._config=this._getConfig(t),this._isActive=!1,this._lastTabNavDirection=null}static get Default(){return en}static get DefaultType(){return nn}static get NAME(){return"focustrap"}activate(){this._isActive||(this._config.autofocus&&this._config.trapElement.focus(),N.off(document,Gi),N.on(document,Ji,(t=>this._handleFocusin(t))),N.on(document,Zi,(t=>this._handleKeydown(t))),this._isActive=!0)}deactivate(){this._isActive&&(this._isActive=!1,N.off(document,Gi))}_handleFocusin(t){const{trapElement:e}=this._config;if(t.target===document||t.target===e||e.contains(t.target))return;const i=z.focusableChildren(e);0===i.length?e.focus():this._lastTabNavDirection===tn?i[i.length-1].focus():i[0].focus()}_handleKeydown(t){"Tab"===t.key&&(this._lastTabNavDirection=t.shiftKey?tn:"forward")}}const on=".fixed-top, .fixed-bottom, .is-fixed, .sticky-top",rn=".sticky-top",an="padding-right",ln="margin-right";class cn{constructor(){this._element=document.body}getWidth(){const t=document.documentElement.clientWidth;return Math.abs(window.innerWidth-t)}hide(){const t=this.getWidth();this._disableOverFlow(),this._setElementAttributes(this._element,an,(e=>e+t)),this._setElementAttributes(on,an,(e=>e+t)),this._setElementAttributes(rn,ln,(e=>e-t))}reset(){this._resetElementAttributes(this._element,"overflow"),this._resetElementAttributes(this._element,an),this._resetElementAttributes(on,an),this._resetElementAttributes(rn,ln)}isOverflowing(){return this.getWidth()>0}_disableOverFlow(){this._saveInitialAttribute(this._element,"overflow"),this._element.style.overflow="hidden"}_setElementAttributes(t,e,i){const n=this.getWidth();this._applyManipulationCallback(t,(t=>{if(t!==this._element&&window.innerWidth>t.clientWidth+n)return;this._saveInitialAttribute(t,e);const s=window.getComputedStyle(t).getPropertyValue(e);t.style.setProperty(e,`${i(Number.parseFloat(s))}px`)}))}_saveInitialAttribute(t,e){const i=t.style.getPropertyValue(e);i&&F.setDataAttribute(t,e,i)}_resetElementAttributes(t,e){this._applyManipulationCallback(t,(t=>{const i=F.getDataAttribute(t,e);null!==i?(F.removeDataAttribute(t,e),t.style.setProperty(e,i)):t.style.removeProperty(e)}))}_applyManipulationCallback(t,e){if(o(t))e(t);else for(const i of z.find(t,this._element))e(i)}}const hn=".bs.modal",dn=`hide${hn}`,un=`hidePrevented${hn}`,fn=`hidden${hn}`,pn=`show${hn}`,mn=`shown${hn}`,gn=`resize${hn}`,_n=`click.dismiss${hn}`,bn=`mousedown.dismiss${hn}`,vn=`keydown.dismiss${hn}`,yn=`click${hn}.data-api`,wn="modal-open",An="show",En="modal-static",Tn={backdrop:!0,focus:!0,keyboard:!0},Cn={backdrop:"(boolean|string)",focus:"boolean",keyboard:"boolean"};class On extends W{constructor(t,e){super(t,e),this._dialog=z.findOne(".modal-dialog",this._element),this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._isShown=!1,this._isTransitioning=!1,this._scrollBar=new cn,this._addEventListeners()}static get Default(){return Tn}static get DefaultType(){return Cn}static get NAME(){return"modal"}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||this._isTransitioning||N.trigger(this._element,pn,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._isTransitioning=!0,this._scrollBar.hide(),document.body.classList.add(wn),this._adjustDialog(),this._backdrop.show((()=>this._showElement(t))))}hide(){this._isShown&&!this._isTransitioning&&(N.trigger(this._element,dn).defaultPrevented||(this._isShown=!1,this._isTransitioning=!0,this._focustrap.deactivate(),this._element.classList.remove(An),this._queueCallback((()=>this._hideModal()),this._element,this._isAnimated())))}dispose(){N.off(window,hn),N.off(this._dialog,hn),this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}handleUpdate(){this._adjustDialog()}_initializeBackDrop(){return new Ui({isVisible:Boolean(this._config.backdrop),isAnimated:this._isAnimated()})}_initializeFocusTrap(){return new sn({trapElement:this._element})}_showElement(t){document.body.contains(this._element)||document.body.append(this._element),this._element.style.display="block",this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.scrollTop=0;const e=z.findOne(".modal-body",this._dialog);e&&(e.scrollTop=0),d(this._element),this._element.classList.add(An),this._queueCallback((()=>{this._config.focus&&this._focustrap.activate(),this._isTransitioning=!1,N.trigger(this._element,mn,{relatedTarget:t})}),this._dialog,this._isAnimated())}_addEventListeners(){N.on(this._element,vn,(t=>{"Escape"===t.key&&(this._config.keyboard?this.hide():this._triggerBackdropTransition())})),N.on(window,gn,(()=>{this._isShown&&!this._isTransitioning&&this._adjustDialog()})),N.on(this._element,bn,(t=>{N.one(this._element,_n,(e=>{this._element===t.target&&this._element===e.target&&("static"!==this._config.backdrop?this._config.backdrop&&this.hide():this._triggerBackdropTransition())}))}))}_hideModal(){this._element.style.display="none",this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._isTransitioning=!1,this._backdrop.hide((()=>{document.body.classList.remove(wn),this._resetAdjustments(),this._scrollBar.reset(),N.trigger(this._element,fn)}))}_isAnimated(){return this._element.classList.contains("fade")}_triggerBackdropTransition(){if(N.trigger(this._element,un).defaultPrevented)return;const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._element.style.overflowY;"hidden"===e||this._element.classList.contains(En)||(t||(this._element.style.overflowY="hidden"),this._element.classList.add(En),this._queueCallback((()=>{this._element.classList.remove(En),this._queueCallback((()=>{this._element.style.overflowY=e}),this._dialog)}),this._dialog),this._element.focus())}_adjustDialog(){const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._scrollBar.getWidth(),i=e>0;if(i&&!t){const t=p()?"paddingLeft":"paddingRight";this._element.style[t]=`${e}px`}if(!i&&t){const t=p()?"paddingRight":"paddingLeft";this._element.style[t]=`${e}px`}}_resetAdjustments(){this._element.style.paddingLeft="",this._element.style.paddingRight=""}static jQueryInterface(t,e){return this.each((function(){const i=On.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t](e)}}))}}N.on(document,yn,'[data-bs-toggle="modal"]',(function(t){const e=z.getElementFromSelector(this);["A","AREA"].includes(this.tagName)&&t.preventDefault(),N.one(e,pn,(t=>{t.defaultPrevented||N.one(e,fn,(()=>{a(this)&&this.focus()}))}));const i=z.findOne(".modal.show");i&&On.getInstance(i).hide(),On.getOrCreateInstance(e).toggle(this)})),R(On),m(On);const xn=".bs.offcanvas",kn=".data-api",Ln=`load${xn}${kn}`,Sn="show",Dn="showing",$n="hiding",In=".offcanvas.show",Nn=`show${xn}`,Pn=`shown${xn}`,Mn=`hide${xn}`,jn=`hidePrevented${xn}`,Fn=`hidden${xn}`,Hn=`resize${xn}`,Wn=`click${xn}${kn}`,Bn=`keydown.dismiss${xn}`,zn={backdrop:!0,keyboard:!0,scroll:!1},Rn={backdrop:"(boolean|string)",keyboard:"boolean",scroll:"boolean"};class qn extends W{constructor(t,e){super(t,e),this._isShown=!1,this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._addEventListeners()}static get Default(){return zn}static get DefaultType(){return Rn}static get NAME(){return"offcanvas"}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||N.trigger(this._element,Nn,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._backdrop.show(),this._config.scroll||(new cn).hide(),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.classList.add(Dn),this._queueCallback((()=>{this._config.scroll&&!this._config.backdrop||this._focustrap.activate(),this._element.classList.add(Sn),this._element.classList.remove(Dn),N.trigger(this._element,Pn,{relatedTarget:t})}),this._element,!0))}hide(){this._isShown&&(N.trigger(this._element,Mn).defaultPrevented||(this._focustrap.deactivate(),this._element.blur(),this._isShown=!1,this._element.classList.add($n),this._backdrop.hide(),this._queueCallback((()=>{this._element.classList.remove(Sn,$n),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._config.scroll||(new cn).reset(),N.trigger(this._element,Fn)}),this._element,!0)))}dispose(){this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}_initializeBackDrop(){const t=Boolean(this._config.backdrop);return new Ui({className:"offcanvas-backdrop",isVisible:t,isAnimated:!0,rootElement:this._element.parentNode,clickCallback:t?()=>{"static"!==this._config.backdrop?this.hide():N.trigger(this._element,jn)}:null})}_initializeFocusTrap(){return new sn({trapElement:this._element})}_addEventListeners(){N.on(this._element,Bn,(t=>{"Escape"===t.key&&(this._config.keyboard?this.hide():N.trigger(this._element,jn))}))}static jQueryInterface(t){return this.each((function(){const e=qn.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}N.on(document,Wn,'[data-bs-toggle="offcanvas"]',(function(t){const e=z.getElementFromSelector(this);if(["A","AREA"].includes(this.tagName)&&t.preventDefault(),l(this))return;N.one(e,Fn,(()=>{a(this)&&this.focus()}));const i=z.findOne(In);i&&i!==e&&qn.getInstance(i).hide(),qn.getOrCreateInstance(e).toggle(this)})),N.on(window,Ln,(()=>{for(const t of z.find(In))qn.getOrCreateInstance(t).show()})),N.on(window,Hn,(()=>{for(const t of z.find("[aria-modal][class*=show][class*=offcanvas-]"))"fixed"!==getComputedStyle(t).position&&qn.getOrCreateInstance(t).hide()})),R(qn),m(qn);const Vn={"*":["class","dir","id","lang","role",/^aria-[\w-]*$/i],a:["target","href","title","rel"],area:[],b:[],br:[],col:[],code:[],div:[],em:[],hr:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],i:[],img:["src","srcset","alt","title","width","height"],li:[],ol:[],p:[],pre:[],s:[],small:[],span:[],sub:[],sup:[],strong:[],u:[],ul:[]},Kn=new Set(["background","cite","href","itemtype","longdesc","poster","src","xlink:href"]),Qn=/^(?!javascript:)(?:[a-z0-9+.-]+:|[^&:/?#]*(?:[/?#]|$))/i,Xn=(t,e)=>{const i=t.nodeName.toLowerCase();return e.includes(i)?!Kn.has(i)||Boolean(Qn.test(t.nodeValue)):e.filter((t=>t instanceof RegExp)).some((t=>t.test(i)))},Yn={allowList:Vn,content:{},extraClass:"",html:!1,sanitize:!0,sanitizeFn:null,template:"
"},Un={allowList:"object",content:"object",extraClass:"(string|function)",html:"boolean",sanitize:"boolean",sanitizeFn:"(null|function)",template:"string"},Gn={entry:"(string|element|function|null)",selector:"(string|element)"};class Jn extends H{constructor(t){super(),this._config=this._getConfig(t)}static get Default(){return Yn}static get DefaultType(){return Un}static get NAME(){return"TemplateFactory"}getContent(){return Object.values(this._config.content).map((t=>this._resolvePossibleFunction(t))).filter(Boolean)}hasContent(){return this.getContent().length>0}changeContent(t){return this._checkContent(t),this._config.content={...this._config.content,...t},this}toHtml(){const t=document.createElement("div");t.innerHTML=this._maybeSanitize(this._config.template);for(const[e,i]of Object.entries(this._config.content))this._setContent(t,i,e);const e=t.children[0],i=this._resolvePossibleFunction(this._config.extraClass);return i&&e.classList.add(...i.split(" ")),e}_typeCheckConfig(t){super._typeCheckConfig(t),this._checkContent(t.content)}_checkContent(t){for(const[e,i]of Object.entries(t))super._typeCheckConfig({selector:e,entry:i},Gn)}_setContent(t,e,i){const n=z.findOne(i,t);n&&((e=this._resolvePossibleFunction(e))?o(e)?this._putElementInTemplate(r(e),n):this._config.html?n.innerHTML=this._maybeSanitize(e):n.textContent=e:n.remove())}_maybeSanitize(t){return this._config.sanitize?function(t,e,i){if(!t.length)return t;if(i&&"function"==typeof i)return i(t);const n=(new window.DOMParser).parseFromString(t,"text/html"),s=[].concat(...n.body.querySelectorAll("*"));for(const t of s){const i=t.nodeName.toLowerCase();if(!Object.keys(e).includes(i)){t.remove();continue}const n=[].concat(...t.attributes),s=[].concat(e["*"]||[],e[i]||[]);for(const e of n)Xn(e,s)||t.removeAttribute(e.nodeName)}return n.body.innerHTML}(t,this._config.allowList,this._config.sanitizeFn):t}_resolvePossibleFunction(t){return g(t,[this])}_putElementInTemplate(t,e){if(this._config.html)return e.innerHTML="",void e.append(t);e.textContent=t.textContent}}const Zn=new Set(["sanitize","allowList","sanitizeFn"]),ts="fade",es="show",is=".modal",ns="hide.bs.modal",ss="hover",os="focus",rs={AUTO:"auto",TOP:"top",RIGHT:p()?"left":"right",BOTTOM:"bottom",LEFT:p()?"right":"left"},as={allowList:Vn,animation:!0,boundary:"clippingParents",container:!1,customClass:"",delay:0,fallbackPlacements:["top","right","bottom","left"],html:!1,offset:[0,6],placement:"top",popperConfig:null,sanitize:!0,sanitizeFn:null,selector:!1,template:'',title:"",trigger:"hover focus"},ls={allowList:"object",animation:"boolean",boundary:"(string|element)",container:"(string|element|boolean)",customClass:"(string|function)",delay:"(number|object)",fallbackPlacements:"array",html:"boolean",offset:"(array|string|function)",placement:"(string|function)",popperConfig:"(null|object|function)",sanitize:"boolean",sanitizeFn:"(null|function)",selector:"(string|boolean)",template:"string",title:"(string|element|function)",trigger:"string"};class cs extends W{constructor(t,e){if(void 0===vi)throw new TypeError("Bootstrap's tooltips require Popper (https://popper.js.org)");super(t,e),this._isEnabled=!0,this._timeout=0,this._isHovered=null,this._activeTrigger={},this._popper=null,this._templateFactory=null,this._newContent=null,this.tip=null,this._setListeners(),this._config.selector||this._fixTitle()}static get Default(){return as}static get DefaultType(){return ls}static get NAME(){return"tooltip"}enable(){this._isEnabled=!0}disable(){this._isEnabled=!1}toggleEnabled(){this._isEnabled=!this._isEnabled}toggle(){this._isEnabled&&(this._activeTrigger.click=!this._activeTrigger.click,this._isShown()?this._leave():this._enter())}dispose(){clearTimeout(this._timeout),N.off(this._element.closest(is),ns,this._hideModalHandler),this._element.getAttribute("data-bs-original-title")&&this._element.setAttribute("title",this._element.getAttribute("data-bs-original-title")),this._disposePopper(),super.dispose()}show(){if("none"===this._element.style.display)throw new Error("Please use show on visible elements");if(!this._isWithContent()||!this._isEnabled)return;const t=N.trigger(this._element,this.constructor.eventName("show")),e=(c(this._element)||this._element.ownerDocument.documentElement).contains(this._element);if(t.defaultPrevented||!e)return;this._disposePopper();const i=this._getTipElement();this._element.setAttribute("aria-describedby",i.getAttribute("id"));const{container:n}=this._config;if(this._element.ownerDocument.documentElement.contains(this.tip)||(n.append(i),N.trigger(this._element,this.constructor.eventName("inserted"))),this._popper=this._createPopper(i),i.classList.add(es),"ontouchstart"in document.documentElement)for(const t of[].concat(...document.body.children))N.on(t,"mouseover",h);this._queueCallback((()=>{N.trigger(this._element,this.constructor.eventName("shown")),!1===this._isHovered&&this._leave(),this._isHovered=!1}),this.tip,this._isAnimated())}hide(){if(this._isShown()&&!N.trigger(this._element,this.constructor.eventName("hide")).defaultPrevented){if(this._getTipElement().classList.remove(es),"ontouchstart"in document.documentElement)for(const t of[].concat(...document.body.children))N.off(t,"mouseover",h);this._activeTrigger.click=!1,this._activeTrigger[os]=!1,this._activeTrigger[ss]=!1,this._isHovered=null,this._queueCallback((()=>{this._isWithActiveTrigger()||(this._isHovered||this._disposePopper(),this._element.removeAttribute("aria-describedby"),N.trigger(this._element,this.constructor.eventName("hidden")))}),this.tip,this._isAnimated())}}update(){this._popper&&this._popper.update()}_isWithContent(){return Boolean(this._getTitle())}_getTipElement(){return this.tip||(this.tip=this._createTipElement(this._newContent||this._getContentForTemplate())),this.tip}_createTipElement(t){const e=this._getTemplateFactory(t).toHtml();if(!e)return null;e.classList.remove(ts,es),e.classList.add(`bs-${this.constructor.NAME}-auto`);const i=(t=>{do{t+=Math.floor(1e6*Math.random())}while(document.getElementById(t));return t})(this.constructor.NAME).toString();return e.setAttribute("id",i),this._isAnimated()&&e.classList.add(ts),e}setContent(t){this._newContent=t,this._isShown()&&(this._disposePopper(),this.show())}_getTemplateFactory(t){return this._templateFactory?this._templateFactory.changeContent(t):this._templateFactory=new Jn({...this._config,content:t,extraClass:this._resolvePossibleFunction(this._config.customClass)}),this._templateFactory}_getContentForTemplate(){return{".tooltip-inner":this._getTitle()}}_getTitle(){return this._resolvePossibleFunction(this._config.title)||this._element.getAttribute("data-bs-original-title")}_initializeOnDelegatedTarget(t){return this.constructor.getOrCreateInstance(t.delegateTarget,this._getDelegateConfig())}_isAnimated(){return this._config.animation||this.tip&&this.tip.classList.contains(ts)}_isShown(){return this.tip&&this.tip.classList.contains(es)}_createPopper(t){const e=g(this._config.placement,[this,t,this._element]),i=rs[e.toUpperCase()];return bi(this._element,t,this._getPopperConfig(i))}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map((t=>Number.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_resolvePossibleFunction(t){return g(t,[this._element])}_getPopperConfig(t){const e={placement:t,modifiers:[{name:"flip",options:{fallbackPlacements:this._config.fallbackPlacements}},{name:"offset",options:{offset:this._getOffset()}},{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"arrow",options:{element:`.${this.constructor.NAME}-arrow`}},{name:"preSetPlacement",enabled:!0,phase:"beforeMain",fn:t=>{this._getTipElement().setAttribute("data-popper-placement",t.state.placement)}}]};return{...e,...g(this._config.popperConfig,[e])}}_setListeners(){const t=this._config.trigger.split(" ");for(const e of t)if("click"===e)N.on(this._element,this.constructor.eventName("click"),this._config.selector,(t=>{this._initializeOnDelegatedTarget(t).toggle()}));else if("manual"!==e){const t=e===ss?this.constructor.eventName("mouseenter"):this.constructor.eventName("focusin"),i=e===ss?this.constructor.eventName("mouseleave"):this.constructor.eventName("focusout");N.on(this._element,t,this._config.selector,(t=>{const e=this._initializeOnDelegatedTarget(t);e._activeTrigger["focusin"===t.type?os:ss]=!0,e._enter()})),N.on(this._element,i,this._config.selector,(t=>{const e=this._initializeOnDelegatedTarget(t);e._activeTrigger["focusout"===t.type?os:ss]=e._element.contains(t.relatedTarget),e._leave()}))}this._hideModalHandler=()=>{this._element&&this.hide()},N.on(this._element.closest(is),ns,this._hideModalHandler)}_fixTitle(){const t=this._element.getAttribute("title");t&&(this._element.getAttribute("aria-label")||this._element.textContent.trim()||this._element.setAttribute("aria-label",t),this._element.setAttribute("data-bs-original-title",t),this._element.removeAttribute("title"))}_enter(){this._isShown()||this._isHovered?this._isHovered=!0:(this._isHovered=!0,this._setTimeout((()=>{this._isHovered&&this.show()}),this._config.delay.show))}_leave(){this._isWithActiveTrigger()||(this._isHovered=!1,this._setTimeout((()=>{this._isHovered||this.hide()}),this._config.delay.hide))}_setTimeout(t,e){clearTimeout(this._timeout),this._timeout=setTimeout(t,e)}_isWithActiveTrigger(){return Object.values(this._activeTrigger).includes(!0)}_getConfig(t){const e=F.getDataAttributes(this._element);for(const t of Object.keys(e))Zn.has(t)&&delete e[t];return t={...e,..."object"==typeof t&&t?t:{}},t=this._mergeConfigObj(t),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}_configAfterMerge(t){return t.container=!1===t.container?document.body:r(t.container),"number"==typeof t.delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),t}_getDelegateConfig(){const t={};for(const[e,i]of Object.entries(this._config))this.constructor.Default[e]!==i&&(t[e]=i);return t.selector=!1,t.trigger="manual",t}_disposePopper(){this._popper&&(this._popper.destroy(),this._popper=null),this.tip&&(this.tip.remove(),this.tip=null)}static jQueryInterface(t){return this.each((function(){const e=cs.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}m(cs);const hs={...cs.Default,content:"",offset:[0,8],placement:"right",template:'',trigger:"click"},ds={...cs.DefaultType,content:"(null|string|element|function)"};class us extends cs{static get Default(){return hs}static get DefaultType(){return ds}static get NAME(){return"popover"}_isWithContent(){return this._getTitle()||this._getContent()}_getContentForTemplate(){return{".popover-header":this._getTitle(),".popover-body":this._getContent()}}_getContent(){return this._resolvePossibleFunction(this._config.content)}static jQueryInterface(t){return this.each((function(){const e=us.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}m(us);const fs=".bs.scrollspy",ps=`activate${fs}`,ms=`click${fs}`,gs=`load${fs}.data-api`,_s="active",bs="[href]",vs=".nav-link",ys=`${vs}, .nav-item > ${vs}, .list-group-item`,ws={offset:null,rootMargin:"0px 0px -25%",smoothScroll:!1,target:null,threshold:[.1,.5,1]},As={offset:"(number|null)",rootMargin:"string",smoothScroll:"boolean",target:"element",threshold:"array"};class Es extends W{constructor(t,e){super(t,e),this._targetLinks=new Map,this._observableSections=new Map,this._rootElement="visible"===getComputedStyle(this._element).overflowY?null:this._element,this._activeTarget=null,this._observer=null,this._previousScrollData={visibleEntryTop:0,parentScrollTop:0},this.refresh()}static get Default(){return ws}static get DefaultType(){return As}static get NAME(){return"scrollspy"}refresh(){this._initializeTargetsAndObservables(),this._maybeEnableSmoothScroll(),this._observer?this._observer.disconnect():this._observer=this._getNewObserver();for(const t of this._observableSections.values())this._observer.observe(t)}dispose(){this._observer.disconnect(),super.dispose()}_configAfterMerge(t){return t.target=r(t.target)||document.body,t.rootMargin=t.offset?`${t.offset}px 0px -30%`:t.rootMargin,"string"==typeof t.threshold&&(t.threshold=t.threshold.split(",").map((t=>Number.parseFloat(t)))),t}_maybeEnableSmoothScroll(){this._config.smoothScroll&&(N.off(this._config.target,ms),N.on(this._config.target,ms,bs,(t=>{const e=this._observableSections.get(t.target.hash);if(e){t.preventDefault();const i=this._rootElement||window,n=e.offsetTop-this._element.offsetTop;if(i.scrollTo)return void i.scrollTo({top:n,behavior:"smooth"});i.scrollTop=n}})))}_getNewObserver(){const t={root:this._rootElement,threshold:this._config.threshold,rootMargin:this._config.rootMargin};return new IntersectionObserver((t=>this._observerCallback(t)),t)}_observerCallback(t){const e=t=>this._targetLinks.get(`#${t.target.id}`),i=t=>{this._previousScrollData.visibleEntryTop=t.target.offsetTop,this._process(e(t))},n=(this._rootElement||document.documentElement).scrollTop,s=n>=this._previousScrollData.parentScrollTop;this._previousScrollData.parentScrollTop=n;for(const o of t){if(!o.isIntersecting){this._activeTarget=null,this._clearActiveClass(e(o));continue}const t=o.target.offsetTop>=this._previousScrollData.visibleEntryTop;if(s&&t){if(i(o),!n)return}else s||t||i(o)}}_initializeTargetsAndObservables(){this._targetLinks=new Map,this._observableSections=new Map;const t=z.find(bs,this._config.target);for(const e of t){if(!e.hash||l(e))continue;const t=z.findOne(decodeURI(e.hash),this._element);a(t)&&(this._targetLinks.set(decodeURI(e.hash),e),this._observableSections.set(e.hash,t))}}_process(t){this._activeTarget!==t&&(this._clearActiveClass(this._config.target),this._activeTarget=t,t.classList.add(_s),this._activateParents(t),N.trigger(this._element,ps,{relatedTarget:t}))}_activateParents(t){if(t.classList.contains("dropdown-item"))z.findOne(".dropdown-toggle",t.closest(".dropdown")).classList.add(_s);else for(const e of z.parents(t,".nav, .list-group"))for(const t of z.prev(e,ys))t.classList.add(_s)}_clearActiveClass(t){t.classList.remove(_s);const e=z.find(`${bs}.${_s}`,t);for(const t of e)t.classList.remove(_s)}static jQueryInterface(t){return this.each((function(){const e=Es.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}))}}N.on(window,gs,(()=>{for(const t of z.find('[data-bs-spy="scroll"]'))Es.getOrCreateInstance(t)})),m(Es);const Ts=".bs.tab",Cs=`hide${Ts}`,Os=`hidden${Ts}`,xs=`show${Ts}`,ks=`shown${Ts}`,Ls=`click${Ts}`,Ss=`keydown${Ts}`,Ds=`load${Ts}`,$s="ArrowLeft",Is="ArrowRight",Ns="ArrowUp",Ps="ArrowDown",Ms="Home",js="End",Fs="active",Hs="fade",Ws="show",Bs=":not(.dropdown-toggle)",zs='[data-bs-toggle="tab"], [data-bs-toggle="pill"], [data-bs-toggle="list"]',Rs=`.nav-link${Bs}, .list-group-item${Bs}, [role="tab"]${Bs}, ${zs}`,qs=`.${Fs}[data-bs-toggle="tab"], .${Fs}[data-bs-toggle="pill"], .${Fs}[data-bs-toggle="list"]`;class Vs extends W{constructor(t){super(t),this._parent=this._element.closest('.list-group, .nav, [role="tablist"]'),this._parent&&(this._setInitialAttributes(this._parent,this._getChildren()),N.on(this._element,Ss,(t=>this._keydown(t))))}static get NAME(){return"tab"}show(){const t=this._element;if(this._elemIsActive(t))return;const e=this._getActiveElem(),i=e?N.trigger(e,Cs,{relatedTarget:t}):null;N.trigger(t,xs,{relatedTarget:e}).defaultPrevented||i&&i.defaultPrevented||(this._deactivate(e,t),this._activate(t,e))}_activate(t,e){t&&(t.classList.add(Fs),this._activate(z.getElementFromSelector(t)),this._queueCallback((()=>{"tab"===t.getAttribute("role")?(t.removeAttribute("tabindex"),t.setAttribute("aria-selected",!0),this._toggleDropDown(t,!0),N.trigger(t,ks,{relatedTarget:e})):t.classList.add(Ws)}),t,t.classList.contains(Hs)))}_deactivate(t,e){t&&(t.classList.remove(Fs),t.blur(),this._deactivate(z.getElementFromSelector(t)),this._queueCallback((()=>{"tab"===t.getAttribute("role")?(t.setAttribute("aria-selected",!1),t.setAttribute("tabindex","-1"),this._toggleDropDown(t,!1),N.trigger(t,Os,{relatedTarget:e})):t.classList.remove(Ws)}),t,t.classList.contains(Hs)))}_keydown(t){if(![$s,Is,Ns,Ps,Ms,js].includes(t.key))return;t.stopPropagation(),t.preventDefault();const e=this._getChildren().filter((t=>!l(t)));let i;if([Ms,js].includes(t.key))i=e[t.key===Ms?0:e.length-1];else{const n=[Is,Ps].includes(t.key);i=b(e,t.target,n,!0)}i&&(i.focus({preventScroll:!0}),Vs.getOrCreateInstance(i).show())}_getChildren(){return z.find(Rs,this._parent)}_getActiveElem(){return this._getChildren().find((t=>this._elemIsActive(t)))||null}_setInitialAttributes(t,e){this._setAttributeIfNotExists(t,"role","tablist");for(const t of e)this._setInitialAttributesOnChild(t)}_setInitialAttributesOnChild(t){t=this._getInnerElement(t);const e=this._elemIsActive(t),i=this._getOuterElement(t);t.setAttribute("aria-selected",e),i!==t&&this._setAttributeIfNotExists(i,"role","presentation"),e||t.setAttribute("tabindex","-1"),this._setAttributeIfNotExists(t,"role","tab"),this._setInitialAttributesOnTargetPanel(t)}_setInitialAttributesOnTargetPanel(t){const e=z.getElementFromSelector(t);e&&(this._setAttributeIfNotExists(e,"role","tabpanel"),t.id&&this._setAttributeIfNotExists(e,"aria-labelledby",`${t.id}`))}_toggleDropDown(t,e){const i=this._getOuterElement(t);if(!i.classList.contains("dropdown"))return;const n=(t,n)=>{const s=z.findOne(t,i);s&&s.classList.toggle(n,e)};n(".dropdown-toggle",Fs),n(".dropdown-menu",Ws),i.setAttribute("aria-expanded",e)}_setAttributeIfNotExists(t,e,i){t.hasAttribute(e)||t.setAttribute(e,i)}_elemIsActive(t){return t.classList.contains(Fs)}_getInnerElement(t){return t.matches(Rs)?t:z.findOne(Rs,t)}_getOuterElement(t){return t.closest(".nav-item, .list-group-item")||t}static jQueryInterface(t){return this.each((function(){const e=Vs.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}))}}N.on(document,Ls,zs,(function(t){["A","AREA"].includes(this.tagName)&&t.preventDefault(),l(this)||Vs.getOrCreateInstance(this).show()})),N.on(window,Ds,(()=>{for(const t of z.find(qs))Vs.getOrCreateInstance(t)})),m(Vs);const Ks=".bs.toast",Qs=`mouseover${Ks}`,Xs=`mouseout${Ks}`,Ys=`focusin${Ks}`,Us=`focusout${Ks}`,Gs=`hide${Ks}`,Js=`hidden${Ks}`,Zs=`show${Ks}`,to=`shown${Ks}`,eo="hide",io="show",no="showing",so={animation:"boolean",autohide:"boolean",delay:"number"},oo={animation:!0,autohide:!0,delay:5e3};class ro extends W{constructor(t,e){super(t,e),this._timeout=null,this._hasMouseInteraction=!1,this._hasKeyboardInteraction=!1,this._setListeners()}static get Default(){return oo}static get DefaultType(){return so}static get NAME(){return"toast"}show(){N.trigger(this._element,Zs).defaultPrevented||(this._clearTimeout(),this._config.animation&&this._element.classList.add("fade"),this._element.classList.remove(eo),d(this._element),this._element.classList.add(io,no),this._queueCallback((()=>{this._element.classList.remove(no),N.trigger(this._element,to),this._maybeScheduleHide()}),this._element,this._config.animation))}hide(){this.isShown()&&(N.trigger(this._element,Gs).defaultPrevented||(this._element.classList.add(no),this._queueCallback((()=>{this._element.classList.add(eo),this._element.classList.remove(no,io),N.trigger(this._element,Js)}),this._element,this._config.animation)))}dispose(){this._clearTimeout(),this.isShown()&&this._element.classList.remove(io),super.dispose()}isShown(){return this._element.classList.contains(io)}_maybeScheduleHide(){this._config.autohide&&(this._hasMouseInteraction||this._hasKeyboardInteraction||(this._timeout=setTimeout((()=>{this.hide()}),this._config.delay)))}_onInteraction(t,e){switch(t.type){case"mouseover":case"mouseout":this._hasMouseInteraction=e;break;case"focusin":case"focusout":this._hasKeyboardInteraction=e}if(e)return void this._clearTimeout();const i=t.relatedTarget;this._element===i||this._element.contains(i)||this._maybeScheduleHide()}_setListeners(){N.on(this._element,Qs,(t=>this._onInteraction(t,!0))),N.on(this._element,Xs,(t=>this._onInteraction(t,!1))),N.on(this._element,Ys,(t=>this._onInteraction(t,!0))),N.on(this._element,Us,(t=>this._onInteraction(t,!1)))}_clearTimeout(){clearTimeout(this._timeout),this._timeout=null}static jQueryInterface(t){return this.each((function(){const e=ro.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}return R(ro),m(ro),{Alert:Q,Button:Y,Carousel:xt,Collapse:Bt,Dropdown:qi,Modal:On,Offcanvas:qn,Popover:us,ScrollSpy:Es,Tab:Vs,Toast:ro,Tooltip:cs}})); -//# sourceMappingURL=bootstrap.bundle.min.js.map \ No newline at end of file diff --git a/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/run_pecan_files/libs/clipboard/clipboard.min.js b/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/run_pecan_files/libs/clipboard/clipboard.min.js deleted file mode 100644 index 1103f811e..000000000 --- a/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/run_pecan_files/libs/clipboard/clipboard.min.js +++ /dev/null @@ -1,7 +0,0 @@ -/*! - * clipboard.js v2.0.11 - * https://clipboardjs.com/ - * - * Licensed MIT © Zeno Rocha - */ -!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ClipboardJS=e():t.ClipboardJS=e()}(this,function(){return n={686:function(t,e,n){"use strict";n.d(e,{default:function(){return b}});var e=n(279),i=n.n(e),e=n(370),u=n.n(e),e=n(817),r=n.n(e);function c(t){try{return document.execCommand(t)}catch(t){return}}var a=function(t){t=r()(t);return c("cut"),t};function o(t,e){var n,o,t=(n=t,o="rtl"===document.documentElement.getAttribute("dir"),(t=document.createElement("textarea")).style.fontSize="12pt",t.style.border="0",t.style.padding="0",t.style.margin="0",t.style.position="absolute",t.style[o?"right":"left"]="-9999px",o=window.pageYOffset||document.documentElement.scrollTop,t.style.top="".concat(o,"px"),t.setAttribute("readonly",""),t.value=n,t);return e.container.appendChild(t),e=r()(t),c("copy"),t.remove(),e}var f=function(t){var e=1.anchorjs-link,.anchorjs-link:focus{opacity:1}",A.sheet.cssRules.length),A.sheet.insertRule("[data-anchorjs-icon]::after{content:attr(data-anchorjs-icon)}",A.sheet.cssRules.length),A.sheet.insertRule('@font-face{font-family:anchorjs-icons;src:url(data:n/a;base64,AAEAAAALAIAAAwAwT1MvMg8yG2cAAAE4AAAAYGNtYXDp3gC3AAABpAAAAExnYXNwAAAAEAAAA9wAAAAIZ2x5ZlQCcfwAAAH4AAABCGhlYWQHFvHyAAAAvAAAADZoaGVhBnACFwAAAPQAAAAkaG10eASAADEAAAGYAAAADGxvY2EACACEAAAB8AAAAAhtYXhwAAYAVwAAARgAAAAgbmFtZQGOH9cAAAMAAAAAunBvc3QAAwAAAAADvAAAACAAAQAAAAEAAHzE2p9fDzz1AAkEAAAAAADRecUWAAAAANQA6R8AAAAAAoACwAAAAAgAAgAAAAAAAAABAAADwP/AAAACgAAA/9MCrQABAAAAAAAAAAAAAAAAAAAAAwABAAAAAwBVAAIAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAMCQAGQAAUAAAKZAswAAACPApkCzAAAAesAMwEJAAAAAAAAAAAAAAAAAAAAARAAAAAAAAAAAAAAAAAAAAAAQAAg//0DwP/AAEADwABAAAAAAQAAAAAAAAAAAAAAIAAAAAAAAAIAAAACgAAxAAAAAwAAAAMAAAAcAAEAAwAAABwAAwABAAAAHAAEADAAAAAIAAgAAgAAACDpy//9//8AAAAg6cv//f///+EWNwADAAEAAAAAAAAAAAAAAAAACACEAAEAAAAAAAAAAAAAAAAxAAACAAQARAKAAsAAKwBUAAABIiYnJjQ3NzY2MzIWFxYUBwcGIicmNDc3NjQnJiYjIgYHBwYUFxYUBwYGIwciJicmNDc3NjIXFhQHBwYUFxYWMzI2Nzc2NCcmNDc2MhcWFAcHBgYjARQGDAUtLXoWOR8fORYtLTgKGwoKCjgaGg0gEhIgDXoaGgkJBQwHdR85Fi0tOAobCgoKOBoaDSASEiANehoaCQkKGwotLXoWOR8BMwUFLYEuehYXFxYugC44CQkKGwo4GkoaDQ0NDXoaShoKGwoFBe8XFi6ALjgJCQobCjgaShoNDQ0NehpKGgobCgoKLYEuehYXAAAADACWAAEAAAAAAAEACAAAAAEAAAAAAAIAAwAIAAEAAAAAAAMACAAAAAEAAAAAAAQACAAAAAEAAAAAAAUAAQALAAEAAAAAAAYACAAAAAMAAQQJAAEAEAAMAAMAAQQJAAIABgAcAAMAAQQJAAMAEAAMAAMAAQQJAAQAEAAMAAMAAQQJAAUAAgAiAAMAAQQJAAYAEAAMYW5jaG9yanM0MDBAAGEAbgBjAGgAbwByAGoAcwA0ADAAMABAAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAH//wAP) format("truetype")}',A.sheet.cssRules.length)),h=document.querySelectorAll("[id]"),t=[].map.call(h,function(A){return A.id}),i=0;i\]./()*\\\n\t\b\v\u00A0]/g,"-").replace(/-{2,}/g,"-").substring(0,this.options.truncate).replace(/^-+|-+$/gm,"").toLowerCase()},this.hasAnchorJSLink=function(A){var e=A.firstChild&&-1<(" "+A.firstChild.className+" ").indexOf(" anchorjs-link "),A=A.lastChild&&-1<(" "+A.lastChild.className+" ").indexOf(" anchorjs-link ");return e||A||!1}}}); -// @license-end \ No newline at end of file diff --git a/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/run_pecan_files/libs/quarto-html/popper.min.js b/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/run_pecan_files/libs/quarto-html/popper.min.js deleted file mode 100644 index e3726d728..000000000 --- a/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/run_pecan_files/libs/quarto-html/popper.min.js +++ /dev/null @@ -1,6 +0,0 @@ -/** - * @popperjs/core v2.11.7 - MIT License - */ - -!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).Popper={})}(this,(function(e){"use strict";function t(e){if(null==e)return window;if("[object Window]"!==e.toString()){var t=e.ownerDocument;return t&&t.defaultView||window}return e}function n(e){return e instanceof t(e).Element||e instanceof Element}function r(e){return e instanceof t(e).HTMLElement||e instanceof HTMLElement}function o(e){return"undefined"!=typeof ShadowRoot&&(e instanceof t(e).ShadowRoot||e instanceof ShadowRoot)}var i=Math.max,a=Math.min,s=Math.round;function f(){var e=navigator.userAgentData;return null!=e&&e.brands&&Array.isArray(e.brands)?e.brands.map((function(e){return e.brand+"/"+e.version})).join(" "):navigator.userAgent}function c(){return!/^((?!chrome|android).)*safari/i.test(f())}function p(e,o,i){void 0===o&&(o=!1),void 0===i&&(i=!1);var a=e.getBoundingClientRect(),f=1,p=1;o&&r(e)&&(f=e.offsetWidth>0&&s(a.width)/e.offsetWidth||1,p=e.offsetHeight>0&&s(a.height)/e.offsetHeight||1);var u=(n(e)?t(e):window).visualViewport,l=!c()&&i,d=(a.left+(l&&u?u.offsetLeft:0))/f,h=(a.top+(l&&u?u.offsetTop:0))/p,m=a.width/f,v=a.height/p;return{width:m,height:v,top:h,right:d+m,bottom:h+v,left:d,x:d,y:h}}function u(e){var n=t(e);return{scrollLeft:n.pageXOffset,scrollTop:n.pageYOffset}}function l(e){return e?(e.nodeName||"").toLowerCase():null}function d(e){return((n(e)?e.ownerDocument:e.document)||window.document).documentElement}function h(e){return p(d(e)).left+u(e).scrollLeft}function m(e){return t(e).getComputedStyle(e)}function v(e){var t=m(e),n=t.overflow,r=t.overflowX,o=t.overflowY;return/auto|scroll|overlay|hidden/.test(n+o+r)}function y(e,n,o){void 0===o&&(o=!1);var i,a,f=r(n),c=r(n)&&function(e){var t=e.getBoundingClientRect(),n=s(t.width)/e.offsetWidth||1,r=s(t.height)/e.offsetHeight||1;return 1!==n||1!==r}(n),m=d(n),y=p(e,c,o),g={scrollLeft:0,scrollTop:0},b={x:0,y:0};return(f||!f&&!o)&&(("body"!==l(n)||v(m))&&(g=(i=n)!==t(i)&&r(i)?{scrollLeft:(a=i).scrollLeft,scrollTop:a.scrollTop}:u(i)),r(n)?((b=p(n,!0)).x+=n.clientLeft,b.y+=n.clientTop):m&&(b.x=h(m))),{x:y.left+g.scrollLeft-b.x,y:y.top+g.scrollTop-b.y,width:y.width,height:y.height}}function g(e){var t=p(e),n=e.offsetWidth,r=e.offsetHeight;return Math.abs(t.width-n)<=1&&(n=t.width),Math.abs(t.height-r)<=1&&(r=t.height),{x:e.offsetLeft,y:e.offsetTop,width:n,height:r}}function b(e){return"html"===l(e)?e:e.assignedSlot||e.parentNode||(o(e)?e.host:null)||d(e)}function x(e){return["html","body","#document"].indexOf(l(e))>=0?e.ownerDocument.body:r(e)&&v(e)?e:x(b(e))}function w(e,n){var r;void 0===n&&(n=[]);var o=x(e),i=o===(null==(r=e.ownerDocument)?void 0:r.body),a=t(o),s=i?[a].concat(a.visualViewport||[],v(o)?o:[]):o,f=n.concat(s);return i?f:f.concat(w(b(s)))}function O(e){return["table","td","th"].indexOf(l(e))>=0}function j(e){return r(e)&&"fixed"!==m(e).position?e.offsetParent:null}function E(e){for(var n=t(e),i=j(e);i&&O(i)&&"static"===m(i).position;)i=j(i);return i&&("html"===l(i)||"body"===l(i)&&"static"===m(i).position)?n:i||function(e){var t=/firefox/i.test(f());if(/Trident/i.test(f())&&r(e)&&"fixed"===m(e).position)return null;var n=b(e);for(o(n)&&(n=n.host);r(n)&&["html","body"].indexOf(l(n))<0;){var i=m(n);if("none"!==i.transform||"none"!==i.perspective||"paint"===i.contain||-1!==["transform","perspective"].indexOf(i.willChange)||t&&"filter"===i.willChange||t&&i.filter&&"none"!==i.filter)return n;n=n.parentNode}return null}(e)||n}var D="top",A="bottom",L="right",P="left",M="auto",k=[D,A,L,P],W="start",B="end",H="viewport",T="popper",R=k.reduce((function(e,t){return e.concat([t+"-"+W,t+"-"+B])}),[]),S=[].concat(k,[M]).reduce((function(e,t){return e.concat([t,t+"-"+W,t+"-"+B])}),[]),V=["beforeRead","read","afterRead","beforeMain","main","afterMain","beforeWrite","write","afterWrite"];function q(e){var t=new Map,n=new Set,r=[];function o(e){n.add(e.name),[].concat(e.requires||[],e.requiresIfExists||[]).forEach((function(e){if(!n.has(e)){var r=t.get(e);r&&o(r)}})),r.push(e)}return e.forEach((function(e){t.set(e.name,e)})),e.forEach((function(e){n.has(e.name)||o(e)})),r}function C(e){return e.split("-")[0]}function N(e,t){var n=t.getRootNode&&t.getRootNode();if(e.contains(t))return!0;if(n&&o(n)){var r=t;do{if(r&&e.isSameNode(r))return!0;r=r.parentNode||r.host}while(r)}return!1}function I(e){return Object.assign({},e,{left:e.x,top:e.y,right:e.x+e.width,bottom:e.y+e.height})}function _(e,r,o){return r===H?I(function(e,n){var r=t(e),o=d(e),i=r.visualViewport,a=o.clientWidth,s=o.clientHeight,f=0,p=0;if(i){a=i.width,s=i.height;var u=c();(u||!u&&"fixed"===n)&&(f=i.offsetLeft,p=i.offsetTop)}return{width:a,height:s,x:f+h(e),y:p}}(e,o)):n(r)?function(e,t){var n=p(e,!1,"fixed"===t);return n.top=n.top+e.clientTop,n.left=n.left+e.clientLeft,n.bottom=n.top+e.clientHeight,n.right=n.left+e.clientWidth,n.width=e.clientWidth,n.height=e.clientHeight,n.x=n.left,n.y=n.top,n}(r,o):I(function(e){var t,n=d(e),r=u(e),o=null==(t=e.ownerDocument)?void 0:t.body,a=i(n.scrollWidth,n.clientWidth,o?o.scrollWidth:0,o?o.clientWidth:0),s=i(n.scrollHeight,n.clientHeight,o?o.scrollHeight:0,o?o.clientHeight:0),f=-r.scrollLeft+h(e),c=-r.scrollTop;return"rtl"===m(o||n).direction&&(f+=i(n.clientWidth,o?o.clientWidth:0)-a),{width:a,height:s,x:f,y:c}}(d(e)))}function F(e,t,o,s){var f="clippingParents"===t?function(e){var t=w(b(e)),o=["absolute","fixed"].indexOf(m(e).position)>=0&&r(e)?E(e):e;return n(o)?t.filter((function(e){return n(e)&&N(e,o)&&"body"!==l(e)})):[]}(e):[].concat(t),c=[].concat(f,[o]),p=c[0],u=c.reduce((function(t,n){var r=_(e,n,s);return t.top=i(r.top,t.top),t.right=a(r.right,t.right),t.bottom=a(r.bottom,t.bottom),t.left=i(r.left,t.left),t}),_(e,p,s));return u.width=u.right-u.left,u.height=u.bottom-u.top,u.x=u.left,u.y=u.top,u}function U(e){return e.split("-")[1]}function z(e){return["top","bottom"].indexOf(e)>=0?"x":"y"}function X(e){var t,n=e.reference,r=e.element,o=e.placement,i=o?C(o):null,a=o?U(o):null,s=n.x+n.width/2-r.width/2,f=n.y+n.height/2-r.height/2;switch(i){case D:t={x:s,y:n.y-r.height};break;case A:t={x:s,y:n.y+n.height};break;case L:t={x:n.x+n.width,y:f};break;case P:t={x:n.x-r.width,y:f};break;default:t={x:n.x,y:n.y}}var c=i?z(i):null;if(null!=c){var p="y"===c?"height":"width";switch(a){case W:t[c]=t[c]-(n[p]/2-r[p]/2);break;case B:t[c]=t[c]+(n[p]/2-r[p]/2)}}return t}function Y(e){return Object.assign({},{top:0,right:0,bottom:0,left:0},e)}function G(e,t){return t.reduce((function(t,n){return t[n]=e,t}),{})}function J(e,t){void 0===t&&(t={});var r=t,o=r.placement,i=void 0===o?e.placement:o,a=r.strategy,s=void 0===a?e.strategy:a,f=r.boundary,c=void 0===f?"clippingParents":f,u=r.rootBoundary,l=void 0===u?H:u,h=r.elementContext,m=void 0===h?T:h,v=r.altBoundary,y=void 0!==v&&v,g=r.padding,b=void 0===g?0:g,x=Y("number"!=typeof b?b:G(b,k)),w=m===T?"reference":T,O=e.rects.popper,j=e.elements[y?w:m],E=F(n(j)?j:j.contextElement||d(e.elements.popper),c,l,s),P=p(e.elements.reference),M=X({reference:P,element:O,strategy:"absolute",placement:i}),W=I(Object.assign({},O,M)),B=m===T?W:P,R={top:E.top-B.top+x.top,bottom:B.bottom-E.bottom+x.bottom,left:E.left-B.left+x.left,right:B.right-E.right+x.right},S=e.modifiersData.offset;if(m===T&&S){var V=S[i];Object.keys(R).forEach((function(e){var t=[L,A].indexOf(e)>=0?1:-1,n=[D,A].indexOf(e)>=0?"y":"x";R[e]+=V[n]*t}))}return R}var K={placement:"bottom",modifiers:[],strategy:"absolute"};function Q(){for(var e=arguments.length,t=new Array(e),n=0;n=0?-1:1,i="function"==typeof n?n(Object.assign({},t,{placement:e})):n,a=i[0],s=i[1];return a=a||0,s=(s||0)*o,[P,L].indexOf(r)>=0?{x:s,y:a}:{x:a,y:s}}(n,t.rects,i),e}),{}),s=a[t.placement],f=s.x,c=s.y;null!=t.modifiersData.popperOffsets&&(t.modifiersData.popperOffsets.x+=f,t.modifiersData.popperOffsets.y+=c),t.modifiersData[r]=a}},se={left:"right",right:"left",bottom:"top",top:"bottom"};function fe(e){return e.replace(/left|right|bottom|top/g,(function(e){return se[e]}))}var ce={start:"end",end:"start"};function pe(e){return e.replace(/start|end/g,(function(e){return ce[e]}))}function ue(e,t){void 0===t&&(t={});var n=t,r=n.placement,o=n.boundary,i=n.rootBoundary,a=n.padding,s=n.flipVariations,f=n.allowedAutoPlacements,c=void 0===f?S:f,p=U(r),u=p?s?R:R.filter((function(e){return U(e)===p})):k,l=u.filter((function(e){return c.indexOf(e)>=0}));0===l.length&&(l=u);var d=l.reduce((function(t,n){return t[n]=J(e,{placement:n,boundary:o,rootBoundary:i,padding:a})[C(n)],t}),{});return Object.keys(d).sort((function(e,t){return d[e]-d[t]}))}var le={name:"flip",enabled:!0,phase:"main",fn:function(e){var t=e.state,n=e.options,r=e.name;if(!t.modifiersData[r]._skip){for(var o=n.mainAxis,i=void 0===o||o,a=n.altAxis,s=void 0===a||a,f=n.fallbackPlacements,c=n.padding,p=n.boundary,u=n.rootBoundary,l=n.altBoundary,d=n.flipVariations,h=void 0===d||d,m=n.allowedAutoPlacements,v=t.options.placement,y=C(v),g=f||(y===v||!h?[fe(v)]:function(e){if(C(e)===M)return[];var t=fe(e);return[pe(e),t,pe(t)]}(v)),b=[v].concat(g).reduce((function(e,n){return e.concat(C(n)===M?ue(t,{placement:n,boundary:p,rootBoundary:u,padding:c,flipVariations:h,allowedAutoPlacements:m}):n)}),[]),x=t.rects.reference,w=t.rects.popper,O=new Map,j=!0,E=b[0],k=0;k=0,S=R?"width":"height",V=J(t,{placement:B,boundary:p,rootBoundary:u,altBoundary:l,padding:c}),q=R?T?L:P:T?A:D;x[S]>w[S]&&(q=fe(q));var N=fe(q),I=[];if(i&&I.push(V[H]<=0),s&&I.push(V[q]<=0,V[N]<=0),I.every((function(e){return e}))){E=B,j=!1;break}O.set(B,I)}if(j)for(var _=function(e){var t=b.find((function(t){var n=O.get(t);if(n)return n.slice(0,e).every((function(e){return e}))}));if(t)return E=t,"break"},F=h?3:1;F>0;F--){if("break"===_(F))break}t.placement!==E&&(t.modifiersData[r]._skip=!0,t.placement=E,t.reset=!0)}},requiresIfExists:["offset"],data:{_skip:!1}};function de(e,t,n){return i(e,a(t,n))}var he={name:"preventOverflow",enabled:!0,phase:"main",fn:function(e){var t=e.state,n=e.options,r=e.name,o=n.mainAxis,s=void 0===o||o,f=n.altAxis,c=void 0!==f&&f,p=n.boundary,u=n.rootBoundary,l=n.altBoundary,d=n.padding,h=n.tether,m=void 0===h||h,v=n.tetherOffset,y=void 0===v?0:v,b=J(t,{boundary:p,rootBoundary:u,padding:d,altBoundary:l}),x=C(t.placement),w=U(t.placement),O=!w,j=z(x),M="x"===j?"y":"x",k=t.modifiersData.popperOffsets,B=t.rects.reference,H=t.rects.popper,T="function"==typeof y?y(Object.assign({},t.rects,{placement:t.placement})):y,R="number"==typeof T?{mainAxis:T,altAxis:T}:Object.assign({mainAxis:0,altAxis:0},T),S=t.modifiersData.offset?t.modifiersData.offset[t.placement]:null,V={x:0,y:0};if(k){if(s){var q,N="y"===j?D:P,I="y"===j?A:L,_="y"===j?"height":"width",F=k[j],X=F+b[N],Y=F-b[I],G=m?-H[_]/2:0,K=w===W?B[_]:H[_],Q=w===W?-H[_]:-B[_],Z=t.elements.arrow,$=m&&Z?g(Z):{width:0,height:0},ee=t.modifiersData["arrow#persistent"]?t.modifiersData["arrow#persistent"].padding:{top:0,right:0,bottom:0,left:0},te=ee[N],ne=ee[I],re=de(0,B[_],$[_]),oe=O?B[_]/2-G-re-te-R.mainAxis:K-re-te-R.mainAxis,ie=O?-B[_]/2+G+re+ne+R.mainAxis:Q+re+ne+R.mainAxis,ae=t.elements.arrow&&E(t.elements.arrow),se=ae?"y"===j?ae.clientTop||0:ae.clientLeft||0:0,fe=null!=(q=null==S?void 0:S[j])?q:0,ce=F+ie-fe,pe=de(m?a(X,F+oe-fe-se):X,F,m?i(Y,ce):Y);k[j]=pe,V[j]=pe-F}if(c){var ue,le="x"===j?D:P,he="x"===j?A:L,me=k[M],ve="y"===M?"height":"width",ye=me+b[le],ge=me-b[he],be=-1!==[D,P].indexOf(x),xe=null!=(ue=null==S?void 0:S[M])?ue:0,we=be?ye:me-B[ve]-H[ve]-xe+R.altAxis,Oe=be?me+B[ve]+H[ve]-xe-R.altAxis:ge,je=m&&be?function(e,t,n){var r=de(e,t,n);return r>n?n:r}(we,me,Oe):de(m?we:ye,me,m?Oe:ge);k[M]=je,V[M]=je-me}t.modifiersData[r]=V}},requiresIfExists:["offset"]};var me={name:"arrow",enabled:!0,phase:"main",fn:function(e){var t,n=e.state,r=e.name,o=e.options,i=n.elements.arrow,a=n.modifiersData.popperOffsets,s=C(n.placement),f=z(s),c=[P,L].indexOf(s)>=0?"height":"width";if(i&&a){var p=function(e,t){return Y("number"!=typeof(e="function"==typeof e?e(Object.assign({},t.rects,{placement:t.placement})):e)?e:G(e,k))}(o.padding,n),u=g(i),l="y"===f?D:P,d="y"===f?A:L,h=n.rects.reference[c]+n.rects.reference[f]-a[f]-n.rects.popper[c],m=a[f]-n.rects.reference[f],v=E(i),y=v?"y"===f?v.clientHeight||0:v.clientWidth||0:0,b=h/2-m/2,x=p[l],w=y-u[c]-p[d],O=y/2-u[c]/2+b,j=de(x,O,w),M=f;n.modifiersData[r]=((t={})[M]=j,t.centerOffset=j-O,t)}},effect:function(e){var t=e.state,n=e.options.element,r=void 0===n?"[data-popper-arrow]":n;null!=r&&("string"!=typeof r||(r=t.elements.popper.querySelector(r)))&&N(t.elements.popper,r)&&(t.elements.arrow=r)},requires:["popperOffsets"],requiresIfExists:["preventOverflow"]};function ve(e,t,n){return void 0===n&&(n={x:0,y:0}),{top:e.top-t.height-n.y,right:e.right-t.width+n.x,bottom:e.bottom-t.height+n.y,left:e.left-t.width-n.x}}function ye(e){return[D,L,A,P].some((function(t){return e[t]>=0}))}var ge={name:"hide",enabled:!0,phase:"main",requiresIfExists:["preventOverflow"],fn:function(e){var t=e.state,n=e.name,r=t.rects.reference,o=t.rects.popper,i=t.modifiersData.preventOverflow,a=J(t,{elementContext:"reference"}),s=J(t,{altBoundary:!0}),f=ve(a,r),c=ve(s,o,i),p=ye(f),u=ye(c);t.modifiersData[n]={referenceClippingOffsets:f,popperEscapeOffsets:c,isReferenceHidden:p,hasPopperEscaped:u},t.attributes.popper=Object.assign({},t.attributes.popper,{"data-popper-reference-hidden":p,"data-popper-escaped":u})}},be=Z({defaultModifiers:[ee,te,oe,ie]}),xe=[ee,te,oe,ie,ae,le,he,me,ge],we=Z({defaultModifiers:xe});e.applyStyles=ie,e.arrow=me,e.computeStyles=oe,e.createPopper=we,e.createPopperLite=be,e.defaultModifiers=xe,e.detectOverflow=J,e.eventListeners=ee,e.flip=le,e.hide=ge,e.offset=ae,e.popperGenerator=Z,e.popperOffsets=te,e.preventOverflow=he,Object.defineProperty(e,"__esModule",{value:!0})})); - diff --git a/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/run_pecan_files/libs/quarto-html/quarto-syntax-highlighting.css b/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/run_pecan_files/libs/quarto-html/quarto-syntax-highlighting.css deleted file mode 100644 index b30ce5766..000000000 --- a/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/run_pecan_files/libs/quarto-html/quarto-syntax-highlighting.css +++ /dev/null @@ -1,205 +0,0 @@ -/* quarto syntax highlight colors */ -:root { - --quarto-hl-ot-color: #003B4F; - --quarto-hl-at-color: #657422; - --quarto-hl-ss-color: #20794D; - --quarto-hl-an-color: #5E5E5E; - --quarto-hl-fu-color: #4758AB; - --quarto-hl-st-color: #20794D; - --quarto-hl-cf-color: #003B4F; - --quarto-hl-op-color: #5E5E5E; - --quarto-hl-er-color: #AD0000; - --quarto-hl-bn-color: #AD0000; - --quarto-hl-al-color: #AD0000; - --quarto-hl-va-color: #111111; - --quarto-hl-bu-color: inherit; - --quarto-hl-ex-color: inherit; - --quarto-hl-pp-color: #AD0000; - --quarto-hl-in-color: #5E5E5E; - --quarto-hl-vs-color: #20794D; - --quarto-hl-wa-color: #5E5E5E; - --quarto-hl-do-color: #5E5E5E; - --quarto-hl-im-color: #00769E; - --quarto-hl-ch-color: #20794D; - --quarto-hl-dt-color: #AD0000; - --quarto-hl-fl-color: #AD0000; - --quarto-hl-co-color: #5E5E5E; - --quarto-hl-cv-color: #5E5E5E; - --quarto-hl-cn-color: #8f5902; - --quarto-hl-sc-color: #5E5E5E; - --quarto-hl-dv-color: #AD0000; - --quarto-hl-kw-color: #003B4F; -} - -/* other quarto variables */ -:root { - --quarto-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; -} - -pre > code.sourceCode > span { - color: #003B4F; -} - -code span { - color: #003B4F; -} - -code.sourceCode > span { - color: #003B4F; -} - -div.sourceCode, -div.sourceCode pre.sourceCode { - color: #003B4F; -} - -code span.ot { - color: #003B4F; - font-style: inherit; -} - -code span.at { - color: #657422; - font-style: inherit; -} - -code span.ss { - color: #20794D; - font-style: inherit; -} - -code span.an { - color: #5E5E5E; - font-style: inherit; -} - -code span.fu { - color: #4758AB; - font-style: inherit; -} - -code span.st { - color: #20794D; - font-style: inherit; -} - -code span.cf { - color: #003B4F; - font-weight: bold; - font-style: inherit; -} - -code span.op { - color: #5E5E5E; - font-style: inherit; -} - -code span.er { - color: #AD0000; - font-style: inherit; -} - -code span.bn { - color: #AD0000; - font-style: inherit; -} - -code span.al { - color: #AD0000; - font-style: inherit; -} - -code span.va { - color: #111111; - font-style: inherit; -} - -code span.bu { - font-style: inherit; -} - -code span.ex { - font-style: inherit; -} - -code span.pp { - color: #AD0000; - font-style: inherit; -} - -code span.in { - color: #5E5E5E; - font-style: inherit; -} - -code span.vs { - color: #20794D; - font-style: inherit; -} - -code span.wa { - color: #5E5E5E; - font-style: italic; -} - -code span.do { - color: #5E5E5E; - font-style: italic; -} - -code span.im { - color: #00769E; - font-style: inherit; -} - -code span.ch { - color: #20794D; - font-style: inherit; -} - -code span.dt { - color: #AD0000; - font-style: inherit; -} - -code span.fl { - color: #AD0000; - font-style: inherit; -} - -code span.co { - color: #5E5E5E; - font-style: inherit; -} - -code span.cv { - color: #5E5E5E; - font-style: italic; -} - -code span.cn { - color: #8f5902; - font-style: inherit; -} - -code span.sc { - color: #5E5E5E; - font-style: inherit; -} - -code span.dv { - color: #AD0000; - font-style: inherit; -} - -code span.kw { - color: #003B4F; - font-weight: bold; - font-style: inherit; -} - -.prevent-inlining { - content: " { - // Find any conflicting margin elements and add margins to the - // top to prevent overlap - const marginChildren = window.document.querySelectorAll( - ".column-margin.column-container > *, .margin-caption, .aside" - ); - - let lastBottom = 0; - for (const marginChild of marginChildren) { - if (marginChild.offsetParent !== null) { - // clear the top margin so we recompute it - marginChild.style.marginTop = null; - const top = marginChild.getBoundingClientRect().top + window.scrollY; - if (top < lastBottom) { - const marginChildStyle = window.getComputedStyle(marginChild); - const marginBottom = parseFloat(marginChildStyle["marginBottom"]); - const margin = lastBottom - top + marginBottom; - marginChild.style.marginTop = `${margin}px`; - } - const styles = window.getComputedStyle(marginChild); - const marginTop = parseFloat(styles["marginTop"]); - lastBottom = top + marginChild.getBoundingClientRect().height + marginTop; - } - } -}; - -window.document.addEventListener("DOMContentLoaded", function (_event) { - // Recompute the position of margin elements anytime the body size changes - if (window.ResizeObserver) { - const resizeObserver = new window.ResizeObserver( - throttle(() => { - layoutMarginEls(); - if ( - window.document.body.getBoundingClientRect().width < 990 && - isReaderMode() - ) { - quartoToggleReader(); - } - }, 50) - ); - resizeObserver.observe(window.document.body); - } - - const tocEl = window.document.querySelector('nav.toc-active[role="doc-toc"]'); - const sidebarEl = window.document.getElementById("quarto-sidebar"); - const leftTocEl = window.document.getElementById("quarto-sidebar-toc-left"); - const marginSidebarEl = window.document.getElementById( - "quarto-margin-sidebar" - ); - // function to determine whether the element has a previous sibling that is active - const prevSiblingIsActiveLink = (el) => { - const sibling = el.previousElementSibling; - if (sibling && sibling.tagName === "A") { - return sibling.classList.contains("active"); - } else { - return false; - } - }; - - // fire slideEnter for bootstrap tab activations (for htmlwidget resize behavior) - function fireSlideEnter(e) { - const event = window.document.createEvent("Event"); - event.initEvent("slideenter", true, true); - window.document.dispatchEvent(event); - } - const tabs = window.document.querySelectorAll('a[data-bs-toggle="tab"]'); - tabs.forEach((tab) => { - tab.addEventListener("shown.bs.tab", fireSlideEnter); - }); - - // fire slideEnter for tabby tab activations (for htmlwidget resize behavior) - document.addEventListener("tabby", fireSlideEnter, false); - - // Track scrolling and mark TOC links as active - // get table of contents and sidebar (bail if we don't have at least one) - const tocLinks = tocEl - ? [...tocEl.querySelectorAll("a[data-scroll-target]")] - : []; - const makeActive = (link) => tocLinks[link].classList.add("active"); - const removeActive = (link) => tocLinks[link].classList.remove("active"); - const removeAllActive = () => - [...Array(tocLinks.length).keys()].forEach((link) => removeActive(link)); - - // activate the anchor for a section associated with this TOC entry - tocLinks.forEach((link) => { - link.addEventListener("click", () => { - if (link.href.indexOf("#") !== -1) { - const anchor = link.href.split("#")[1]; - const heading = window.document.querySelector( - `[data-anchor-id="${anchor}"]` - ); - if (heading) { - // Add the class - heading.classList.add("reveal-anchorjs-link"); - - // function to show the anchor - const handleMouseout = () => { - heading.classList.remove("reveal-anchorjs-link"); - heading.removeEventListener("mouseout", handleMouseout); - }; - - // add a function to clear the anchor when the user mouses out of it - heading.addEventListener("mouseout", handleMouseout); - } - } - }); - }); - - const sections = tocLinks.map((link) => { - const target = link.getAttribute("data-scroll-target"); - if (target.startsWith("#")) { - return window.document.getElementById(decodeURI(`${target.slice(1)}`)); - } else { - return window.document.querySelector(decodeURI(`${target}`)); - } - }); - - const sectionMargin = 200; - let currentActive = 0; - // track whether we've initialized state the first time - let init = false; - - const updateActiveLink = () => { - // The index from bottom to top (e.g. reversed list) - let sectionIndex = -1; - if ( - window.innerHeight + window.pageYOffset >= - window.document.body.offsetHeight - ) { - // This is the no-scroll case where last section should be the active one - sectionIndex = 0; - } else { - // This finds the last section visible on screen that should be made active - sectionIndex = [...sections].reverse().findIndex((section) => { - if (section) { - return window.pageYOffset >= section.offsetTop - sectionMargin; - } else { - return false; - } - }); - } - if (sectionIndex > -1) { - const current = sections.length - sectionIndex - 1; - if (current !== currentActive) { - removeAllActive(); - currentActive = current; - makeActive(current); - if (init) { - window.dispatchEvent(sectionChanged); - } - init = true; - } - } - }; - - const inHiddenRegion = (top, bottom, hiddenRegions) => { - for (const region of hiddenRegions) { - if (top <= region.bottom && bottom >= region.top) { - return true; - } - } - return false; - }; - - const categorySelector = "header.quarto-title-block .quarto-category"; - const activateCategories = (href) => { - // Find any categories - // Surround them with a link pointing back to: - // #category=Authoring - try { - const categoryEls = window.document.querySelectorAll(categorySelector); - for (const categoryEl of categoryEls) { - const categoryText = categoryEl.textContent; - if (categoryText) { - const link = `${href}#category=${encodeURIComponent(categoryText)}`; - const linkEl = window.document.createElement("a"); - linkEl.setAttribute("href", link); - for (const child of categoryEl.childNodes) { - linkEl.append(child); - } - categoryEl.appendChild(linkEl); - } - } - } catch { - // Ignore errors - } - }; - function hasTitleCategories() { - return window.document.querySelector(categorySelector) !== null; - } - - function offsetRelativeUrl(url) { - const offset = getMeta("quarto:offset"); - return offset ? offset + url : url; - } - - function offsetAbsoluteUrl(url) { - const offset = getMeta("quarto:offset"); - const baseUrl = new URL(offset, window.location); - - const projRelativeUrl = url.replace(baseUrl, ""); - if (projRelativeUrl.startsWith("/")) { - return projRelativeUrl; - } else { - return "/" + projRelativeUrl; - } - } - - // read a meta tag value - function getMeta(metaName) { - const metas = window.document.getElementsByTagName("meta"); - for (let i = 0; i < metas.length; i++) { - if (metas[i].getAttribute("name") === metaName) { - return metas[i].getAttribute("content"); - } - } - return ""; - } - - async function findAndActivateCategories() { - const currentPagePath = offsetAbsoluteUrl(window.location.href); - const response = await fetch(offsetRelativeUrl("listings.json")); - if (response.status == 200) { - return response.json().then(function (listingPaths) { - const listingHrefs = []; - for (const listingPath of listingPaths) { - const pathWithoutLeadingSlash = listingPath.listing.substring(1); - for (const item of listingPath.items) { - if ( - item === currentPagePath || - item === currentPagePath + "index.html" - ) { - // Resolve this path against the offset to be sure - // we already are using the correct path to the listing - // (this adjusts the listing urls to be rooted against - // whatever root the page is actually running against) - const relative = offsetRelativeUrl(pathWithoutLeadingSlash); - const baseUrl = window.location; - const resolvedPath = new URL(relative, baseUrl); - listingHrefs.push(resolvedPath.pathname); - break; - } - } - } - - // Look up the tree for a nearby linting and use that if we find one - const nearestListing = findNearestParentListing( - offsetAbsoluteUrl(window.location.pathname), - listingHrefs - ); - if (nearestListing) { - activateCategories(nearestListing); - } else { - // See if the referrer is a listing page for this item - const referredRelativePath = offsetAbsoluteUrl(document.referrer); - const referrerListing = listingHrefs.find((listingHref) => { - const isListingReferrer = - listingHref === referredRelativePath || - listingHref === referredRelativePath + "index.html"; - return isListingReferrer; - }); - - if (referrerListing) { - // Try to use the referrer if possible - activateCategories(referrerListing); - } else if (listingHrefs.length > 0) { - // Otherwise, just fall back to the first listing - activateCategories(listingHrefs[0]); - } - } - }); - } - } - if (hasTitleCategories()) { - findAndActivateCategories(); - } - - const findNearestParentListing = (href, listingHrefs) => { - if (!href || !listingHrefs) { - return undefined; - } - // Look up the tree for a nearby linting and use that if we find one - const relativeParts = href.substring(1).split("/"); - while (relativeParts.length > 0) { - const path = relativeParts.join("/"); - for (const listingHref of listingHrefs) { - if (listingHref.startsWith(path)) { - return listingHref; - } - } - relativeParts.pop(); - } - - return undefined; - }; - - const manageSidebarVisiblity = (el, placeholderDescriptor) => { - let isVisible = true; - let elRect; - - return (hiddenRegions) => { - if (el === null) { - return; - } - - // Find the last element of the TOC - const lastChildEl = el.lastElementChild; - - if (lastChildEl) { - // Converts the sidebar to a menu - const convertToMenu = () => { - for (const child of el.children) { - child.style.opacity = 0; - child.style.overflow = "hidden"; - child.style.pointerEvents = "none"; - } - - nexttick(() => { - const toggleContainer = window.document.createElement("div"); - toggleContainer.style.width = "100%"; - toggleContainer.classList.add("zindex-over-content"); - toggleContainer.classList.add("quarto-sidebar-toggle"); - toggleContainer.classList.add("headroom-target"); // Marks this to be managed by headeroom - toggleContainer.id = placeholderDescriptor.id; - toggleContainer.style.position = "fixed"; - - const toggleIcon = window.document.createElement("i"); - toggleIcon.classList.add("quarto-sidebar-toggle-icon"); - toggleIcon.classList.add("bi"); - toggleIcon.classList.add("bi-caret-down-fill"); - - const toggleTitle = window.document.createElement("div"); - const titleEl = window.document.body.querySelector( - placeholderDescriptor.titleSelector - ); - if (titleEl) { - toggleTitle.append( - titleEl.textContent || titleEl.innerText, - toggleIcon - ); - } - toggleTitle.classList.add("zindex-over-content"); - toggleTitle.classList.add("quarto-sidebar-toggle-title"); - toggleContainer.append(toggleTitle); - - const toggleContents = window.document.createElement("div"); - toggleContents.classList = el.classList; - toggleContents.classList.add("zindex-over-content"); - toggleContents.classList.add("quarto-sidebar-toggle-contents"); - for (const child of el.children) { - if (child.id === "toc-title") { - continue; - } - - const clone = child.cloneNode(true); - clone.style.opacity = 1; - clone.style.pointerEvents = null; - clone.style.display = null; - toggleContents.append(clone); - } - toggleContents.style.height = "0px"; - const positionToggle = () => { - // position the element (top left of parent, same width as parent) - if (!elRect) { - elRect = el.getBoundingClientRect(); - } - toggleContainer.style.left = `${elRect.left}px`; - toggleContainer.style.top = `${elRect.top}px`; - toggleContainer.style.width = `${elRect.width}px`; - }; - positionToggle(); - - toggleContainer.append(toggleContents); - el.parentElement.prepend(toggleContainer); - - // Process clicks - let tocShowing = false; - // Allow the caller to control whether this is dismissed - // when it is clicked (e.g. sidebar navigation supports - // opening and closing the nav tree, so don't dismiss on click) - const clickEl = placeholderDescriptor.dismissOnClick - ? toggleContainer - : toggleTitle; - - const closeToggle = () => { - if (tocShowing) { - toggleContainer.classList.remove("expanded"); - toggleContents.style.height = "0px"; - tocShowing = false; - } - }; - - // Get rid of any expanded toggle if the user scrolls - window.document.addEventListener( - "scroll", - throttle(() => { - closeToggle(); - }, 50) - ); - - // Handle positioning of the toggle - window.addEventListener( - "resize", - throttle(() => { - elRect = undefined; - positionToggle(); - }, 50) - ); - - window.addEventListener("quarto-hrChanged", () => { - elRect = undefined; - }); - - // Process the click - clickEl.onclick = () => { - if (!tocShowing) { - toggleContainer.classList.add("expanded"); - toggleContents.style.height = null; - tocShowing = true; - } else { - closeToggle(); - } - }; - }); - }; - - // Converts a sidebar from a menu back to a sidebar - const convertToSidebar = () => { - for (const child of el.children) { - child.style.opacity = 1; - child.style.overflow = null; - child.style.pointerEvents = null; - } - - const placeholderEl = window.document.getElementById( - placeholderDescriptor.id - ); - if (placeholderEl) { - placeholderEl.remove(); - } - - el.classList.remove("rollup"); - }; - - if (isReaderMode()) { - convertToMenu(); - isVisible = false; - } else { - // Find the top and bottom o the element that is being managed - const elTop = el.offsetTop; - const elBottom = - elTop + lastChildEl.offsetTop + lastChildEl.offsetHeight; - - if (!isVisible) { - // If the element is current not visible reveal if there are - // no conflicts with overlay regions - if (!inHiddenRegion(elTop, elBottom, hiddenRegions)) { - convertToSidebar(); - isVisible = true; - } - } else { - // If the element is visible, hide it if it conflicts with overlay regions - // and insert a placeholder toggle (or if we're in reader mode) - if (inHiddenRegion(elTop, elBottom, hiddenRegions)) { - convertToMenu(); - isVisible = false; - } - } - } - } - }; - }; - - const tabEls = document.querySelectorAll('a[data-bs-toggle="tab"]'); - for (const tabEl of tabEls) { - const id = tabEl.getAttribute("data-bs-target"); - if (id) { - const columnEl = document.querySelector( - `${id} .column-margin, .tabset-margin-content` - ); - if (columnEl) - tabEl.addEventListener("shown.bs.tab", function (event) { - const el = event.srcElement; - if (el) { - const visibleCls = `${el.id}-margin-content`; - // walk up until we find a parent tabset - let panelTabsetEl = el.parentElement; - while (panelTabsetEl) { - if (panelTabsetEl.classList.contains("panel-tabset")) { - break; - } - panelTabsetEl = panelTabsetEl.parentElement; - } - - if (panelTabsetEl) { - const prevSib = panelTabsetEl.previousElementSibling; - if ( - prevSib && - prevSib.classList.contains("tabset-margin-container") - ) { - const childNodes = prevSib.querySelectorAll( - ".tabset-margin-content" - ); - for (const childEl of childNodes) { - if (childEl.classList.contains(visibleCls)) { - childEl.classList.remove("collapse"); - } else { - childEl.classList.add("collapse"); - } - } - } - } - } - - layoutMarginEls(); - }); - } - } - - // Manage the visibility of the toc and the sidebar - const marginScrollVisibility = manageSidebarVisiblity(marginSidebarEl, { - id: "quarto-toc-toggle", - titleSelector: "#toc-title", - dismissOnClick: true, - }); - const sidebarScrollVisiblity = manageSidebarVisiblity(sidebarEl, { - id: "quarto-sidebarnav-toggle", - titleSelector: ".title", - dismissOnClick: false, - }); - let tocLeftScrollVisibility; - if (leftTocEl) { - tocLeftScrollVisibility = manageSidebarVisiblity(leftTocEl, { - id: "quarto-lefttoc-toggle", - titleSelector: "#toc-title", - dismissOnClick: true, - }); - } - - // Find the first element that uses formatting in special columns - const conflictingEls = window.document.body.querySelectorAll( - '[class^="column-"], [class*=" column-"], aside, [class*="margin-caption"], [class*=" margin-caption"], [class*="margin-ref"], [class*=" margin-ref"]' - ); - - // Filter all the possibly conflicting elements into ones - // the do conflict on the left or ride side - const arrConflictingEls = Array.from(conflictingEls); - const leftSideConflictEls = arrConflictingEls.filter((el) => { - if (el.tagName === "ASIDE") { - return false; - } - return Array.from(el.classList).find((className) => { - return ( - className !== "column-body" && - className.startsWith("column-") && - !className.endsWith("right") && - !className.endsWith("container") && - className !== "column-margin" - ); - }); - }); - const rightSideConflictEls = arrConflictingEls.filter((el) => { - if (el.tagName === "ASIDE") { - return true; - } - - const hasMarginCaption = Array.from(el.classList).find((className) => { - return className == "margin-caption"; - }); - if (hasMarginCaption) { - return true; - } - - return Array.from(el.classList).find((className) => { - return ( - className !== "column-body" && - !className.endsWith("container") && - className.startsWith("column-") && - !className.endsWith("left") - ); - }); - }); - - const kOverlapPaddingSize = 10; - function toRegions(els) { - return els.map((el) => { - const boundRect = el.getBoundingClientRect(); - const top = - boundRect.top + - document.documentElement.scrollTop - - kOverlapPaddingSize; - return { - top, - bottom: top + el.scrollHeight + 2 * kOverlapPaddingSize, - }; - }); - } - - let hasObserved = false; - const visibleItemObserver = (els) => { - let visibleElements = [...els]; - const intersectionObserver = new IntersectionObserver( - (entries, _observer) => { - entries.forEach((entry) => { - if (entry.isIntersecting) { - if (visibleElements.indexOf(entry.target) === -1) { - visibleElements.push(entry.target); - } - } else { - visibleElements = visibleElements.filter((visibleEntry) => { - return visibleEntry !== entry; - }); - } - }); - - if (!hasObserved) { - hideOverlappedSidebars(); - } - hasObserved = true; - }, - {} - ); - els.forEach((el) => { - intersectionObserver.observe(el); - }); - - return { - getVisibleEntries: () => { - return visibleElements; - }, - }; - }; - - const rightElementObserver = visibleItemObserver(rightSideConflictEls); - const leftElementObserver = visibleItemObserver(leftSideConflictEls); - - const hideOverlappedSidebars = () => { - marginScrollVisibility(toRegions(rightElementObserver.getVisibleEntries())); - sidebarScrollVisiblity(toRegions(leftElementObserver.getVisibleEntries())); - if (tocLeftScrollVisibility) { - tocLeftScrollVisibility( - toRegions(leftElementObserver.getVisibleEntries()) - ); - } - }; - - window.quartoToggleReader = () => { - // Applies a slow class (or removes it) - // to update the transition speed - const slowTransition = (slow) => { - const manageTransition = (id, slow) => { - const el = document.getElementById(id); - if (el) { - if (slow) { - el.classList.add("slow"); - } else { - el.classList.remove("slow"); - } - } - }; - - manageTransition("TOC", slow); - manageTransition("quarto-sidebar", slow); - }; - const readerMode = !isReaderMode(); - setReaderModeValue(readerMode); - - // If we're entering reader mode, slow the transition - if (readerMode) { - slowTransition(readerMode); - } - highlightReaderToggle(readerMode); - hideOverlappedSidebars(); - - // If we're exiting reader mode, restore the non-slow transition - if (!readerMode) { - slowTransition(!readerMode); - } - }; - - const highlightReaderToggle = (readerMode) => { - const els = document.querySelectorAll(".quarto-reader-toggle"); - if (els) { - els.forEach((el) => { - if (readerMode) { - el.classList.add("reader"); - } else { - el.classList.remove("reader"); - } - }); - } - }; - - const setReaderModeValue = (val) => { - if (window.location.protocol !== "file:") { - window.localStorage.setItem("quarto-reader-mode", val); - } else { - localReaderMode = val; - } - }; - - const isReaderMode = () => { - if (window.location.protocol !== "file:") { - return window.localStorage.getItem("quarto-reader-mode") === "true"; - } else { - return localReaderMode; - } - }; - let localReaderMode = null; - - const tocOpenDepthStr = tocEl?.getAttribute("data-toc-expanded"); - const tocOpenDepth = tocOpenDepthStr ? Number(tocOpenDepthStr) : 1; - - // Walk the TOC and collapse/expand nodes - // Nodes are expanded if: - // - they are top level - // - they have children that are 'active' links - // - they are directly below an link that is 'active' - const walk = (el, depth) => { - // Tick depth when we enter a UL - if (el.tagName === "UL") { - depth = depth + 1; - } - - // It this is active link - let isActiveNode = false; - if (el.tagName === "A" && el.classList.contains("active")) { - isActiveNode = true; - } - - // See if there is an active child to this element - let hasActiveChild = false; - for (child of el.children) { - hasActiveChild = walk(child, depth) || hasActiveChild; - } - - // Process the collapse state if this is an UL - if (el.tagName === "UL") { - if (tocOpenDepth === -1 && depth > 1) { - // toc-expand: false - el.classList.add("collapse"); - } else if ( - depth <= tocOpenDepth || - hasActiveChild || - prevSiblingIsActiveLink(el) - ) { - el.classList.remove("collapse"); - } else { - el.classList.add("collapse"); - } - - // untick depth when we leave a UL - depth = depth - 1; - } - return hasActiveChild || isActiveNode; - }; - - // walk the TOC and expand / collapse any items that should be shown - if (tocEl) { - updateActiveLink(); - walk(tocEl, 0); - } - - // Throttle the scroll event and walk peridiocally - window.document.addEventListener( - "scroll", - throttle(() => { - if (tocEl) { - updateActiveLink(); - walk(tocEl, 0); - } - if (!isReaderMode()) { - hideOverlappedSidebars(); - } - }, 5) - ); - window.addEventListener( - "resize", - throttle(() => { - if (tocEl) { - updateActiveLink(); - walk(tocEl, 0); - } - if (!isReaderMode()) { - hideOverlappedSidebars(); - } - }, 10) - ); - hideOverlappedSidebars(); - highlightReaderToggle(isReaderMode()); -}); - -// grouped tabsets -window.addEventListener("pageshow", (_event) => { - function getTabSettings() { - const data = localStorage.getItem("quarto-persistent-tabsets-data"); - if (!data) { - localStorage.setItem("quarto-persistent-tabsets-data", "{}"); - return {}; - } - if (data) { - return JSON.parse(data); - } - } - - function setTabSettings(data) { - localStorage.setItem( - "quarto-persistent-tabsets-data", - JSON.stringify(data) - ); - } - - function setTabState(groupName, groupValue) { - const data = getTabSettings(); - data[groupName] = groupValue; - setTabSettings(data); - } - - function toggleTab(tab, active) { - const tabPanelId = tab.getAttribute("aria-controls"); - const tabPanel = document.getElementById(tabPanelId); - if (active) { - tab.classList.add("active"); - tabPanel.classList.add("active"); - } else { - tab.classList.remove("active"); - tabPanel.classList.remove("active"); - } - } - - function toggleAll(selectedGroup, selectorsToSync) { - for (const [thisGroup, tabs] of Object.entries(selectorsToSync)) { - const active = selectedGroup === thisGroup; - for (const tab of tabs) { - toggleTab(tab, active); - } - } - } - - function findSelectorsToSyncByLanguage() { - const result = {}; - const tabs = Array.from( - document.querySelectorAll(`div[data-group] a[id^='tabset-']`) - ); - for (const item of tabs) { - const div = item.parentElement.parentElement.parentElement; - const group = div.getAttribute("data-group"); - if (!result[group]) { - result[group] = {}; - } - const selectorsToSync = result[group]; - const value = item.innerHTML; - if (!selectorsToSync[value]) { - selectorsToSync[value] = []; - } - selectorsToSync[value].push(item); - } - return result; - } - - function setupSelectorSync() { - const selectorsToSync = findSelectorsToSyncByLanguage(); - Object.entries(selectorsToSync).forEach(([group, tabSetsByValue]) => { - Object.entries(tabSetsByValue).forEach(([value, items]) => { - items.forEach((item) => { - item.addEventListener("click", (_event) => { - setTabState(group, value); - toggleAll(value, selectorsToSync[group]); - }); - }); - }); - }); - return selectorsToSync; - } - - const selectorsToSync = setupSelectorSync(); - for (const [group, selectedName] of Object.entries(getTabSettings())) { - const selectors = selectorsToSync[group]; - // it's possible that stale state gives us empty selections, so we explicitly check here. - if (selectors) { - toggleAll(selectedName, selectors); - } - } -}); - -function throttle(func, wait) { - let waiting = false; - return function () { - if (!waiting) { - func.apply(this, arguments); - waiting = true; - setTimeout(function () { - waiting = false; - }, wait); - } - }; -} - -function nexttick(func) { - return setTimeout(func, 0); -} diff --git a/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/run_pecan_files/libs/quarto-html/tippy.css b/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/run_pecan_files/libs/quarto-html/tippy.css deleted file mode 100644 index e6ae635cb..000000000 --- a/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/run_pecan_files/libs/quarto-html/tippy.css +++ /dev/null @@ -1 +0,0 @@ -.tippy-box[data-animation=fade][data-state=hidden]{opacity:0}[data-tippy-root]{max-width:calc(100vw - 10px)}.tippy-box{position:relative;background-color:#333;color:#fff;border-radius:4px;font-size:14px;line-height:1.4;white-space:normal;outline:0;transition-property:transform,visibility,opacity}.tippy-box[data-placement^=top]>.tippy-arrow{bottom:0}.tippy-box[data-placement^=top]>.tippy-arrow:before{bottom:-7px;left:0;border-width:8px 8px 0;border-top-color:initial;transform-origin:center top}.tippy-box[data-placement^=bottom]>.tippy-arrow{top:0}.tippy-box[data-placement^=bottom]>.tippy-arrow:before{top:-7px;left:0;border-width:0 8px 8px;border-bottom-color:initial;transform-origin:center bottom}.tippy-box[data-placement^=left]>.tippy-arrow{right:0}.tippy-box[data-placement^=left]>.tippy-arrow:before{border-width:8px 0 8px 8px;border-left-color:initial;right:-7px;transform-origin:center left}.tippy-box[data-placement^=right]>.tippy-arrow{left:0}.tippy-box[data-placement^=right]>.tippy-arrow:before{left:-7px;border-width:8px 8px 8px 0;border-right-color:initial;transform-origin:center right}.tippy-box[data-inertia][data-state=visible]{transition-timing-function:cubic-bezier(.54,1.5,.38,1.11)}.tippy-arrow{width:16px;height:16px;color:#333}.tippy-arrow:before{content:"";position:absolute;border-color:transparent;border-style:solid}.tippy-content{position:relative;padding:5px 9px;z-index:1} \ No newline at end of file diff --git a/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/run_pecan_files/libs/quarto-html/tippy.umd.min.js b/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/run_pecan_files/libs/quarto-html/tippy.umd.min.js deleted file mode 100644 index ca292be32..000000000 --- a/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/run_pecan_files/libs/quarto-html/tippy.umd.min.js +++ /dev/null @@ -1,2 +0,0 @@ -!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t(require("@popperjs/core")):"function"==typeof define&&define.amd?define(["@popperjs/core"],t):(e=e||self).tippy=t(e.Popper)}(this,(function(e){"use strict";var t={passive:!0,capture:!0},n=function(){return document.body};function r(e,t,n){if(Array.isArray(e)){var r=e[t];return null==r?Array.isArray(n)?n[t]:n:r}return e}function o(e,t){var n={}.toString.call(e);return 0===n.indexOf("[object")&&n.indexOf(t+"]")>-1}function i(e,t){return"function"==typeof e?e.apply(void 0,t):e}function a(e,t){return 0===t?e:function(r){clearTimeout(n),n=setTimeout((function(){e(r)}),t)};var n}function s(e,t){var n=Object.assign({},e);return t.forEach((function(e){delete n[e]})),n}function u(e){return[].concat(e)}function c(e,t){-1===e.indexOf(t)&&e.push(t)}function p(e){return e.split("-")[0]}function f(e){return[].slice.call(e)}function l(e){return Object.keys(e).reduce((function(t,n){return void 0!==e[n]&&(t[n]=e[n]),t}),{})}function d(){return document.createElement("div")}function v(e){return["Element","Fragment"].some((function(t){return o(e,t)}))}function m(e){return o(e,"MouseEvent")}function g(e){return!(!e||!e._tippy||e._tippy.reference!==e)}function h(e){return v(e)?[e]:function(e){return o(e,"NodeList")}(e)?f(e):Array.isArray(e)?e:f(document.querySelectorAll(e))}function b(e,t){e.forEach((function(e){e&&(e.style.transitionDuration=t+"ms")}))}function y(e,t){e.forEach((function(e){e&&e.setAttribute("data-state",t)}))}function w(e){var t,n=u(e)[0];return null!=n&&null!=(t=n.ownerDocument)&&t.body?n.ownerDocument:document}function E(e,t,n){var r=t+"EventListener";["transitionend","webkitTransitionEnd"].forEach((function(t){e[r](t,n)}))}function O(e,t){for(var n=t;n;){var r;if(e.contains(n))return!0;n=null==n.getRootNode||null==(r=n.getRootNode())?void 0:r.host}return!1}var x={isTouch:!1},C=0;function T(){x.isTouch||(x.isTouch=!0,window.performance&&document.addEventListener("mousemove",A))}function A(){var e=performance.now();e-C<20&&(x.isTouch=!1,document.removeEventListener("mousemove",A)),C=e}function L(){var e=document.activeElement;if(g(e)){var t=e._tippy;e.blur&&!t.state.isVisible&&e.blur()}}var D=!!("undefined"!=typeof window&&"undefined"!=typeof document)&&!!window.msCrypto,R=Object.assign({appendTo:n,aria:{content:"auto",expanded:"auto"},delay:0,duration:[300,250],getReferenceClientRect:null,hideOnClick:!0,ignoreAttributes:!1,interactive:!1,interactiveBorder:2,interactiveDebounce:0,moveTransition:"",offset:[0,10],onAfterUpdate:function(){},onBeforeUpdate:function(){},onCreate:function(){},onDestroy:function(){},onHidden:function(){},onHide:function(){},onMount:function(){},onShow:function(){},onShown:function(){},onTrigger:function(){},onUntrigger:function(){},onClickOutside:function(){},placement:"top",plugins:[],popperOptions:{},render:null,showOnCreate:!1,touch:!0,trigger:"mouseenter focus",triggerTarget:null},{animateFill:!1,followCursor:!1,inlinePositioning:!1,sticky:!1},{allowHTML:!1,animation:"fade",arrow:!0,content:"",inertia:!1,maxWidth:350,role:"tooltip",theme:"",zIndex:9999}),k=Object.keys(R);function P(e){var t=(e.plugins||[]).reduce((function(t,n){var r,o=n.name,i=n.defaultValue;o&&(t[o]=void 0!==e[o]?e[o]:null!=(r=R[o])?r:i);return t}),{});return Object.assign({},e,t)}function j(e,t){var n=Object.assign({},t,{content:i(t.content,[e])},t.ignoreAttributes?{}:function(e,t){return(t?Object.keys(P(Object.assign({},R,{plugins:t}))):k).reduce((function(t,n){var r=(e.getAttribute("data-tippy-"+n)||"").trim();if(!r)return t;if("content"===n)t[n]=r;else try{t[n]=JSON.parse(r)}catch(e){t[n]=r}return t}),{})}(e,t.plugins));return n.aria=Object.assign({},R.aria,n.aria),n.aria={expanded:"auto"===n.aria.expanded?t.interactive:n.aria.expanded,content:"auto"===n.aria.content?t.interactive?null:"describedby":n.aria.content},n}function M(e,t){e.innerHTML=t}function V(e){var t=d();return!0===e?t.className="tippy-arrow":(t.className="tippy-svg-arrow",v(e)?t.appendChild(e):M(t,e)),t}function I(e,t){v(t.content)?(M(e,""),e.appendChild(t.content)):"function"!=typeof t.content&&(t.allowHTML?M(e,t.content):e.textContent=t.content)}function S(e){var t=e.firstElementChild,n=f(t.children);return{box:t,content:n.find((function(e){return e.classList.contains("tippy-content")})),arrow:n.find((function(e){return e.classList.contains("tippy-arrow")||e.classList.contains("tippy-svg-arrow")})),backdrop:n.find((function(e){return e.classList.contains("tippy-backdrop")}))}}function N(e){var t=d(),n=d();n.className="tippy-box",n.setAttribute("data-state","hidden"),n.setAttribute("tabindex","-1");var r=d();function o(n,r){var o=S(t),i=o.box,a=o.content,s=o.arrow;r.theme?i.setAttribute("data-theme",r.theme):i.removeAttribute("data-theme"),"string"==typeof r.animation?i.setAttribute("data-animation",r.animation):i.removeAttribute("data-animation"),r.inertia?i.setAttribute("data-inertia",""):i.removeAttribute("data-inertia"),i.style.maxWidth="number"==typeof r.maxWidth?r.maxWidth+"px":r.maxWidth,r.role?i.setAttribute("role",r.role):i.removeAttribute("role"),n.content===r.content&&n.allowHTML===r.allowHTML||I(a,e.props),r.arrow?s?n.arrow!==r.arrow&&(i.removeChild(s),i.appendChild(V(r.arrow))):i.appendChild(V(r.arrow)):s&&i.removeChild(s)}return r.className="tippy-content",r.setAttribute("data-state","hidden"),I(r,e.props),t.appendChild(n),n.appendChild(r),o(e.props,e.props),{popper:t,onUpdate:o}}N.$$tippy=!0;var B=1,H=[],U=[];function _(o,s){var v,g,h,C,T,A,L,k,M=j(o,Object.assign({},R,P(l(s)))),V=!1,I=!1,N=!1,_=!1,F=[],W=a(we,M.interactiveDebounce),X=B++,Y=(k=M.plugins).filter((function(e,t){return k.indexOf(e)===t})),$={id:X,reference:o,popper:d(),popperInstance:null,props:M,state:{isEnabled:!0,isVisible:!1,isDestroyed:!1,isMounted:!1,isShown:!1},plugins:Y,clearDelayTimeouts:function(){clearTimeout(v),clearTimeout(g),cancelAnimationFrame(h)},setProps:function(e){if($.state.isDestroyed)return;ae("onBeforeUpdate",[$,e]),be();var t=$.props,n=j(o,Object.assign({},t,l(e),{ignoreAttributes:!0}));$.props=n,he(),t.interactiveDebounce!==n.interactiveDebounce&&(ce(),W=a(we,n.interactiveDebounce));t.triggerTarget&&!n.triggerTarget?u(t.triggerTarget).forEach((function(e){e.removeAttribute("aria-expanded")})):n.triggerTarget&&o.removeAttribute("aria-expanded");ue(),ie(),J&&J(t,n);$.popperInstance&&(Ce(),Ae().forEach((function(e){requestAnimationFrame(e._tippy.popperInstance.forceUpdate)})));ae("onAfterUpdate",[$,e])},setContent:function(e){$.setProps({content:e})},show:function(){var e=$.state.isVisible,t=$.state.isDestroyed,o=!$.state.isEnabled,a=x.isTouch&&!$.props.touch,s=r($.props.duration,0,R.duration);if(e||t||o||a)return;if(te().hasAttribute("disabled"))return;if(ae("onShow",[$],!1),!1===$.props.onShow($))return;$.state.isVisible=!0,ee()&&(z.style.visibility="visible");ie(),de(),$.state.isMounted||(z.style.transition="none");if(ee()){var u=re(),p=u.box,f=u.content;b([p,f],0)}A=function(){var e;if($.state.isVisible&&!_){if(_=!0,z.offsetHeight,z.style.transition=$.props.moveTransition,ee()&&$.props.animation){var t=re(),n=t.box,r=t.content;b([n,r],s),y([n,r],"visible")}se(),ue(),c(U,$),null==(e=$.popperInstance)||e.forceUpdate(),ae("onMount",[$]),$.props.animation&&ee()&&function(e,t){me(e,t)}(s,(function(){$.state.isShown=!0,ae("onShown",[$])}))}},function(){var e,t=$.props.appendTo,r=te();e=$.props.interactive&&t===n||"parent"===t?r.parentNode:i(t,[r]);e.contains(z)||e.appendChild(z);$.state.isMounted=!0,Ce()}()},hide:function(){var e=!$.state.isVisible,t=$.state.isDestroyed,n=!$.state.isEnabled,o=r($.props.duration,1,R.duration);if(e||t||n)return;if(ae("onHide",[$],!1),!1===$.props.onHide($))return;$.state.isVisible=!1,$.state.isShown=!1,_=!1,V=!1,ee()&&(z.style.visibility="hidden");if(ce(),ve(),ie(!0),ee()){var i=re(),a=i.box,s=i.content;$.props.animation&&(b([a,s],o),y([a,s],"hidden"))}se(),ue(),$.props.animation?ee()&&function(e,t){me(e,(function(){!$.state.isVisible&&z.parentNode&&z.parentNode.contains(z)&&t()}))}(o,$.unmount):$.unmount()},hideWithInteractivity:function(e){ne().addEventListener("mousemove",W),c(H,W),W(e)},enable:function(){$.state.isEnabled=!0},disable:function(){$.hide(),$.state.isEnabled=!1},unmount:function(){$.state.isVisible&&$.hide();if(!$.state.isMounted)return;Te(),Ae().forEach((function(e){e._tippy.unmount()})),z.parentNode&&z.parentNode.removeChild(z);U=U.filter((function(e){return e!==$})),$.state.isMounted=!1,ae("onHidden",[$])},destroy:function(){if($.state.isDestroyed)return;$.clearDelayTimeouts(),$.unmount(),be(),delete o._tippy,$.state.isDestroyed=!0,ae("onDestroy",[$])}};if(!M.render)return $;var q=M.render($),z=q.popper,J=q.onUpdate;z.setAttribute("data-tippy-root",""),z.id="tippy-"+$.id,$.popper=z,o._tippy=$,z._tippy=$;var G=Y.map((function(e){return e.fn($)})),K=o.hasAttribute("aria-expanded");return he(),ue(),ie(),ae("onCreate",[$]),M.showOnCreate&&Le(),z.addEventListener("mouseenter",(function(){$.props.interactive&&$.state.isVisible&&$.clearDelayTimeouts()})),z.addEventListener("mouseleave",(function(){$.props.interactive&&$.props.trigger.indexOf("mouseenter")>=0&&ne().addEventListener("mousemove",W)})),$;function Q(){var e=$.props.touch;return Array.isArray(e)?e:[e,0]}function Z(){return"hold"===Q()[0]}function ee(){var e;return!(null==(e=$.props.render)||!e.$$tippy)}function te(){return L||o}function ne(){var e=te().parentNode;return e?w(e):document}function re(){return S(z)}function oe(e){return $.state.isMounted&&!$.state.isVisible||x.isTouch||C&&"focus"===C.type?0:r($.props.delay,e?0:1,R.delay)}function ie(e){void 0===e&&(e=!1),z.style.pointerEvents=$.props.interactive&&!e?"":"none",z.style.zIndex=""+$.props.zIndex}function ae(e,t,n){var r;(void 0===n&&(n=!0),G.forEach((function(n){n[e]&&n[e].apply(n,t)})),n)&&(r=$.props)[e].apply(r,t)}function se(){var e=$.props.aria;if(e.content){var t="aria-"+e.content,n=z.id;u($.props.triggerTarget||o).forEach((function(e){var r=e.getAttribute(t);if($.state.isVisible)e.setAttribute(t,r?r+" "+n:n);else{var o=r&&r.replace(n,"").trim();o?e.setAttribute(t,o):e.removeAttribute(t)}}))}}function ue(){!K&&$.props.aria.expanded&&u($.props.triggerTarget||o).forEach((function(e){$.props.interactive?e.setAttribute("aria-expanded",$.state.isVisible&&e===te()?"true":"false"):e.removeAttribute("aria-expanded")}))}function ce(){ne().removeEventListener("mousemove",W),H=H.filter((function(e){return e!==W}))}function pe(e){if(!x.isTouch||!N&&"mousedown"!==e.type){var t=e.composedPath&&e.composedPath()[0]||e.target;if(!$.props.interactive||!O(z,t)){if(u($.props.triggerTarget||o).some((function(e){return O(e,t)}))){if(x.isTouch)return;if($.state.isVisible&&$.props.trigger.indexOf("click")>=0)return}else ae("onClickOutside",[$,e]);!0===$.props.hideOnClick&&($.clearDelayTimeouts(),$.hide(),I=!0,setTimeout((function(){I=!1})),$.state.isMounted||ve())}}}function fe(){N=!0}function le(){N=!1}function de(){var e=ne();e.addEventListener("mousedown",pe,!0),e.addEventListener("touchend",pe,t),e.addEventListener("touchstart",le,t),e.addEventListener("touchmove",fe,t)}function ve(){var e=ne();e.removeEventListener("mousedown",pe,!0),e.removeEventListener("touchend",pe,t),e.removeEventListener("touchstart",le,t),e.removeEventListener("touchmove",fe,t)}function me(e,t){var n=re().box;function r(e){e.target===n&&(E(n,"remove",r),t())}if(0===e)return t();E(n,"remove",T),E(n,"add",r),T=r}function ge(e,t,n){void 0===n&&(n=!1),u($.props.triggerTarget||o).forEach((function(r){r.addEventListener(e,t,n),F.push({node:r,eventType:e,handler:t,options:n})}))}function he(){var e;Z()&&(ge("touchstart",ye,{passive:!0}),ge("touchend",Ee,{passive:!0})),(e=$.props.trigger,e.split(/\s+/).filter(Boolean)).forEach((function(e){if("manual"!==e)switch(ge(e,ye),e){case"mouseenter":ge("mouseleave",Ee);break;case"focus":ge(D?"focusout":"blur",Oe);break;case"focusin":ge("focusout",Oe)}}))}function be(){F.forEach((function(e){var t=e.node,n=e.eventType,r=e.handler,o=e.options;t.removeEventListener(n,r,o)})),F=[]}function ye(e){var t,n=!1;if($.state.isEnabled&&!xe(e)&&!I){var r="focus"===(null==(t=C)?void 0:t.type);C=e,L=e.currentTarget,ue(),!$.state.isVisible&&m(e)&&H.forEach((function(t){return t(e)})),"click"===e.type&&($.props.trigger.indexOf("mouseenter")<0||V)&&!1!==$.props.hideOnClick&&$.state.isVisible?n=!0:Le(e),"click"===e.type&&(V=!n),n&&!r&&De(e)}}function we(e){var t=e.target,n=te().contains(t)||z.contains(t);"mousemove"===e.type&&n||function(e,t){var n=t.clientX,r=t.clientY;return e.every((function(e){var t=e.popperRect,o=e.popperState,i=e.props.interactiveBorder,a=p(o.placement),s=o.modifiersData.offset;if(!s)return!0;var u="bottom"===a?s.top.y:0,c="top"===a?s.bottom.y:0,f="right"===a?s.left.x:0,l="left"===a?s.right.x:0,d=t.top-r+u>i,v=r-t.bottom-c>i,m=t.left-n+f>i,g=n-t.right-l>i;return d||v||m||g}))}(Ae().concat(z).map((function(e){var t,n=null==(t=e._tippy.popperInstance)?void 0:t.state;return n?{popperRect:e.getBoundingClientRect(),popperState:n,props:M}:null})).filter(Boolean),e)&&(ce(),De(e))}function Ee(e){xe(e)||$.props.trigger.indexOf("click")>=0&&V||($.props.interactive?$.hideWithInteractivity(e):De(e))}function Oe(e){$.props.trigger.indexOf("focusin")<0&&e.target!==te()||$.props.interactive&&e.relatedTarget&&z.contains(e.relatedTarget)||De(e)}function xe(e){return!!x.isTouch&&Z()!==e.type.indexOf("touch")>=0}function Ce(){Te();var t=$.props,n=t.popperOptions,r=t.placement,i=t.offset,a=t.getReferenceClientRect,s=t.moveTransition,u=ee()?S(z).arrow:null,c=a?{getBoundingClientRect:a,contextElement:a.contextElement||te()}:o,p=[{name:"offset",options:{offset:i}},{name:"preventOverflow",options:{padding:{top:2,bottom:2,left:5,right:5}}},{name:"flip",options:{padding:5}},{name:"computeStyles",options:{adaptive:!s}},{name:"$$tippy",enabled:!0,phase:"beforeWrite",requires:["computeStyles"],fn:function(e){var t=e.state;if(ee()){var n=re().box;["placement","reference-hidden","escaped"].forEach((function(e){"placement"===e?n.setAttribute("data-placement",t.placement):t.attributes.popper["data-popper-"+e]?n.setAttribute("data-"+e,""):n.removeAttribute("data-"+e)})),t.attributes.popper={}}}}];ee()&&u&&p.push({name:"arrow",options:{element:u,padding:3}}),p.push.apply(p,(null==n?void 0:n.modifiers)||[]),$.popperInstance=e.createPopper(c,z,Object.assign({},n,{placement:r,onFirstUpdate:A,modifiers:p}))}function Te(){$.popperInstance&&($.popperInstance.destroy(),$.popperInstance=null)}function Ae(){return f(z.querySelectorAll("[data-tippy-root]"))}function Le(e){$.clearDelayTimeouts(),e&&ae("onTrigger",[$,e]),de();var t=oe(!0),n=Q(),r=n[0],o=n[1];x.isTouch&&"hold"===r&&o&&(t=o),t?v=setTimeout((function(){$.show()}),t):$.show()}function De(e){if($.clearDelayTimeouts(),ae("onUntrigger",[$,e]),$.state.isVisible){if(!($.props.trigger.indexOf("mouseenter")>=0&&$.props.trigger.indexOf("click")>=0&&["mouseleave","mousemove"].indexOf(e.type)>=0&&V)){var t=oe(!1);t?g=setTimeout((function(){$.state.isVisible&&$.hide()}),t):h=requestAnimationFrame((function(){$.hide()}))}}else ve()}}function F(e,n){void 0===n&&(n={});var r=R.plugins.concat(n.plugins||[]);document.addEventListener("touchstart",T,t),window.addEventListener("blur",L);var o=Object.assign({},n,{plugins:r}),i=h(e).reduce((function(e,t){var n=t&&_(t,o);return n&&e.push(n),e}),[]);return v(e)?i[0]:i}F.defaultProps=R,F.setDefaultProps=function(e){Object.keys(e).forEach((function(t){R[t]=e[t]}))},F.currentInput=x;var W=Object.assign({},e.applyStyles,{effect:function(e){var t=e.state,n={popper:{position:t.options.strategy,left:"0",top:"0",margin:"0"},arrow:{position:"absolute"},reference:{}};Object.assign(t.elements.popper.style,n.popper),t.styles=n,t.elements.arrow&&Object.assign(t.elements.arrow.style,n.arrow)}}),X={mouseover:"mouseenter",focusin:"focus",click:"click"};var Y={name:"animateFill",defaultValue:!1,fn:function(e){var t;if(null==(t=e.props.render)||!t.$$tippy)return{};var n=S(e.popper),r=n.box,o=n.content,i=e.props.animateFill?function(){var e=d();return e.className="tippy-backdrop",y([e],"hidden"),e}():null;return{onCreate:function(){i&&(r.insertBefore(i,r.firstElementChild),r.setAttribute("data-animatefill",""),r.style.overflow="hidden",e.setProps({arrow:!1,animation:"shift-away"}))},onMount:function(){if(i){var e=r.style.transitionDuration,t=Number(e.replace("ms",""));o.style.transitionDelay=Math.round(t/10)+"ms",i.style.transitionDuration=e,y([i],"visible")}},onShow:function(){i&&(i.style.transitionDuration="0ms")},onHide:function(){i&&y([i],"hidden")}}}};var $={clientX:0,clientY:0},q=[];function z(e){var t=e.clientX,n=e.clientY;$={clientX:t,clientY:n}}var J={name:"followCursor",defaultValue:!1,fn:function(e){var t=e.reference,n=w(e.props.triggerTarget||t),r=!1,o=!1,i=!0,a=e.props;function s(){return"initial"===e.props.followCursor&&e.state.isVisible}function u(){n.addEventListener("mousemove",f)}function c(){n.removeEventListener("mousemove",f)}function p(){r=!0,e.setProps({getReferenceClientRect:null}),r=!1}function f(n){var r=!n.target||t.contains(n.target),o=e.props.followCursor,i=n.clientX,a=n.clientY,s=t.getBoundingClientRect(),u=i-s.left,c=a-s.top;!r&&e.props.interactive||e.setProps({getReferenceClientRect:function(){var e=t.getBoundingClientRect(),n=i,r=a;"initial"===o&&(n=e.left+u,r=e.top+c);var s="horizontal"===o?e.top:r,p="vertical"===o?e.right:n,f="horizontal"===o?e.bottom:r,l="vertical"===o?e.left:n;return{width:p-l,height:f-s,top:s,right:p,bottom:f,left:l}}})}function l(){e.props.followCursor&&(q.push({instance:e,doc:n}),function(e){e.addEventListener("mousemove",z)}(n))}function d(){0===(q=q.filter((function(t){return t.instance!==e}))).filter((function(e){return e.doc===n})).length&&function(e){e.removeEventListener("mousemove",z)}(n)}return{onCreate:l,onDestroy:d,onBeforeUpdate:function(){a=e.props},onAfterUpdate:function(t,n){var i=n.followCursor;r||void 0!==i&&a.followCursor!==i&&(d(),i?(l(),!e.state.isMounted||o||s()||u()):(c(),p()))},onMount:function(){e.props.followCursor&&!o&&(i&&(f($),i=!1),s()||u())},onTrigger:function(e,t){m(t)&&($={clientX:t.clientX,clientY:t.clientY}),o="focus"===t.type},onHidden:function(){e.props.followCursor&&(p(),c(),i=!0)}}}};var G={name:"inlinePositioning",defaultValue:!1,fn:function(e){var t,n=e.reference;var r=-1,o=!1,i=[],a={name:"tippyInlinePositioning",enabled:!0,phase:"afterWrite",fn:function(o){var a=o.state;e.props.inlinePositioning&&(-1!==i.indexOf(a.placement)&&(i=[]),t!==a.placement&&-1===i.indexOf(a.placement)&&(i.push(a.placement),e.setProps({getReferenceClientRect:function(){return function(e){return function(e,t,n,r){if(n.length<2||null===e)return t;if(2===n.length&&r>=0&&n[0].left>n[1].right)return n[r]||t;switch(e){case"top":case"bottom":var o=n[0],i=n[n.length-1],a="top"===e,s=o.top,u=i.bottom,c=a?o.left:i.left,p=a?o.right:i.right;return{top:s,bottom:u,left:c,right:p,width:p-c,height:u-s};case"left":case"right":var f=Math.min.apply(Math,n.map((function(e){return e.left}))),l=Math.max.apply(Math,n.map((function(e){return e.right}))),d=n.filter((function(t){return"left"===e?t.left===f:t.right===l})),v=d[0].top,m=d[d.length-1].bottom;return{top:v,bottom:m,left:f,right:l,width:l-f,height:m-v};default:return t}}(p(e),n.getBoundingClientRect(),f(n.getClientRects()),r)}(a.placement)}})),t=a.placement)}};function s(){var t;o||(t=function(e,t){var n;return{popperOptions:Object.assign({},e.popperOptions,{modifiers:[].concat(((null==(n=e.popperOptions)?void 0:n.modifiers)||[]).filter((function(e){return e.name!==t.name})),[t])})}}(e.props,a),o=!0,e.setProps(t),o=!1)}return{onCreate:s,onAfterUpdate:s,onTrigger:function(t,n){if(m(n)){var o=f(e.reference.getClientRects()),i=o.find((function(e){return e.left-2<=n.clientX&&e.right+2>=n.clientX&&e.top-2<=n.clientY&&e.bottom+2>=n.clientY})),a=o.indexOf(i);r=a>-1?a:r}},onHidden:function(){r=-1}}}};var K={name:"sticky",defaultValue:!1,fn:function(e){var t=e.reference,n=e.popper;function r(t){return!0===e.props.sticky||e.props.sticky===t}var o=null,i=null;function a(){var s=r("reference")?(e.popperInstance?e.popperInstance.state.elements.reference:t).getBoundingClientRect():null,u=r("popper")?n.getBoundingClientRect():null;(s&&Q(o,s)||u&&Q(i,u))&&e.popperInstance&&e.popperInstance.update(),o=s,i=u,e.state.isMounted&&requestAnimationFrame(a)}return{onMount:function(){e.props.sticky&&a()}}}};function Q(e,t){return!e||!t||(e.top!==t.top||e.right!==t.right||e.bottom!==t.bottom||e.left!==t.left)}return F.setDefaultProps({plugins:[Y,J,G,K],render:N}),F.createSingleton=function(e,t){var n;void 0===t&&(t={});var r,o=e,i=[],a=[],c=t.overrides,p=[],f=!1;function l(){a=o.map((function(e){return u(e.props.triggerTarget||e.reference)})).reduce((function(e,t){return e.concat(t)}),[])}function v(){i=o.map((function(e){return e.reference}))}function m(e){o.forEach((function(t){e?t.enable():t.disable()}))}function g(e){return o.map((function(t){var n=t.setProps;return t.setProps=function(o){n(o),t.reference===r&&e.setProps(o)},function(){t.setProps=n}}))}function h(e,t){var n=a.indexOf(t);if(t!==r){r=t;var s=(c||[]).concat("content").reduce((function(e,t){return e[t]=o[n].props[t],e}),{});e.setProps(Object.assign({},s,{getReferenceClientRect:"function"==typeof s.getReferenceClientRect?s.getReferenceClientRect:function(){var e;return null==(e=i[n])?void 0:e.getBoundingClientRect()}}))}}m(!1),v(),l();var b={fn:function(){return{onDestroy:function(){m(!0)},onHidden:function(){r=null},onClickOutside:function(e){e.props.showOnCreate&&!f&&(f=!0,r=null)},onShow:function(e){e.props.showOnCreate&&!f&&(f=!0,h(e,i[0]))},onTrigger:function(e,t){h(e,t.currentTarget)}}}},y=F(d(),Object.assign({},s(t,["overrides"]),{plugins:[b].concat(t.plugins||[]),triggerTarget:a,popperOptions:Object.assign({},t.popperOptions,{modifiers:[].concat((null==(n=t.popperOptions)?void 0:n.modifiers)||[],[W])})})),w=y.show;y.show=function(e){if(w(),!r&&null==e)return h(y,i[0]);if(!r||null!=e){if("number"==typeof e)return i[e]&&h(y,i[e]);if(o.indexOf(e)>=0){var t=e.reference;return h(y,t)}return i.indexOf(e)>=0?h(y,e):void 0}},y.showNext=function(){var e=i[0];if(!r)return y.show(0);var t=i.indexOf(r);y.show(i[t+1]||e)},y.showPrevious=function(){var e=i[i.length-1];if(!r)return y.show(e);var t=i.indexOf(r),n=i[t-1]||e;y.show(n)};var E=y.setProps;return y.setProps=function(e){c=e.overrides||c,E(e)},y.setInstances=function(e){m(!0),p.forEach((function(e){return e()})),o=e,m(!1),v(),l(),p=g(y),y.setProps({triggerTarget:a})},p=g(y),y},F.delegate=function(e,n){var r=[],o=[],i=!1,a=n.target,c=s(n,["target"]),p=Object.assign({},c,{trigger:"manual",touch:!1}),f=Object.assign({touch:R.touch},c,{showOnCreate:!0}),l=F(e,p);function d(e){if(e.target&&!i){var t=e.target.closest(a);if(t){var r=t.getAttribute("data-tippy-trigger")||n.trigger||R.trigger;if(!t._tippy&&!("touchstart"===e.type&&"boolean"==typeof f.touch||"touchstart"!==e.type&&r.indexOf(X[e.type])<0)){var s=F(t,f);s&&(o=o.concat(s))}}}}function v(e,t,n,o){void 0===o&&(o=!1),e.addEventListener(t,n,o),r.push({node:e,eventType:t,handler:n,options:o})}return u(l).forEach((function(e){var n=e.destroy,a=e.enable,s=e.disable;e.destroy=function(e){void 0===e&&(e=!0),e&&o.forEach((function(e){e.destroy()})),o=[],r.forEach((function(e){var t=e.node,n=e.eventType,r=e.handler,o=e.options;t.removeEventListener(n,r,o)})),r=[],n()},e.enable=function(){a(),o.forEach((function(e){return e.enable()})),i=!1},e.disable=function(){s(),o.forEach((function(e){return e.disable()})),i=!0},function(e){var n=e.reference;v(n,"touchstart",d,t),v(n,"mouseover",d),v(n,"focusin",d),v(n,"click",d)}(e)})),l},F.hideAll=function(e){var t=void 0===e?{}:e,n=t.exclude,r=t.duration;U.forEach((function(e){var t=!1;if(n&&(t=g(n)?e.reference===n:e.popper===n.popper),!t){var o=e.props.duration;e.setProps({duration:r}),e.hide(),e.state.isDestroyed||e.setProps({duration:o})}}))},F.roundArrow='',F})); - diff --git a/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/uncertainty.html b/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/uncertainty.html deleted file mode 100644 index dc681268d..000000000 --- a/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/uncertainty.html +++ /dev/null @@ -1,1770 +0,0 @@ - - - - - - - - - - - -Uncertainty Analysis Using PEcAn - - - - - - - - - - - - - - - - - - - -
- -
- -
-
-

Uncertainty Analysis Using PEcAn

-
- - - -
- -
-
Authors
-
-

Aritra Dey

-

David LeBauer

-
-
- - - -
- - - -
- - -
-

Introduction

-

In Demo 2 we will be looking at how PEcAn can use information about parameter uncertainty to perform three automated analyses:

-
    -
  • Ensemble Analysis: Repeat numerous model runs, each sampling from the parameter uncertainty, to generate a probability distribution of model projections. Allows us to put a confidence interval on the model.
  • -
  • Sensitivity Analysis: Repeats numerous model runs to assess how changes in model parameters will affect model outputs. Allows us to identify which parameters the model is most sensitive to.
  • -
  • Uncertainty Analysis: Combines information about model sensitivity with information about parameter uncertainty to determine the contribution of each model parameter to the uncertainty in model outputs. Allow us to identify which parameters are driving model uncertainty.
  • -
-

This demo shows how to run an uncertainty analysis workflow in PEcAn using an R-based Quarto notebook. It covers loading settings, configuring models, running simulations, and performing ensemble and sensitivity analyses to assess uncertainty and parameter importance. This programmatic approach complements the web-based PEcAn interface.

-

Context & modeling scenario:

-

We simulate plant and ecosystem carbon balance (Net Primary Productivity and Net Ecosystem Exchange) at the AmeriFlux Niwot Ridge Forest site (US‑NR1) during the year 2004. We use SIPNET parameterized as a temperate conifer PFT and driven by AmeriFlux meteorology following the analysis in Moore et al. (2007). This notebook also provides a compact template that can be extended to more years, locations, and PFTs.

-

What this notebook does:

-
    -
  1. Configure a PEcAn workflow by loading and validating a pecan.xml settings file.
  2. -
  3. Run a set of ecosystem model simulations by writing model configuration files and then running SIPNET.
  4. -
  5. Quantify uncertainty using ensemble analysis, sensitivity analyses, and variance decomposition.
  6. -
  7. Visualize results to identify important parameters and how they influence model variance.
  8. -
  9. Change configuration settings and re-run the workflow.
  10. -
-
-

Prerequisites

-

To run this notebook, you will need to install PEcAn and its dependencies, as well as download the SIPNET model binary.

-
-

PEcAn packages and dependencies.

-
# Enable repository from pecanproject
-options(repos = c(
-  pecanproject = 'https://pecanproject.r-universe.dev',
-  CRAN = 'https://cloud.r-project.org'))
-install.packages('PEcAn.all')
-

A valid pecan.xml configuration file. Start with the example at pecan/documentation/tutorials/Demo_02_Uncertainty_Analysis/pecan.xml.

-
-
-

SIPNET v1.3.0

-

If you haven’t already installed the SIPNET model, you can do so by running the following code. This will download the SIPNET binary to demo_outdir/sipnet and make it executable.

-
-

Note: The demo_outdir directory will be created inside of your PEcAn installation, at documentation/tutorials/Demo_02_Uncertainty_Analysis/demo_outdir/. This directory will contain the SIPNET binary as well as the output generated by PEcAn in this demo.

-
-
-
# Download and install SIPNET v1.3.0
-source(
-  here::here(
-    "documentation/tutorials/Demo_1_Basic_Run/download_sipnet.R"
-  )
-)
-
-
-

Note: You can find the most recent version of the SIPNET binary at: SIPNET GitHub Releases, but this notebook is designed to work with SIPNET v1.3.0.

-
-
-
-
-
-

Load PEcAn Packages

-

First, we need to load the PEcAn R packages. These packages provide all the functions we’ll use to run the workflow.

-
-
# Load the PEcAn.all package, which includes all necessary PEcAn functionality
-library("PEcAn.all")
-
-
Loading required package: PEcAn.DB
-
-
-
Loading required package: PEcAn.settings
-
-
-
Loading required package: PEcAn.MA
-
-
-
Loading required package: PEcAn.logger
-
-
-
Loading required package: PEcAn.utils
-
-
-
Loading required package: PEcAn.uncertainty
-
-
-
Loading required package: PEcAn.data.atmosphere
-
-
-
Loading required package: PEcAn.data.land
-
-
-
Loading required package: PEcAn.data.remote
-
-
-
Loading required package: PEcAn.assim.batch
-
-
-
Loading required package: PEcAn.emulator
-
-
-
Loading required package: PEcAn.priors
-
-
-
Loading required package: PEcAn.benchmark
-
-
-
Loading required package: PEcAn.remote
-
-
-
Loading required package: PEcAn.workflow
-
-
-
-
-

Load PEcAn Settings File

-

Use the XML settings file (pecan.xml) exactly as in the Demo 1 Basic Run tutorial. See the “Load PEcAn Settings File” section of Demo 1 for a more detailed walkthrough of fields and schema. In this tutorial we focus on settings relevant to this notebook and explain the additional options associated with uncertainty analysis.

-
-

Settings

-

Example settings for this demo live at pecan/documentation/tutorials/Demo_02_Uncertainty_Analysis/pecan.xml and you can read more about the settings in the PEcAn Documentation, and sections focused on ensemble and sensitivity analysis settings in particular.

-

Open that settings file and look at the ensemble and sensitivity analysis sections. You can modify these settings to change the number of ensemble members, the variable to analyze, and the sampling method. Some of the key settings in this demo include:

-

Ensemble size

-

The number of runs in the ensemble is set to 50 in this demo, but a larger ensemble size (100-5000) is often used in practice to better estimate the posterior distribution of the output.

-

Output variable

-

The output variable for the ensemble analysis is set to NPP (Net Primary Productivity). You can change this to other variables like NEE (Net Ecosystem Exchange), LAI (Leaf Area Index), ET (Evapotranspiration), etc. You can also specify multiple variables by providing a vector of variable names (e.g., c("NPP", "NEE", "LAI")) to analyze uncertainty across several ecosystem processes simultaneously.

-

Sampling method

-

The sampling method for generating parameter sets is set to halton in this demo. This tells PEcAn to sample using the Halton sequence, which is a quasi-random sampling method that more efficiently explores parameter space than random sampling. Other options include Latin Hypercube (lhc), which is another quasi-random sequence, as well as uniform that draws random samples. A random sampler requires a larger ensemble size to adequately explore parameter space.

-

Sensitivity analysis quantiles

-

PEcAn’s sensitivity analysis includes a handy shortcut that converts a specified standard deviation into its normal quantile equivalent. In the example pecan.xml, these are set to -1, 1 (the median value, 0, occurs by default) which are converted internally to the 15.9th and 84.1th quantiles of the parameter distribution. You can add more quantiles to explore a wider range of parameter values: {-3, -2, -1, 1, 2, 3} is often used in practice.

-

By working in quantiles relative to each parameter’s distribution, the sensitivity and variance decomposition reflect sensitivity across the range of parameter values. Many sensitivity analyses tools use a fixed perturbation size such as the mean +/- 10%. PEcAn’s SA does not take this approach because it does not capture the uncertainty across the parameter distribution and can not be used for variance decomposition.

-
-
-

Load the settings file

-
-
settings_path <- here::here("documentation/tutorials/Demo_02_Uncertainty_Analysis/pecan.xml")
-
-settings <- PEcAn.settings::read.settings(settings_path)
-
-settings <- PEcAn.settings::prepare.settings(settings)
-
-

See Demo 1 Section 6 for details on what these functions do. Briefly, they read the XML file, convert it into an R list object that PEcAn can use, check that settings are valid, fill in defaults, and create the output directory.

-
-
-
-

Write Model Configuration Files

-

This step generates the model-specific configuration files that will be used to run the ecosystem model. The process involves:

-
    -
  1. Disabling database write operations because we are not using a database
  2. -
-
-
settings$database <- NULL # Disable database operations for this demo
-
-
    -
  1. Generating SIPNET configuration files using the runModule.run.write.configs() function.
  2. -
-
-
settings <- PEcAn.workflow::runModule.run.write.configs(settings)
-
-
Error in postgresqlNewConnection(drv, ...) : 
-  RPosgreSQL error: could not connect root@/var/run/postgresql:5432 on dbname "root": connection to server on socket "/var/run/postgresql/.s.PGSQL.5432" failed: No such file or directory
-    Is the server running locally and accepting connections on that socket?
-
-
-
Loading required package: PEcAn.SIPNET
-
-
-
-
-

Run Model Simulations

-

This section executes the SIPNET simulations and retrieves the results.

-

It uses the function runModule_start_model_runs(settings) to initiate the model runs using the configuration files generated in the previous step.

-
-
PEcAn.workflow::runModule_start_model_runs(settings)
-
-

-  |                                                                            
-  |                                                                      |   0%
-  |                                                                            
-  |=                                                                     |   1%
-  |                                                                            
-  |==                                                                    |   2%
-  |                                                                            
-  |==                                                                    |   3%
-  |                                                                            
-  |===                                                                   |   4%
-  |                                                                            
-  |====                                                                  |   6%
-  |                                                                            
-  |=====                                                                 |   7%
-  |                                                                            
-  |======                                                                |   8%
-  |                                                                            
-  |======                                                                |   9%
-  |                                                                            
-  |=======                                                               |  10%
-  |                                                                            
-  |========                                                              |  11%
-  |                                                                            
-  |=========                                                             |  12%
-  |                                                                            
-  |=========                                                             |  13%
-  |                                                                            
-  |==========                                                            |  15%
-  |                                                                            
-  |===========                                                           |  16%
-  |                                                                            
-  |============                                                          |  17%
-  |                                                                            
-  |=============                                                         |  18%
-  |                                                                            
-  |=============                                                         |  19%
-  |                                                                            
-  |==============                                                        |  20%
-  |                                                                            
-  |===============                                                       |  21%
-  |                                                                            
-  |================                                                      |  22%
-  |                                                                            
-  |=================                                                     |  24%
-  |                                                                            
-  |=================                                                     |  25%
-  |                                                                            
-  |==================                                                    |  26%
-  |                                                                            
-  |===================                                                   |  27%
-  |                                                                            
-  |====================                                                  |  28%
-  |                                                                            
-  |====================                                                  |  29%
-  |                                                                            
-  |=====================                                                 |  30%
-  |                                                                            
-  |======================                                                |  31%
-  |                                                                            
-  |=======================                                               |  33%
-  |                                                                            
-  |========================                                              |  34%
-  |                                                                            
-  |========================                                              |  35%
-  |                                                                            
-  |=========================                                             |  36%
-  |                                                                            
-  |==========================                                            |  37%
-  |                                                                            
-  |===========================                                           |  38%
-  |                                                                            
-  |============================                                          |  39%
-  |                                                                            
-  |============================                                          |  40%
-  |                                                                            
-  |=============================                                         |  42%
-  |                                                                            
-  |==============================                                        |  43%
-  |                                                                            
-  |===============================                                       |  44%
-  |                                                                            
-  |===============================                                       |  45%
-  |                                                                            
-  |================================                                      |  46%
-  |                                                                            
-  |=================================                                     |  47%
-  |                                                                            
-  |==================================                                    |  48%
-  |                                                                            
-  |===================================                                   |  49%
-  |                                                                            
-  |===================================                                   |  51%
-  |                                                                            
-  |====================================                                  |  52%
-  |                                                                            
-  |=====================================                                 |  53%
-  |                                                                            
-  |======================================                                |  54%
-  |                                                                            
-  |=======================================                               |  55%
-  |                                                                            
-  |=======================================                               |  56%
-  |                                                                            
-  |========================================                              |  57%
-  |                                                                            
-  |=========================================                             |  58%
-  |                                                                            
-  |==========================================                            |  60%
-  |                                                                            
-  |==========================================                            |  61%
-  |                                                                            
-  |===========================================                           |  62%
-  |                                                                            
-  |============================================                          |  63%
-  |                                                                            
-  |=============================================                         |  64%
-  |                                                                            
-  |==============================================                        |  65%
-  |                                                                            
-  |==============================================                        |  66%
-  |                                                                            
-  |===============================================                       |  67%
-  |                                                                            
-  |================================================                      |  69%
-  |                                                                            
-  |=================================================                     |  70%
-  |                                                                            
-  |==================================================                    |  71%
-  |                                                                            
-  |==================================================                    |  72%
-  |                                                                            
-  |===================================================                   |  73%
-  |                                                                            
-  |====================================================                  |  74%
-  |                                                                            
-  |=====================================================                 |  75%
-  |                                                                            
-  |=====================================================                 |  76%
-  |                                                                            
-  |======================================================                |  78%
-  |                                                                            
-  |=======================================================               |  79%
-  |                                                                            
-  |========================================================              |  80%
-  |                                                                            
-  |=========================================================             |  81%
-  |                                                                            
-  |=========================================================             |  82%
-  |                                                                            
-  |==========================================================            |  83%
-  |                                                                            
-  |===========================================================           |  84%
-  |                                                                            
-  |============================================================          |  85%
-  |                                                                            
-  |=============================================================         |  87%
-  |                                                                            
-  |=============================================================         |  88%
-  |                                                                            
-  |==============================================================        |  89%
-  |                                                                            
-  |===============================================================       |  90%
-  |                                                                            
-  |================================================================      |  91%
-  |                                                                            
-  |================================================================      |  92%
-  |                                                                            
-  |=================================================================     |  93%
-  |                                                                            
-  |==================================================================    |  94%
-  |                                                                            
-  |===================================================================   |  96%
-  |                                                                            
-  |====================================================================  |  97%
-  |                                                                            
-  |====================================================================  |  98%
-  |                                                                            
-  |===================================================================== |  99%
-  |                                                                            
-  |======================================================================| 100%
-
-
-

The PEcAn workflow will take a longer time to complete than in Demo 1 because we have just asked for over a hundred model runs. Once the runs are complete we will continue.

-
-
-

Fetch Model Outputs

-

Next we convert all of the model output from the previous run to a standard format that PEcAn can use for analysis. This is done using the runModule.get.results() function.

-
-
runModule.get.results(settings)
-
-
-
-

Ensemble and Sensitivity Analysis

-

Next, we use the outputs from the previous step to perform ensemble and sensitivity analyses.

-

Ensemble Analysis: Quantifies uncertainty in model predictions by running multiple simulations with parameters sampled from their uncertainty distributions. This generates probability distributions of model outputs and confidence intervals.

-
-
runModule.run.ensemble.analysis(settings)
-
-
[1] "----- Variable: NPP"
-[1] "----- Running ensemble analysis for site:  Niwot Ridge Forest/LTER NWT1 (US-NR1)"
-
-
-
[1] "----- Done!"
-[1] " "
-[1] "-----------------------------------------------"
-[1] " "
-[1] " "
-
-
-

Sensitivity Analysis: Systematically varies individual parameters to assess their influence on model outputs. This identifies which parameters most strongly affect model predictions and helps prioritize parameter refinement efforts.

-
-
runModule.run.sensitivity.analysis(settings)
-
-
$coef.vars
-         growth_resp_factor          leaf_turnover_rate 
-                 0.52314023                  0.88169612 
-      root_respiration_rate          root_turnover_rate 
-                 0.57750504                  0.57760373 
-                       Amax    leaf_respiration_rate_m2 
-                 0.57764863                  0.55600452 
-                        SLA                       leafC 
-                 0.80223473                  0.02607590 
-                Vm_low_temp                    AmaxFrac 
-                 0.01097613                  0.11546966 
-                    psnTOpt       stem_respiration_rate 
-                 0.03417927                  0.57838935 
-     extinction_coefficient         half_saturation_PAR 
-                 0.13855053                  0.42885852 
-                  dVPDSlope                     dVpdExp 
-                 0.53356551                  0.28896893 
-        veg_respiration_Q10   fine_root_respiration_Q10 
-                 0.17324390                  0.32501552 
-coarse_root_respiration_Q10 
-                 0.32534666 
-
-$elasticities
-         growth_resp_factor          leaf_turnover_rate 
-                 0.00000000                  0.02320464 
-      root_respiration_rate          root_turnover_rate 
-                -0.02508999                  0.05192989 
-                       Amax    leaf_respiration_rate_m2 
-                 2.83476962                 -2.06513816 
-                        SLA                       leafC 
-                 0.81446798                  0.15306831 
-                Vm_low_temp                    AmaxFrac 
-                 1.01795920                  2.48502840 
-                    psnTOpt       stem_respiration_rate 
-                 1.01055079                 -1.43854509 
-     extinction_coefficient         half_saturation_PAR 
-                -0.57229325                 -1.28681308 
-                  dVPDSlope                     dVpdExp 
-                -0.18295933                  0.09271587 
-        veg_respiration_Q10   fine_root_respiration_Q10 
-                 6.50084187                  0.08360650 
-coarse_root_respiration_Q10 
-                -0.23722866 
-
-$sensitivities
-         growth_resp_factor          leaf_turnover_rate 
-               0.000000e+00                9.970835e-11 
-      root_respiration_rate          root_turnover_rate 
-              -2.359663e-12                4.884707e-11 
-                       Amax    leaf_respiration_rate_m2 
-               6.666635e-10               -1.944744e-09 
-                        SLA                       leafC 
-               2.732070e-10                1.422201e-11 
-                Vm_low_temp                    AmaxFrac 
-              -9.748919e-10                1.557956e-08 
-                    psnTOpt       stem_respiration_rate 
-               2.423273e-10               -1.355162e-10 
-     extinction_coefficient         half_saturation_PAR 
-              -5.381744e-09               -3.907003e-10 
-                  dVPDSlope                     dVpdExp 
-              -6.624579e-09                2.181281e-10 
-        veg_respiration_Q10   fine_root_respiration_Q10 
-               1.528495e-08                1.229585e-10 
-coarse_root_respiration_Q10 
-              -3.491744e-10 
-
-$variances
-         growth_resp_factor          leaf_turnover_rate 
-               5.983871e-50                1.785332e-20 
-      root_respiration_rate          root_turnover_rate 
-               4.672753e-21                2.193432e-20 
-                       Amax    leaf_respiration_rate_m2 
-               6.122857e-17                2.785313e-17 
-                        SLA                       leafC 
-               1.096593e-17                3.746338e-22 
-                Vm_low_temp                    AmaxFrac 
-               8.542850e-18                1.822057e-18 
-                    psnTOpt       stem_respiration_rate 
-               5.995813e-18                1.530077e-17 
-     extinction_coefficient         half_saturation_PAR 
-               1.389601e-19                6.768366e-18 
-                  dVPDSlope                     dVpdExp 
-               2.123853e-19                1.622220e-20 
-        veg_respiration_Q10   fine_root_respiration_Q10 
-               2.851950e-17                1.785504e-20 
-coarse_root_respiration_Q10 
-               1.316744e-19 
-
-$partial.variances
-         growth_resp_factor          leaf_turnover_rate 
-               3.571204e-34                1.065495e-04 
-      root_respiration_rate          root_turnover_rate 
-               2.788722e-05                1.309051e-04 
-                       Amax    leaf_respiration_rate_m2 
-               3.654152e-01                1.662288e-01 
-                        SLA                       leafC 
-               6.544522e-02                2.235833e-06 
-                Vm_low_temp                    AmaxFrac 
-               5.098415e-02                1.087413e-02 
-                    psnTOpt       stem_respiration_rate 
-               3.578331e-02                9.131574e-02 
-     extinction_coefficient         half_saturation_PAR 
-               8.293210e-04                4.039395e-02 
-                  dVPDSlope                     dVpdExp 
-               1.267526e-03                9.681491e-05 
-        veg_respiration_Q10   fine_root_respiration_Q10 
-               1.702058e-01                1.065597e-04 
-coarse_root_respiration_Q10 
-               7.858395e-04 
-
-       growth_resp_factor leaf_turnover_rate root_respiration_rate
-15.866       4.701256e-09       4.449915e-09          4.793975e-09
-50           4.701256e-09       4.701256e-09          4.701256e-09
-84.134       4.701256e-09       4.739615e-09          4.632887e-09
-       root_turnover_rate          Amax leaf_respiration_rate_m2          SLA
-15.866       4.437930e-09 -7.392576e-09             9.995320e-09 7.454526e-10
-50           4.701256e-09  4.701256e-09             4.701256e-09 4.701256e-09
-84.134       4.771365e-09  1.080759e-08            -8.726093e-10 4.574289e-10
-              leafC  Vm_low_temp     AmaxFrac       psnTOpt
-15.866 4.689967e-09 6.977459e-09 3.003852e-09 -5.232746e-09
-50     4.701256e-09 4.701256e-09 4.701256e-09  4.701256e-09
-84.134 4.727503e-09 1.776842e-09 6.194027e-09  7.597368e-09
-       stem_respiration_rate extinction_coefficient half_saturation_PAR
-15.866          9.335914e-09           5.145403e-09        8.187772e-09
-50              4.701256e-09           4.701256e-09        4.701256e-09
-84.134          8.203046e-11           4.264066e-09        2.050097e-09
-          dVPDSlope      dVpdExp veg_respiration_Q10 fine_root_respiration_Q10
-15.866 5.155744e-09 4.511517e-09       -3.046701e-09              4.466264e-09
-50     4.701256e-09 4.701256e-09        4.701256e-09              4.701256e-09
-84.134 4.070785e-09 4.809312e-09        9.472557e-09              4.768234e-09
-       coarse_root_respiration_Q10
-15.866                5.142842e-09
-50                    4.701256e-09
-84.134                4.284874e-09
-
-
-
-
-

PEcAn Outputs

-
-

Output Directory Structure

-

These are the key folders and files that will be created under the directory defined by settings$outdir (e.g., demo_outdir in the example). The file contents are described in the next section.

-

We discussed the output directory in Demo 1 (Basic Run), but now we have three new folders that contain outputs from the sensitivity, ensemble, and variance decomposition analyses. Here we focus on the additional outputs generated by the ensemble and sensitivity analyses.

-
demo_outdir/
-├── run/                                    # Configuration & execution metadata
-│   ├── runs.txt                           # List of run IDs (SA and ensemble runs)
-│   ├── ENS-*-*/                          # Ensemble run directories (e.g., ENS-00001--1/)
-│   └── SA-*-*/                           # Sensitivity analysis run directories
-├── out/                                   # Raw model outputs by run ID
-│   └── <runid>/                          # E.g., daily or sub-daily SIPNET output files
-├── ensemble.analysis.*.pdf                # Ensemble analysis plots
-├── ensemble.output.*.Rdata               # Raw ensemble outputs
-├── ensemble.samples.*.Rdata              # Parameter samples used for ensemble
-├── ensemble.ts.*.Rdata                   # Time series data from ensemble
-├── samples.Rdata                         # Parameter samples for both SA and ensemble
-├── sensitivity.output.*.Rdata            # SA model outputs
-├── sensitivity.results.*.Rdata           # Processed SA results
-├── sensitivity.samples.*.Rdata           # SA parameter samples
-├── variance.decomposition.*.pdf          # Variance decomposition analysis
-├── pft/                                  # Parameter (prior/posterior) files per PFT
-│   └── temperate.coniferous/
-└── sipnet                                # SIPNET binary (downloaded earlier)
-
-

Model outputs and logs

-
    -
  • Standardized netCDF files ([year].nc) for analysis and visualization
  • -
  • Raw model output (for SIPNET, e.g., sipnet.out per run)
  • -
  • logfile.txt with model and workflow messages
  • -
  • Note: pft/ contains parameter files used in estimation; see the parameter-estimation tutorial (Demo 3) for details
  • -
-
-
-
-
-

Understanding PEcAn Uncertainty Analysis Outputs

-

After running ensemble and sensitivity analyses, PEcAn generates several important outputs that help you understand model uncertainty and parameter sensitivity.

-

The samples.Rdata file contains the parameter values used in the sensitivity and ensemble runs. It stores two objects, sa.samples and ensemble.samples, which are the parameter values for the sensitivity analysis and ensemble runs, respectively.

-
-

Ensemble Analysis Outputs

-

The ensemble analysis produces:

-
    -
  • ensemble.Rdata: Contains ensemble.output object with model predictions for all ensemble members
  • -
  • ensemble.analysis.[RunID].[Variable].[StartYear].[EndYear].pdf: Histogram and boxplot of ensemble predictions
  • -
  • ensemble.ts.[RunID].[Variable].[StartYear].[EndYear].pdf: Time-series plot showing ensemble mean, median, and 95% confidence intervals
  • -
-
-
-

Sensitivity Analysis Outputs

-

The sensitivity analysis generates:

-
    -
  • sensitivity.analysis.[RunID].[Variable].[StartYear].[EndYear].pdf: Raw data points from univariate analyses with spline fits.
  • -
  • sensitivity.output.[RunID].[Variable].[StartYear].[EndYear].Rdata: Model outputs corresponding to parameter variations.
  • -
  • sensitivity.analysis.[RunID].[Variable].[StartYear].[EndYear].pdf shows the raw data points from univariate one-at-a-time analyses and spline fits through the points. Open this file to determine which parameters are most and least sensitive.
  • -
-
-
-

Variance Decomposition Outputs

-

The variance decomposition produces:

-
    -
  • variance.decomposition.[RunID].[Variable].[StartYear].[EndYear].pdf: Three-column analysis showing: -
      -
    • Coefficient of variation (normalized posterior variance)
    • -
    • Elasticity (normalized sensitivity)
    • -
    • Partial standard deviation of each parameter
    • -
  • -
-
-
-

Interpreting the Results

-

Variance Decomposition Analysis:

-
    -
  • Parameters are sorted by their contribution to model output uncertainty (the right column).
  • -
  • Identify parameters that are: -
      -
    • Highly sensitive but low uncertainty.
    • -
    • Highly uncertain but low sensitivity.
    • -
    • Both sensitive and uncertain.
    • -
  • -
  • Identify parameters that are both sensitive and uncertain for future constraint with data or expert knowledge.
  • -
  • Potential gotchas: -
      -
    • Flat sensitivity curves: check that parameter values were correctly generated and read by the model.
    • -
    • Parameters with high uncertainty: consider revising priors.
    • -
    • Multi-modal or otherwise unexpected parameter distributions: check that parameter was specified correctly.
    • -
  • -
-

Choose the parameter that you think provides the most efficient means of reducing model uncertainty and propose how you might best reduce uncertainty in this process. In making this choice remember that not all processes in models can be directly observed, and that the cost-per-sample for different measurements can vary tremendously (and thus the parameter you measure next is not always the one contributing the most to model variability). Also consider the role of parameter uncertainty versus model sensitivity in justifying your choice of what parameters to constrain.

-
-
-
-

Visualize Uncertainty Analysis Results

-

This section loads the results from the uncertainty analyses and generates plots directly in the notebook. This provides an immediate view of the ensemble time series, sensitivity plots, and variance decomposition.

-
-

Ensemble Analysis Visualization

-

Here we visualize the results of the ensemble analysis. It shows the overall distribution of the model output and how the output and its uncertainty change over time.

-

This section reproduces the plots saved in the ensemble.analysis/ folder in order to show the user how to access and visualize the results programmatically so that they can further investigate output and customize plots.

-
-
# --- 1. Define Helper Variables ---
-# Extract key variables from the settings object to simplify file path construction
-# and plotting. This makes the code cleaner and easier to read.
-variable <- settings$ensemble$variable
-pft <- settings$pfts[[1]]
-start.year <- lubridate::year(settings$run$start.date)
-end.year <- lubridate::year(settings$run$end.date)
-ensemble.id <- if (!is.null(settings$ensemble$id)) settings$ensemble$id else "NOENSEMBLEID"
-
-# --- 2. Load and Plot Ensemble Output Distribution ---
-# This section visualizes the distribution of the ensemble model runs.
-# It generates a histogram and a boxplot to show the central tendency, spread,
-# and shape of the output variable's distribution.
-
-# Construct the path to the ensemble output file
-ens_file <- PEcAn.uncertainty::ensemble.filename(
-  settings,
-  prefix = "ensemble.output",
-  ensemble.id = ensemble.id,
-  variable = variable,
-  start.year = start.year,
-  end.year = end.year
-)
-
-# Check if the file exists, then load and plot the data
-if (file.exists(ens_file)) {
-  ens_env <- new.env()
-  load(ens_file, envir = ens_env)
-  ens_data <- as.numeric(unlist(ens_env$ensemble.output))
-
-  # Define units for plot labels
-  units <- paste0(variable, " (", PEcAn.utils::mstmipvar(variable, silent = TRUE)$units, ")")
-
-  # Create side-by-side histogram and boxplot
-  par(mfrow = c(1, 2), mar = c(4, 4.8, 1, 2))
-  hist(ens_data, xlab = units, main = "Ensemble Distribution", cex.lab = 1.4, col = "grey85")
-  box(lwd = 2.2)
-  boxplot(ens_data, ylab = units, main = "Ensemble Boxplot", col = "grey85", cex.lab = 1.5)
-  box(lwd = 2.2)
-  par(mfrow = c(1, 1))
-} else {
-  PEcAn.logger::logger.warn("Could not find ensemble output file:", ens_file)
-}
-
-
-# --- 3. Plot Ensemble Time Series ---
-# This section visualizes the ensemble results over time, showing the mean,
-# median, and 95% confidence interval of the model output.
-ens_ts_data <- PEcAn.uncertainty::read.ensemble.ts(settings, variable = variable)
-
-
[1] "----- Variable: NPP"
-[1] "----- Reading ensemble output ------"
-[1] "ENS-00001--1"
-[1] "ENS-00002--1"
-[1] "ENS-00003--1"
-[1] "ENS-00004--1"
-[1] "ENS-00005--1"
-[1] "ENS-00006--1"
-[1] "ENS-00007--1"
-[1] "ENS-00008--1"
-[1] "ENS-00009--1"
-[1] "ENS-00010--1"
-[1] "ENS-00011--1"
-[1] "ENS-00012--1"
-[1] "ENS-00013--1"
-[1] "ENS-00014--1"
-[1] "ENS-00015--1"
-[1] "ENS-00016--1"
-[1] "ENS-00017--1"
-[1] "ENS-00018--1"
-[1] "ENS-00019--1"
-[1] "ENS-00020--1"
-[1] "ENS-00021--1"
-[1] "ENS-00022--1"
-[1] "ENS-00023--1"
-[1] "ENS-00024--1"
-[1] "ENS-00025--1"
-[1] "ENS-00026--1"
-[1] "ENS-00027--1"
-[1] "ENS-00028--1"
-[1] "ENS-00029--1"
-[1] "ENS-00030--1"
-[1] "ENS-00031--1"
-[1] "ENS-00032--1"
-[1] "ENS-00033--1"
-[1] "ENS-00034--1"
-[1] "ENS-00035--1"
-[1] "ENS-00036--1"
-[1] "ENS-00037--1"
-[1] "ENS-00038--1"
-[1] "ENS-00039--1"
-[1] "ENS-00040--1"
-[1] "ENS-00041--1"
-[1] "ENS-00042--1"
-[1] "ENS-00043--1"
-[1] "ENS-00044--1"
-[1] "ENS-00045--1"
-[1] "ENS-00046--1"
-[1] "ENS-00047--1"
-[1] "ENS-00048--1"
-[1] "ENS-00049--1"
-[1] "ENS-00050--1"
-
-
if (!is.null(ens_ts_data)) {
-  PEcAn.uncertainty::ensemble.ts(ens_ts_data)
-}
-
-
[1] "------ Generating ensemble time-series plot ------"
-
-
-
-
-

-
-
-
-
-
-
-

Sensitivity and Variance Decomposition Visualization

-

This block visualizes the results of the sensitivity analysis. The plots show how sensitive the model output is to changes in each parameter and which parameters contribute most to the overall uncertainty.

-
-
# --- 1. Load Sensitivity Analysis Results ---
-# This section loads the saved sensitivity analysis data, which contains the
-# outputs needed to generate the sensitivity and variance decomposition plots.
-
-# Construct the path to the sensitivity analysis results file
-sens_file <- file.path(
-  settings$outdir,
-  paste0("sensitivity.results", ".", ensemble.id, ".", variable, ".", start.year, ".", end.year, ".Rdata")
-)
-
-# Check if the file exists, then load the data and generate plots
-if (file.exists(sens_file)) {
-  sens_env <- new.env()
-  load(sens_file, envir = sens_env)
-  sensitivity.results <- sens_env$sensitivity.results
-
-  # --- 2. Generate Sensitivity Plots ---
-  # These plots show how the model output changes as each parameter is varied
-  # one at a time, helping to identify which parameters have the strongest influence.
-  sa_plots <- PEcAn.uncertainty::plot_sensitivities(
-    sensitivity.results[[pft$name]]$sensitivity.output
-  )
-  print(do.call(gridExtra::grid.arrange, c(sa_plots, ncol = floor(sqrt(length(sa_plots))))))
-
-  # --- 3. Generate Variance Decomposition Plots ---
-  # These plots break down the total output variance into contributions from
-  # each parameter, highlighting the most important sources of uncertainty.
-  vd_plots <- PEcAn.uncertainty::plot_variance_decomposition(
-    sensitivity.results[[pft$name]]$variance.decomposition.output
-  )
-  print(do.call(gridExtra::grid.arrange, c(vd_plots, ncol = 4)))
-} else {
-  PEcAn.logger::logger.warn("Could not find sensitivity results file:", sens_file)
-}
-
-
-
-
-

Customizing Ensemble Analysis Parameters (Optional)

-
-

(Optional) Use this section only if you want to override the default ensemble analysis parameters. Skip if defaults are sufficient.

-
-

Important: If you modify the ensemble analysis parameters in this section, re-run Section Section 7 and then Section Section 10 to regenerate outputs and plots.

-
-
-
# Set the number of ensemble members (model runs)
-settings$ensemble$size <- 50
-
-# Specify the variable(s) to be analyzed in the ensemble
-# Single variable:
-settings$ensemble$variable <- "NEE"
-# Multiple variables (uncomment to use):
-# settings$ensemble$variable <- c("NEE", "NPP", "LAI")
-
-# Choose the method for sampling the parameter space (options: "uniform", "lhc", "halton", "sobol", "torus")
-settings$ensemble$samplingspace$parameters$method <- "halton"
-
-
-
-
-

Customizing Sensitivity Analysis Parameters (Optional)

-
-

(Optional) Use this section only if you want to override the default sensitivity analysis parameters. Skip if defaults are sufficient.

-
-

Important: If you modify the sensitivity analysis parameters in this section, re-run Section Section 7 and then Section Section 10 to regenerate outputs and plots.

-
-
-
# Set the quantiles (in standard deviations) for parameter distribution in sensitivity analysis
-settings$sensitivity.analysis$quantiles$sigma <- c(-2, -1, 1, 2)
-
-# Specify the variable to be analyzed in sensitivity analysis
-settings$sensitivity.analysis$variable <- "NEE"
-
-
-
-
-

Extract Model Results and Prepare for Analysis

-

After the model simulation completes, we need to extract the results and prepare them for analysis. This involves:

-
    -
  1. Reading the run ID
  2. -
  3. Setting up output paths
  4. -
  5. Defining time period
  6. -
  7. Loading model output
  8. -
-
-
runid <- as.character(read.table(paste(settings$outdir, "/run/", "runs.txt", sep = ""))[1, 1]) # Note: if you are using an xml from a run with multiple ensembles this line will provide only the first run id
-# You can change [1,1] to [10,1], [5,1], etc. to select different run IDs from runs.txt
-# For example: [10,1] selects the 10th run ID, [5,1] selects the 5th run ID
-outdir <- paste(settings$outdir, "/out/", runid, sep = "")
-start.year <- as.numeric(lubridate::year(settings$run$start.date))
-end.year <- as.numeric(lubridate::year(settings$run$end.date))
-model_output <- PEcAn.utils::read.output(
-  runid,
-  outdir,
-  start.year,
-  end.year,
-  variables = NULL,
-  dataframe = TRUE,
-  verbose = FALSE
-)
-available_vars <- names(model_output)[!names(model_output) %in% c("posix", "time_bounds")]
-
-
-
-

Display Available Model Variables

-

This section shows all the variables that are available in the model output. These variables represent different ecosystem processes and states that the model has simulated.

-
-
vars_df <- PEcAn.utils::standard_vars |>
-  dplyr::select(
-    Variable = Variable.Name,
-    Description = Long.name
-  ) |>
-  dplyr::filter(Variable %in% available_vars) |>
-  # TODO: add year to PEcAn.utils::standard vars
-  dplyr::bind_rows(
-    dplyr::tibble(
-      Variable = "year",
-      Description = "Year"
-    )
-  )
-
-vars_df$Description[is.na(vars_df$Description)] <- "(No description available)"
-knitr::kable(vars_df, caption = "Model Output Variables and Descriptions")
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Model Output Variables and Descriptions
VariableDescription
GPPGross Primary Productivity
NEENet Ecosystem Exchange
TotalRespTotal Respiration
AutoRespAutotrophic Respiration
HeteroRespHeterotrophic Respiration
SoilRespSoil Respiration
NPPNet Primary Productivity
GWBIGross Woody Biomass Increment
TotLivBiomTotal living biomass
AGBTotal aboveground biomass
LAILeaf Area Index
leaf_carbon_contentLeaf Carbon Content
fine_root_carbon_contentFine Root Carbon Content
coarse_root_carbon_contentCoarse Root Carbon Content
AbvGrndWoodAbove ground woody biomass
TotSoilCarbTotal Soil Carbon
litter_carbon_contentLitter Carbon Content
QleLatent heat
TranspTotal transpiration
SoilMoistAverage Layer Soil Moisture
SoilMoistFracAverage Layer Fraction of Saturation
SWESnow Water Equivalent
litter_mass_content_of_waterAverage layer litter moisture
yearYear
-
-
-
-
-

Visualize Model Results

-

This section provides examples of how to create time series plots of different model variables. The examples cover various ecosystem processes including carbon fluxes, carbon pools, water variables, and structural variables like Leaf Area Index (LAI).

-
-

Plot Carbon Fluxes

-
-
# Plot Gross Primary Productivity (GPP) and Net Primary Productivity (NPP)
-plot(model_output$posix, model_output$GPP,
-  type = "l",
-  col = "green",
-  xlab = "Date",
-  ylab = "Carbon Flux (kg C m-2 s-1)",
-  main = paste("Carbon Fluxes Over Time — PEcAn", runid)
-)
-lines(model_output$posix, model_output$NPP, col = "blue")
-legend("topright", legend = c("GPP", "NPP"), col = c("green", "blue"), lty = 1)
-
-
-
-

-
-
-
-
-
-
-

Plot Carbon Pools

-
-
# Plot Total Live Biomass and Total Soil Carbon
-plot(model_output$posix, model_output$TotLivBiom,
-  type = "l",
-  col = "darkgreen",
-  xlab = "Date",
-  ylab = "Carbon Pool (kg C m-2)",
-  main = paste("Carbon Pools Over Time — PEcAn", runid)
-)
-lines(model_output$posix, model_output$TotSoilCarb, col = "brown")
-legend("topright", legend = c("Total Live Biomass", "Total Soil Carbon"), col = c("darkgreen", "brown"), lty = 1)
-
-
-
-

-
-
-
-
-
-
-

Plot Water Variables

-
-
# Plot Soil Moisture and Snow Water Equivalent
-plot(model_output$posix, model_output$SoilMoist,
-  type = "l",
-  col = "blue",
-  xlab = "Date",
-  ylab = "Soil Moisture (kg m-2)",
-  main = paste("Soil Moisture Over Time — PEcAn", runid)
-)
-lines(model_output$posix, model_output$SWE, col = "lightblue")
-legend("topright", legend = c("Soil Moisture", "Snow Water Equivalent"), col = c("blue", "lightblue"), lty = 1)
-
-
-
-

-
-
-
-
-
-
-

Plot LAI and Biomass

-
-
# Plot Leaf Area Index (LAI) and Above Ground Wood
-plot(model_output$posix, model_output$LAI,
-  type = "l",
-  col = "darkgreen",
-  xlab = "Date",
-  ylab = "LAI (m2 m-2)",
-  main = paste("Leaf Area Index Over Time — PEcAn", runid)
-)
-lines(model_output$posix, model_output$AbvGrndWood, col = "brown")
-legend("topright", legend = c("LAI", "Above Ground Wood"), col = c("darkgreen", "brown"), lty = 1)
-
-
-
-

-
-
-
-
-
-
-
-

Conclusion

-

This notebook demonstrated how to set up, run, and analyze a PEcAn ecosystem model workflow programmatically. You can now modify parameters, try different models, or extend the analysis as needed.

-

Try editing the pecan.xml file. Give it a new name and update the settings_path variable at the beginning of this Demo to point to the new file. See how the changes affect the model output!

-
-
-

Further Exploration

-

The next set of tutorials will focus on the process of data assimilation and parameter estimation. The next two steps are in “.Rmd” files which can be viewed online.

-

Assimilation ‘by hand’

-

Explore how model error changes as a function of parameter value (i.e. data assimilation ‘by hand’)

-

MCMC Concepts Explore Bayesian MCMC concepts using the photosynthesis module

-

More info about tools, analyses, and specific tasks…

-

Additional information about specific tasks (adding sites, models, data; software updates; etc.) and analyses (e.g. data assimilation) can be found in the PEcAn documentation

-

If you encounter a problem with PEcAn that’s not covered in the documentation, or if PEcAn is missing functionality you need, please search known bugs and issues, submit a bug report, or ask a question in our chat room.

-
-
-

Clean Up Workflow Output (Optional)

-

If you want to remove all files and directories created by this workflow and start fresh, you can run the following code. This will delete the entire output directory specified in your settings. Use with caution!

-
-
# WARNING: This will permanently delete all workflow output files!
-# Uncomment the line below to enable cleanup.
-# fs::dir_delete(settings$outdir)
-
-
-
-

Session Information

-
-

PEcAn package versions.

-
-
PEcAn.all::pecan_version()
-
-
 package               v1.9.0 installed  source              
- PEcAn.all             1.9.0  1.9.0.9000 local (/pecan/bas...
- PEcAn.allometry       1.7.4  1.7.4.9000 local (/pecan/mod...
- PEcAn.assim.batch     1.9.0  1.9.0.9000 local (/pecan/mod...
- PEcAn.BASGRA          1.8.1  1.8.1.9000 local (/pecan/mod...
- PEcAn.benchmark       1.7.4  1.7.4.9000 local (/pecan/mod...
- PEcAn.BIOCRO          1.7.4  1.7.5      local (/pecan/mod...
- PEcAn.CABLE           1.7.4  NA         NA                  
- PEcAn.CLM45           1.7.4  1.7.4.9000 local (/pecan/mod...
- PEcAn.DALEC           1.7.4  1.7.5      local (/pecan/mod...
- PEcAn.data.atmosphere 1.9.0  1.9.1      local (/pecan/mod...
- PEcAn.data.land       1.8.1  1.8.2      local (/pecan/mod...
- PEcAn.data.mining     1.7.4  NA         NA                  
- PEcAn.data.remote     1.9.0  1.9.1      local (/pecan/mod...
- PEcAn.DB              1.8.1  1.8.1.9000 local (/pecan/bas...
- PEcAn.dvmdostem       1.7.4  1.7.5      local (/pecan/mod...
- PEcAn.ED2             1.8.1  1.8.2      local (/pecan/mod...
- PEcAn.emulator        1.8.1  1.8.1.9000 local (/pecan/mod...
- PEcAn.FATES           1.8.0  1.8.1      local (/pecan/mod...
- PEcAn.GDAY            1.7.4  1.7.5      local (/pecan/mod...
- PEcAn.JULES           1.7.4  1.7.5      local (/pecan/mod...
- PEcAn.LDNDC           1.0.1  1.0.2      local (/pecan/mod...
- PEcAn.LINKAGES        1.7.4  1.7.5      local (/pecan/mod...
- PEcAn.logger          1.8.3  1.8.4      local (/pecan/bas...
- PEcAn.LPJGUESS        1.8.0  1.8.1      local (/pecan/mod...
- PEcAn.MA              1.7.4  1.7.4.9000 local (/pecan/mod...
- PEcAn.MAAT            1.7.4  1.7.5      local (/pecan/mod...
- PEcAn.MAESPA          1.7.4  1.7.5      local (/pecan/mod...
- PEcAn.ModelName       1.8.1  1.8.1.9000 local (/pecan/mod...
- PEcAn.photosynthesis  1.7.4  1.7.4.9000 local (/pecan/mod...
- PEcAn.PRELES          1.7.4  NA         NA                  
- PEcAn.priors          1.7.4  1.7.4.9000 local (/pecan/mod...
- PEcAn.qaqc            1.7.4  1.7.4.9000 local (/pecan/bas...
- PEcAn.remote          1.9.0  1.9.0.9000 local (/pecan/bas...
- PEcAn.settings        1.9.0  1.9.1      local (/pecan/bas...
- PEcAn.SIBCASA         0.0.2  0.0.3      local (/pecan/mod...
- PEcAn.SIPNET          1.9.0  1.9.1      local (/pecan/mod...
- PEcAn.STICS           1.8.1  1.8.2      local (/pecan/mod...
- PEcAn.uncertainty     1.8.1  1.8.2      local (/pecan/mod...
- PEcAn.utils           1.8.1  1.8.2      local (/pecan/bas...
- PEcAn.visualization   1.8.1  1.8.1.9000 local (/pecan/bas...
- PEcAn.workflow        1.9.0  1.9.0.9000 local (/pecan/bas...
- PEcAnAssimSequential  1.9.0  1.9.0.9000 local (/pecan/mod...
- PEcAnRTM              1.7.4  1.9.0.9000 local (/pecan/mod...
-
-
-
-
-

R session information:

-
-
sessionInfo()
-
-
R version 4.4.3 (2025-02-28)
-Platform: x86_64-pc-linux-gnu
-Running under: Ubuntu 24.04.2 LTS
-
-Matrix products: default
-BLAS:   /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3 
-LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.26.so;  LAPACK version 3.12.0
-
-locale:
- [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C              
- [3] LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8    
- [5] LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8   
- [7] LC_PAPER=en_US.UTF-8       LC_NAME=C                 
- [9] LC_ADDRESS=C               LC_TELEPHONE=C            
-[11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       
-
-time zone: Etc/UTC
-tzcode source: system (glibc)
-
-attached base packages:
-[1] stats     graphics  grDevices utils     datasets  methods   base     
-
-other attached packages:
- [1] PEcAn.SIPNET_1.9.1           PEcAn.all_1.9.0.9000        
- [3] PEcAn.workflow_1.9.0.9000    PEcAn.remote_1.9.0.9000     
- [5] PEcAn.benchmark_1.7.4.9000   PEcAn.priors_1.7.4.9000     
- [7] PEcAn.emulator_1.8.1.9000    PEcAn.assim.batch_1.9.0.9000
- [9] PEcAn.data.remote_1.9.1      PEcAn.data.land_1.8.2       
-[11] PEcAn.data.atmosphere_1.9.1  PEcAn.uncertainty_1.8.2     
-[13] PEcAn.utils_1.8.2            PEcAn.logger_1.8.4          
-[15] PEcAn.MA_1.7.4.9000          PEcAn.settings_1.9.1        
-[17] PEcAn.DB_1.8.1.9000         
-
-loaded via a namespace (and not attached):
- [1] PEcAn.qaqc_1.7.4.9000           DBI_1.2.3                      
- [3] gridExtra_2.3                   PEcAn.allometry_1.7.4.9000     
- [5] rlang_1.1.5                     magrittr_2.0.3                 
- [7] furrr_0.3.1                     e1071_1.7-16                   
- [9] compiler_4.4.3                  vctrs_0.6.5                    
-[11] stringr_1.5.1                   pkgconfig_2.0.3                
-[13] PEcAn.MAESPA_1.7.5              fastmap_1.2.0                  
-[15] PEcAn.ED2_1.8.2                 labeling_0.4.3                 
-[17] PEcAn.dvmdostem_1.7.5           PEcAn.ModelName_1.8.1.9000     
-[19] rmarkdown_2.29                  pracma_2.4.4                   
-[21] sessioninfo_1.2.3               purrr_1.0.4                    
-[23] xfun_0.52                       PEcAn.JULES_1.7.5              
-[25] jsonlite_2.0.0                  PEcAn.LINKAGES_1.7.5           
-[27] PEcAn.SIBCASA_0.0.3             parallel_4.4.3                 
-[29] R6_2.6.1                        PEcAn.DALEC_1.7.5              
-[31] stringi_1.8.7                   PEcAn.CLM45_1.7.4.9000         
-[33] RPostgreSQL_0.7-8               parallelly_1.43.0              
-[35] numDeriv_2016.8-1.1             lubridate_1.9.4                
-[37] Rcpp_1.0.14                     iterators_1.0.14               
-[39] knitr_1.50                      PEcAnAssimSequential_1.9.0.9000
-[41] igraph_2.1.4                    rngWELL_0.10-10                
-[43] timechange_0.3.0                tidyselect_1.2.1               
-[45] abind_1.4-8                     yaml_2.3.10                    
-[47] PEcAn.LPJGUESS_1.8.1            codetools_0.2-20               
-[49] listenv_0.9.1                   lattice_0.22-6                 
-[51] tibble_3.2.1                    withr_3.0.2                    
-[53] coda_0.19-4.1                   evaluate_1.0.3                 
-[55] future_1.34.0                   sf_1.0-20                      
-[57] units_0.8-7                     proxy_0.4-27                   
-[59] PEcAn.BASGRA_1.8.1.9000         pillar_1.10.2                  
-[61] PEcAn.BIOCRO_1.7.5              KernSmooth_2.23-26             
-[63] foreach_1.5.2                   nimble_1.3.0                   
-[65] ncdf4_1.24                      generics_0.1.3                 
-[67] rprojroot_2.0.4                 ggplot2_3.5.2                  
-[69] munsell_0.5.1                   scales_1.3.0                   
-[71] randtoolbox_2.0.5               globals_0.16.3                 
-[73] PEcAn.MAAT_1.7.5                PEcAn.STICS_1.8.2              
-[75] class_7.3-23                    glue_1.8.0                     
-[77] tools_4.4.3                     data.table_1.17.0              
-[79] XML_3.99-0.18                   grid_4.4.3                     
-[81] PEcAn.visualization_1.8.1.9000  PEcAn.photosynthesis_1.7.4.9000
-[83] colorspace_2.1-1                cli_3.6.4                      
-[85] PEcAnRTM_1.9.0.9000             dplyr_1.1.4                    
-[87] PEcAn.GDAY_1.7.5                gtable_0.3.6                   
-[89] PEcAn.FATES_1.8.1               digest_0.6.37                  
-[91] classInt_0.4-11                 PEcAn.LDNDC_1.0.2              
-[93] rjson_0.2.23                    htmlwidgets_1.6.4              
-[95] farver_2.1.2                    htmltools_0.5.8.1              
-[97] lifecycle_1.0.4                 here_1.0.1                     
-
-
-
-
- -
- - -
- - - - - \ No newline at end of file diff --git a/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/uncertainty_files/figure-html/plot-carbon-fluxes-1.png b/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/uncertainty_files/figure-html/plot-carbon-fluxes-1.png deleted file mode 100644 index 8fe6bec90..000000000 Binary files a/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/uncertainty_files/figure-html/plot-carbon-fluxes-1.png and /dev/null differ diff --git a/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/uncertainty_files/figure-html/plot-carbon-pools-1.png b/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/uncertainty_files/figure-html/plot-carbon-pools-1.png deleted file mode 100644 index c21fc5d2f..000000000 Binary files a/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/uncertainty_files/figure-html/plot-carbon-pools-1.png and /dev/null differ diff --git a/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/uncertainty_files/figure-html/plot-lai-biomass-1.png b/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/uncertainty_files/figure-html/plot-lai-biomass-1.png deleted file mode 100644 index c33ae1268..000000000 Binary files a/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/uncertainty_files/figure-html/plot-lai-biomass-1.png and /dev/null differ diff --git a/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/uncertainty_files/figure-html/plot-water-variables-1.png b/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/uncertainty_files/figure-html/plot-water-variables-1.png deleted file mode 100644 index 5fca5bf7d..000000000 Binary files a/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/uncertainty_files/figure-html/plot-water-variables-1.png and /dev/null differ diff --git a/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/uncertainty_files/figure-html/visualize-ensemble-results-1.png b/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/uncertainty_files/figure-html/visualize-ensemble-results-1.png deleted file mode 100644 index 87b78c07e..000000000 Binary files a/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/uncertainty_files/figure-html/visualize-ensemble-results-1.png and /dev/null differ diff --git a/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/uncertainty_files/libs/bootstrap/bootstrap-icons.css b/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/uncertainty_files/libs/bootstrap/bootstrap-icons.css deleted file mode 100644 index 285e4448f..000000000 --- a/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/uncertainty_files/libs/bootstrap/bootstrap-icons.css +++ /dev/null @@ -1,2078 +0,0 @@ -/*! - * Bootstrap Icons v1.11.1 (https://icons.getbootstrap.com/) - * Copyright 2019-2023 The Bootstrap Authors - * Licensed under MIT (https://github.com/twbs/icons/blob/main/LICENSE) - */ - -@font-face { - font-display: block; - font-family: "bootstrap-icons"; - src: -url("./bootstrap-icons.woff?2820a3852bdb9a5832199cc61cec4e65") format("woff"); -} - -.bi::before, -[class^="bi-"]::before, -[class*=" bi-"]::before { - display: inline-block; - font-family: bootstrap-icons !important; - font-style: normal; - font-weight: normal !important; - font-variant: normal; - text-transform: none; - line-height: 1; - vertical-align: -.125em; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -.bi-123::before { content: "\f67f"; } -.bi-alarm-fill::before { content: "\f101"; } -.bi-alarm::before { content: "\f102"; } -.bi-align-bottom::before { content: "\f103"; } -.bi-align-center::before { content: "\f104"; } -.bi-align-end::before { content: "\f105"; } -.bi-align-middle::before { content: "\f106"; } -.bi-align-start::before { content: "\f107"; } -.bi-align-top::before { content: "\f108"; } -.bi-alt::before { content: "\f109"; } -.bi-app-indicator::before { content: "\f10a"; } -.bi-app::before { content: "\f10b"; } -.bi-archive-fill::before { content: "\f10c"; } -.bi-archive::before { content: "\f10d"; } -.bi-arrow-90deg-down::before { content: "\f10e"; } -.bi-arrow-90deg-left::before { content: "\f10f"; } -.bi-arrow-90deg-right::before { content: "\f110"; } -.bi-arrow-90deg-up::before { content: "\f111"; } -.bi-arrow-bar-down::before { content: "\f112"; } -.bi-arrow-bar-left::before { content: "\f113"; } -.bi-arrow-bar-right::before { content: "\f114"; } -.bi-arrow-bar-up::before { content: "\f115"; } -.bi-arrow-clockwise::before { content: "\f116"; } -.bi-arrow-counterclockwise::before { content: "\f117"; } -.bi-arrow-down-circle-fill::before { content: "\f118"; } -.bi-arrow-down-circle::before { content: "\f119"; } -.bi-arrow-down-left-circle-fill::before { content: "\f11a"; } -.bi-arrow-down-left-circle::before { content: "\f11b"; } -.bi-arrow-down-left-square-fill::before { content: "\f11c"; } -.bi-arrow-down-left-square::before { content: "\f11d"; } -.bi-arrow-down-left::before { content: "\f11e"; } -.bi-arrow-down-right-circle-fill::before { content: "\f11f"; } -.bi-arrow-down-right-circle::before { content: "\f120"; } -.bi-arrow-down-right-square-fill::before { content: "\f121"; } -.bi-arrow-down-right-square::before { content: "\f122"; } -.bi-arrow-down-right::before { content: "\f123"; } -.bi-arrow-down-short::before { content: "\f124"; } -.bi-arrow-down-square-fill::before { content: "\f125"; } -.bi-arrow-down-square::before { content: "\f126"; } -.bi-arrow-down-up::before { content: "\f127"; } -.bi-arrow-down::before { content: "\f128"; } -.bi-arrow-left-circle-fill::before { content: "\f129"; } -.bi-arrow-left-circle::before { content: "\f12a"; } -.bi-arrow-left-right::before { content: "\f12b"; } -.bi-arrow-left-short::before { content: "\f12c"; } -.bi-arrow-left-square-fill::before { content: "\f12d"; } -.bi-arrow-left-square::before { content: "\f12e"; } -.bi-arrow-left::before { content: "\f12f"; } -.bi-arrow-repeat::before { content: "\f130"; } -.bi-arrow-return-left::before { content: "\f131"; } -.bi-arrow-return-right::before { content: "\f132"; } -.bi-arrow-right-circle-fill::before { content: "\f133"; } -.bi-arrow-right-circle::before { content: "\f134"; } -.bi-arrow-right-short::before { content: "\f135"; } -.bi-arrow-right-square-fill::before { content: "\f136"; } -.bi-arrow-right-square::before { content: "\f137"; } -.bi-arrow-right::before { content: "\f138"; } -.bi-arrow-up-circle-fill::before { content: "\f139"; } -.bi-arrow-up-circle::before { content: "\f13a"; } -.bi-arrow-up-left-circle-fill::before { content: "\f13b"; } -.bi-arrow-up-left-circle::before { content: "\f13c"; } -.bi-arrow-up-left-square-fill::before { content: "\f13d"; } -.bi-arrow-up-left-square::before { content: "\f13e"; } -.bi-arrow-up-left::before { content: "\f13f"; } -.bi-arrow-up-right-circle-fill::before { content: "\f140"; } -.bi-arrow-up-right-circle::before { content: "\f141"; } -.bi-arrow-up-right-square-fill::before { content: "\f142"; } -.bi-arrow-up-right-square::before { content: "\f143"; } -.bi-arrow-up-right::before { content: "\f144"; } -.bi-arrow-up-short::before { content: "\f145"; } -.bi-arrow-up-square-fill::before { content: "\f146"; } -.bi-arrow-up-square::before { content: "\f147"; } -.bi-arrow-up::before { content: "\f148"; } -.bi-arrows-angle-contract::before { content: "\f149"; } -.bi-arrows-angle-expand::before { content: "\f14a"; } -.bi-arrows-collapse::before { content: "\f14b"; } -.bi-arrows-expand::before { content: "\f14c"; } -.bi-arrows-fullscreen::before { content: "\f14d"; } -.bi-arrows-move::before { content: "\f14e"; } -.bi-aspect-ratio-fill::before { content: "\f14f"; } -.bi-aspect-ratio::before { content: "\f150"; } -.bi-asterisk::before { content: "\f151"; } -.bi-at::before { content: "\f152"; } -.bi-award-fill::before { content: "\f153"; } -.bi-award::before { content: "\f154"; } -.bi-back::before { content: "\f155"; } -.bi-backspace-fill::before { content: "\f156"; } -.bi-backspace-reverse-fill::before { content: "\f157"; } -.bi-backspace-reverse::before { content: "\f158"; } -.bi-backspace::before { content: "\f159"; } -.bi-badge-3d-fill::before { content: "\f15a"; } -.bi-badge-3d::before { content: "\f15b"; } -.bi-badge-4k-fill::before { content: "\f15c"; } -.bi-badge-4k::before { content: "\f15d"; } -.bi-badge-8k-fill::before { content: "\f15e"; } -.bi-badge-8k::before { content: "\f15f"; } -.bi-badge-ad-fill::before { content: "\f160"; } -.bi-badge-ad::before { content: "\f161"; } -.bi-badge-ar-fill::before { content: "\f162"; } -.bi-badge-ar::before { content: "\f163"; } -.bi-badge-cc-fill::before { content: "\f164"; } -.bi-badge-cc::before { content: "\f165"; } -.bi-badge-hd-fill::before { content: "\f166"; } -.bi-badge-hd::before { content: "\f167"; } -.bi-badge-tm-fill::before { content: "\f168"; } -.bi-badge-tm::before { content: "\f169"; } -.bi-badge-vo-fill::before { content: "\f16a"; } -.bi-badge-vo::before { content: "\f16b"; } -.bi-badge-vr-fill::before { content: "\f16c"; } -.bi-badge-vr::before { content: "\f16d"; } -.bi-badge-wc-fill::before { content: "\f16e"; } -.bi-badge-wc::before { content: "\f16f"; } -.bi-bag-check-fill::before { content: "\f170"; } -.bi-bag-check::before { content: "\f171"; } -.bi-bag-dash-fill::before { content: "\f172"; } -.bi-bag-dash::before { content: "\f173"; } -.bi-bag-fill::before { content: "\f174"; } -.bi-bag-plus-fill::before { content: "\f175"; } -.bi-bag-plus::before { content: "\f176"; } -.bi-bag-x-fill::before { content: "\f177"; } -.bi-bag-x::before { content: "\f178"; } -.bi-bag::before { content: "\f179"; } -.bi-bar-chart-fill::before { content: "\f17a"; } -.bi-bar-chart-line-fill::before { content: "\f17b"; } -.bi-bar-chart-line::before { content: "\f17c"; } -.bi-bar-chart-steps::before { content: "\f17d"; } -.bi-bar-chart::before { content: "\f17e"; } -.bi-basket-fill::before { content: "\f17f"; } -.bi-basket::before { content: "\f180"; } -.bi-basket2-fill::before { content: "\f181"; } -.bi-basket2::before { content: "\f182"; } -.bi-basket3-fill::before { content: "\f183"; } -.bi-basket3::before { content: "\f184"; } -.bi-battery-charging::before { content: "\f185"; } -.bi-battery-full::before { content: "\f186"; } -.bi-battery-half::before { content: "\f187"; } -.bi-battery::before { content: "\f188"; } -.bi-bell-fill::before { content: "\f189"; } -.bi-bell::before { content: "\f18a"; } -.bi-bezier::before { content: "\f18b"; } -.bi-bezier2::before { content: "\f18c"; } -.bi-bicycle::before { content: "\f18d"; } -.bi-binoculars-fill::before { content: "\f18e"; } -.bi-binoculars::before { content: "\f18f"; } -.bi-blockquote-left::before { content: "\f190"; } -.bi-blockquote-right::before { content: "\f191"; } -.bi-book-fill::before { content: "\f192"; } -.bi-book-half::before { content: "\f193"; } -.bi-book::before { content: "\f194"; } -.bi-bookmark-check-fill::before { content: "\f195"; } -.bi-bookmark-check::before { content: "\f196"; } -.bi-bookmark-dash-fill::before { content: "\f197"; } -.bi-bookmark-dash::before { content: "\f198"; } -.bi-bookmark-fill::before { content: "\f199"; } -.bi-bookmark-heart-fill::before { content: "\f19a"; } -.bi-bookmark-heart::before { content: "\f19b"; } -.bi-bookmark-plus-fill::before { content: "\f19c"; } -.bi-bookmark-plus::before { content: "\f19d"; } -.bi-bookmark-star-fill::before { content: "\f19e"; } -.bi-bookmark-star::before { content: "\f19f"; } -.bi-bookmark-x-fill::before { content: "\f1a0"; } -.bi-bookmark-x::before { content: "\f1a1"; } -.bi-bookmark::before { content: "\f1a2"; } -.bi-bookmarks-fill::before { content: "\f1a3"; } -.bi-bookmarks::before { content: "\f1a4"; } -.bi-bookshelf::before { content: "\f1a5"; } -.bi-bootstrap-fill::before { content: "\f1a6"; } -.bi-bootstrap-reboot::before { content: "\f1a7"; } -.bi-bootstrap::before { content: "\f1a8"; } -.bi-border-all::before { content: "\f1a9"; } -.bi-border-bottom::before { content: "\f1aa"; } -.bi-border-center::before { content: "\f1ab"; } -.bi-border-inner::before { content: "\f1ac"; } -.bi-border-left::before { content: "\f1ad"; } -.bi-border-middle::before { content: "\f1ae"; } -.bi-border-outer::before { content: "\f1af"; } -.bi-border-right::before { content: "\f1b0"; } -.bi-border-style::before { content: "\f1b1"; } -.bi-border-top::before { content: "\f1b2"; } -.bi-border-width::before { content: "\f1b3"; } -.bi-border::before { content: "\f1b4"; } -.bi-bounding-box-circles::before { content: "\f1b5"; } -.bi-bounding-box::before { content: "\f1b6"; } -.bi-box-arrow-down-left::before { content: "\f1b7"; } -.bi-box-arrow-down-right::before { content: "\f1b8"; } -.bi-box-arrow-down::before { content: "\f1b9"; } -.bi-box-arrow-in-down-left::before { content: "\f1ba"; } -.bi-box-arrow-in-down-right::before { content: "\f1bb"; } -.bi-box-arrow-in-down::before { content: "\f1bc"; } -.bi-box-arrow-in-left::before { content: "\f1bd"; } -.bi-box-arrow-in-right::before { content: "\f1be"; } -.bi-box-arrow-in-up-left::before { content: "\f1bf"; } -.bi-box-arrow-in-up-right::before { content: "\f1c0"; } -.bi-box-arrow-in-up::before { content: "\f1c1"; } -.bi-box-arrow-left::before { content: "\f1c2"; } -.bi-box-arrow-right::before { content: "\f1c3"; } -.bi-box-arrow-up-left::before { content: "\f1c4"; } -.bi-box-arrow-up-right::before { content: "\f1c5"; } -.bi-box-arrow-up::before { content: "\f1c6"; } -.bi-box-seam::before { content: "\f1c7"; } -.bi-box::before { content: "\f1c8"; } -.bi-braces::before { content: "\f1c9"; } -.bi-bricks::before { content: "\f1ca"; } -.bi-briefcase-fill::before { content: "\f1cb"; } -.bi-briefcase::before { content: "\f1cc"; } -.bi-brightness-alt-high-fill::before { content: "\f1cd"; } -.bi-brightness-alt-high::before { content: "\f1ce"; } -.bi-brightness-alt-low-fill::before { content: "\f1cf"; } -.bi-brightness-alt-low::before { content: "\f1d0"; } -.bi-brightness-high-fill::before { content: "\f1d1"; } -.bi-brightness-high::before { content: "\f1d2"; } -.bi-brightness-low-fill::before { content: "\f1d3"; } -.bi-brightness-low::before { content: "\f1d4"; } -.bi-broadcast-pin::before { content: "\f1d5"; } -.bi-broadcast::before { content: "\f1d6"; } -.bi-brush-fill::before { content: "\f1d7"; } -.bi-brush::before { content: "\f1d8"; } -.bi-bucket-fill::before { content: "\f1d9"; } -.bi-bucket::before { content: "\f1da"; } -.bi-bug-fill::before { content: "\f1db"; } -.bi-bug::before { content: "\f1dc"; } -.bi-building::before { content: "\f1dd"; } -.bi-bullseye::before { content: "\f1de"; } -.bi-calculator-fill::before { content: "\f1df"; } -.bi-calculator::before { content: "\f1e0"; } -.bi-calendar-check-fill::before { content: "\f1e1"; } -.bi-calendar-check::before { content: "\f1e2"; } -.bi-calendar-date-fill::before { content: "\f1e3"; } -.bi-calendar-date::before { content: "\f1e4"; } -.bi-calendar-day-fill::before { content: "\f1e5"; } -.bi-calendar-day::before { content: "\f1e6"; } -.bi-calendar-event-fill::before { content: "\f1e7"; } -.bi-calendar-event::before { content: "\f1e8"; } -.bi-calendar-fill::before { content: "\f1e9"; } -.bi-calendar-minus-fill::before { content: "\f1ea"; } -.bi-calendar-minus::before { content: "\f1eb"; } -.bi-calendar-month-fill::before { content: "\f1ec"; } -.bi-calendar-month::before { content: "\f1ed"; } -.bi-calendar-plus-fill::before { content: "\f1ee"; } -.bi-calendar-plus::before { content: "\f1ef"; } -.bi-calendar-range-fill::before { content: "\f1f0"; } -.bi-calendar-range::before { content: "\f1f1"; } -.bi-calendar-week-fill::before { content: "\f1f2"; } -.bi-calendar-week::before { content: "\f1f3"; } -.bi-calendar-x-fill::before { content: "\f1f4"; } -.bi-calendar-x::before { content: "\f1f5"; } -.bi-calendar::before { content: "\f1f6"; } -.bi-calendar2-check-fill::before { content: "\f1f7"; } -.bi-calendar2-check::before { content: "\f1f8"; } -.bi-calendar2-date-fill::before { content: "\f1f9"; } -.bi-calendar2-date::before { content: "\f1fa"; } -.bi-calendar2-day-fill::before { content: "\f1fb"; } -.bi-calendar2-day::before { content: "\f1fc"; } -.bi-calendar2-event-fill::before { content: "\f1fd"; } -.bi-calendar2-event::before { content: "\f1fe"; } -.bi-calendar2-fill::before { content: "\f1ff"; } -.bi-calendar2-minus-fill::before { content: "\f200"; } -.bi-calendar2-minus::before { content: "\f201"; } -.bi-calendar2-month-fill::before { content: "\f202"; } -.bi-calendar2-month::before { content: "\f203"; } -.bi-calendar2-plus-fill::before { content: "\f204"; } -.bi-calendar2-plus::before { content: "\f205"; } -.bi-calendar2-range-fill::before { content: "\f206"; } -.bi-calendar2-range::before { content: "\f207"; } -.bi-calendar2-week-fill::before { content: "\f208"; } -.bi-calendar2-week::before { content: "\f209"; } -.bi-calendar2-x-fill::before { content: "\f20a"; } -.bi-calendar2-x::before { content: "\f20b"; } -.bi-calendar2::before { content: "\f20c"; } -.bi-calendar3-event-fill::before { content: "\f20d"; } -.bi-calendar3-event::before { content: "\f20e"; } -.bi-calendar3-fill::before { content: "\f20f"; } -.bi-calendar3-range-fill::before { content: "\f210"; } -.bi-calendar3-range::before { content: "\f211"; } -.bi-calendar3-week-fill::before { content: "\f212"; } -.bi-calendar3-week::before { content: "\f213"; } -.bi-calendar3::before { content: "\f214"; } -.bi-calendar4-event::before { content: "\f215"; } -.bi-calendar4-range::before { content: "\f216"; } -.bi-calendar4-week::before { content: "\f217"; } -.bi-calendar4::before { content: "\f218"; } -.bi-camera-fill::before { content: "\f219"; } -.bi-camera-reels-fill::before { content: "\f21a"; } -.bi-camera-reels::before { content: "\f21b"; } -.bi-camera-video-fill::before { content: "\f21c"; } -.bi-camera-video-off-fill::before { content: "\f21d"; } -.bi-camera-video-off::before { content: "\f21e"; } -.bi-camera-video::before { content: "\f21f"; } -.bi-camera::before { content: "\f220"; } -.bi-camera2::before { content: "\f221"; } -.bi-capslock-fill::before { content: "\f222"; } -.bi-capslock::before { content: "\f223"; } -.bi-card-checklist::before { content: "\f224"; } -.bi-card-heading::before { content: "\f225"; } -.bi-card-image::before { content: "\f226"; } -.bi-card-list::before { content: "\f227"; } -.bi-card-text::before { content: "\f228"; } -.bi-caret-down-fill::before { content: "\f229"; } -.bi-caret-down-square-fill::before { content: "\f22a"; } -.bi-caret-down-square::before { content: "\f22b"; } -.bi-caret-down::before { content: "\f22c"; } -.bi-caret-left-fill::before { content: "\f22d"; } -.bi-caret-left-square-fill::before { content: "\f22e"; } -.bi-caret-left-square::before { content: "\f22f"; } -.bi-caret-left::before { content: "\f230"; } -.bi-caret-right-fill::before { content: "\f231"; } -.bi-caret-right-square-fill::before { content: "\f232"; } -.bi-caret-right-square::before { content: "\f233"; } -.bi-caret-right::before { content: "\f234"; } -.bi-caret-up-fill::before { content: "\f235"; } -.bi-caret-up-square-fill::before { content: "\f236"; } -.bi-caret-up-square::before { content: "\f237"; } -.bi-caret-up::before { content: "\f238"; } -.bi-cart-check-fill::before { content: "\f239"; } -.bi-cart-check::before { content: "\f23a"; } -.bi-cart-dash-fill::before { content: "\f23b"; } -.bi-cart-dash::before { content: "\f23c"; } -.bi-cart-fill::before { content: "\f23d"; } -.bi-cart-plus-fill::before { content: "\f23e"; } -.bi-cart-plus::before { content: "\f23f"; } -.bi-cart-x-fill::before { content: "\f240"; } -.bi-cart-x::before { content: "\f241"; } -.bi-cart::before { content: "\f242"; } -.bi-cart2::before { content: "\f243"; } -.bi-cart3::before { content: "\f244"; } -.bi-cart4::before { content: "\f245"; } -.bi-cash-stack::before { content: "\f246"; } -.bi-cash::before { content: "\f247"; } -.bi-cast::before { content: "\f248"; } -.bi-chat-dots-fill::before { content: "\f249"; } -.bi-chat-dots::before { content: "\f24a"; } -.bi-chat-fill::before { content: "\f24b"; } -.bi-chat-left-dots-fill::before { content: "\f24c"; } -.bi-chat-left-dots::before { content: "\f24d"; } -.bi-chat-left-fill::before { content: "\f24e"; } -.bi-chat-left-quote-fill::before { content: "\f24f"; } -.bi-chat-left-quote::before { content: "\f250"; } -.bi-chat-left-text-fill::before { content: "\f251"; } -.bi-chat-left-text::before { content: "\f252"; } -.bi-chat-left::before { content: "\f253"; } -.bi-chat-quote-fill::before { content: "\f254"; } -.bi-chat-quote::before { content: "\f255"; } -.bi-chat-right-dots-fill::before { content: "\f256"; } -.bi-chat-right-dots::before { content: "\f257"; } -.bi-chat-right-fill::before { content: "\f258"; } -.bi-chat-right-quote-fill::before { content: "\f259"; } -.bi-chat-right-quote::before { content: "\f25a"; } -.bi-chat-right-text-fill::before { content: "\f25b"; } -.bi-chat-right-text::before { content: "\f25c"; } -.bi-chat-right::before { content: "\f25d"; } -.bi-chat-square-dots-fill::before { content: "\f25e"; } -.bi-chat-square-dots::before { content: "\f25f"; } -.bi-chat-square-fill::before { content: "\f260"; } -.bi-chat-square-quote-fill::before { content: "\f261"; } -.bi-chat-square-quote::before { content: "\f262"; } -.bi-chat-square-text-fill::before { content: "\f263"; } -.bi-chat-square-text::before { content: "\f264"; } -.bi-chat-square::before { content: "\f265"; } -.bi-chat-text-fill::before { content: "\f266"; } -.bi-chat-text::before { content: "\f267"; } -.bi-chat::before { content: "\f268"; } -.bi-check-all::before { content: "\f269"; } -.bi-check-circle-fill::before { content: "\f26a"; } -.bi-check-circle::before { content: "\f26b"; } -.bi-check-square-fill::before { content: "\f26c"; } -.bi-check-square::before { content: "\f26d"; } -.bi-check::before { content: "\f26e"; } -.bi-check2-all::before { content: "\f26f"; } -.bi-check2-circle::before { content: "\f270"; } -.bi-check2-square::before { content: "\f271"; } -.bi-check2::before { content: "\f272"; } -.bi-chevron-bar-contract::before { content: "\f273"; } -.bi-chevron-bar-down::before { content: "\f274"; } -.bi-chevron-bar-expand::before { content: "\f275"; } -.bi-chevron-bar-left::before { content: "\f276"; } -.bi-chevron-bar-right::before { content: "\f277"; } -.bi-chevron-bar-up::before { content: "\f278"; } -.bi-chevron-compact-down::before { content: "\f279"; } -.bi-chevron-compact-left::before { content: "\f27a"; } -.bi-chevron-compact-right::before { content: "\f27b"; } -.bi-chevron-compact-up::before { content: "\f27c"; } -.bi-chevron-contract::before { content: "\f27d"; } -.bi-chevron-double-down::before { content: "\f27e"; } -.bi-chevron-double-left::before { content: "\f27f"; } -.bi-chevron-double-right::before { content: "\f280"; } -.bi-chevron-double-up::before { content: "\f281"; } -.bi-chevron-down::before { content: "\f282"; } -.bi-chevron-expand::before { content: "\f283"; } -.bi-chevron-left::before { content: "\f284"; } -.bi-chevron-right::before { content: "\f285"; } -.bi-chevron-up::before { content: "\f286"; } -.bi-circle-fill::before { content: "\f287"; } -.bi-circle-half::before { content: "\f288"; } -.bi-circle-square::before { content: "\f289"; } -.bi-circle::before { content: "\f28a"; } -.bi-clipboard-check::before { content: "\f28b"; } -.bi-clipboard-data::before { content: "\f28c"; } -.bi-clipboard-minus::before { content: "\f28d"; } -.bi-clipboard-plus::before { content: "\f28e"; } -.bi-clipboard-x::before { content: "\f28f"; } -.bi-clipboard::before { content: "\f290"; } -.bi-clock-fill::before { content: "\f291"; } -.bi-clock-history::before { content: "\f292"; } -.bi-clock::before { content: "\f293"; } -.bi-cloud-arrow-down-fill::before { content: "\f294"; } -.bi-cloud-arrow-down::before { content: "\f295"; } -.bi-cloud-arrow-up-fill::before { content: "\f296"; } -.bi-cloud-arrow-up::before { content: "\f297"; } -.bi-cloud-check-fill::before { content: "\f298"; } -.bi-cloud-check::before { content: "\f299"; } -.bi-cloud-download-fill::before { content: "\f29a"; } -.bi-cloud-download::before { content: "\f29b"; } -.bi-cloud-drizzle-fill::before { content: "\f29c"; } -.bi-cloud-drizzle::before { content: "\f29d"; } -.bi-cloud-fill::before { content: "\f29e"; } -.bi-cloud-fog-fill::before { content: "\f29f"; } -.bi-cloud-fog::before { content: "\f2a0"; } -.bi-cloud-fog2-fill::before { content: "\f2a1"; } -.bi-cloud-fog2::before { content: "\f2a2"; } -.bi-cloud-hail-fill::before { content: "\f2a3"; } -.bi-cloud-hail::before { content: "\f2a4"; } -.bi-cloud-haze-fill::before { content: "\f2a6"; } -.bi-cloud-haze::before { content: "\f2a7"; } -.bi-cloud-haze2-fill::before { content: "\f2a8"; } -.bi-cloud-lightning-fill::before { content: "\f2a9"; } -.bi-cloud-lightning-rain-fill::before { content: "\f2aa"; } -.bi-cloud-lightning-rain::before { content: "\f2ab"; } -.bi-cloud-lightning::before { content: "\f2ac"; } -.bi-cloud-minus-fill::before { content: "\f2ad"; } -.bi-cloud-minus::before { content: "\f2ae"; } -.bi-cloud-moon-fill::before { content: "\f2af"; } -.bi-cloud-moon::before { content: "\f2b0"; } -.bi-cloud-plus-fill::before { content: "\f2b1"; } -.bi-cloud-plus::before { content: "\f2b2"; } -.bi-cloud-rain-fill::before { content: "\f2b3"; } -.bi-cloud-rain-heavy-fill::before { content: "\f2b4"; } -.bi-cloud-rain-heavy::before { content: "\f2b5"; } -.bi-cloud-rain::before { content: "\f2b6"; } -.bi-cloud-slash-fill::before { content: "\f2b7"; } -.bi-cloud-slash::before { content: "\f2b8"; } -.bi-cloud-sleet-fill::before { content: "\f2b9"; } -.bi-cloud-sleet::before { content: "\f2ba"; } -.bi-cloud-snow-fill::before { content: "\f2bb"; } -.bi-cloud-snow::before { content: "\f2bc"; } -.bi-cloud-sun-fill::before { content: "\f2bd"; } -.bi-cloud-sun::before { content: "\f2be"; } -.bi-cloud-upload-fill::before { content: "\f2bf"; } -.bi-cloud-upload::before { content: "\f2c0"; } -.bi-cloud::before { content: "\f2c1"; } -.bi-clouds-fill::before { content: "\f2c2"; } -.bi-clouds::before { content: "\f2c3"; } -.bi-cloudy-fill::before { content: "\f2c4"; } -.bi-cloudy::before { content: "\f2c5"; } -.bi-code-slash::before { content: "\f2c6"; } -.bi-code-square::before { content: "\f2c7"; } -.bi-code::before { content: "\f2c8"; } -.bi-collection-fill::before { content: "\f2c9"; } -.bi-collection-play-fill::before { content: "\f2ca"; } -.bi-collection-play::before { content: "\f2cb"; } -.bi-collection::before { content: "\f2cc"; } -.bi-columns-gap::before { content: "\f2cd"; } -.bi-columns::before { content: "\f2ce"; } -.bi-command::before { content: "\f2cf"; } -.bi-compass-fill::before { content: "\f2d0"; } -.bi-compass::before { content: "\f2d1"; } -.bi-cone-striped::before { content: "\f2d2"; } -.bi-cone::before { content: "\f2d3"; } -.bi-controller::before { content: "\f2d4"; } -.bi-cpu-fill::before { content: "\f2d5"; } -.bi-cpu::before { content: "\f2d6"; } -.bi-credit-card-2-back-fill::before { content: "\f2d7"; } -.bi-credit-card-2-back::before { content: "\f2d8"; } -.bi-credit-card-2-front-fill::before { content: "\f2d9"; } -.bi-credit-card-2-front::before { content: "\f2da"; } -.bi-credit-card-fill::before { content: "\f2db"; } -.bi-credit-card::before { content: "\f2dc"; } -.bi-crop::before { content: "\f2dd"; } -.bi-cup-fill::before { content: "\f2de"; } -.bi-cup-straw::before { content: "\f2df"; } -.bi-cup::before { content: "\f2e0"; } -.bi-cursor-fill::before { content: "\f2e1"; } -.bi-cursor-text::before { content: "\f2e2"; } -.bi-cursor::before { content: "\f2e3"; } -.bi-dash-circle-dotted::before { content: "\f2e4"; } -.bi-dash-circle-fill::before { content: "\f2e5"; } -.bi-dash-circle::before { content: "\f2e6"; } -.bi-dash-square-dotted::before { content: "\f2e7"; } -.bi-dash-square-fill::before { content: "\f2e8"; } -.bi-dash-square::before { content: "\f2e9"; } -.bi-dash::before { content: "\f2ea"; } -.bi-diagram-2-fill::before { content: "\f2eb"; } -.bi-diagram-2::before { content: "\f2ec"; } -.bi-diagram-3-fill::before { content: "\f2ed"; } -.bi-diagram-3::before { content: "\f2ee"; } -.bi-diamond-fill::before { content: "\f2ef"; } -.bi-diamond-half::before { content: "\f2f0"; } -.bi-diamond::before { content: "\f2f1"; } -.bi-dice-1-fill::before { content: "\f2f2"; } -.bi-dice-1::before { content: "\f2f3"; } -.bi-dice-2-fill::before { content: "\f2f4"; } -.bi-dice-2::before { content: "\f2f5"; } -.bi-dice-3-fill::before { content: "\f2f6"; } -.bi-dice-3::before { content: "\f2f7"; } -.bi-dice-4-fill::before { content: "\f2f8"; } -.bi-dice-4::before { content: "\f2f9"; } -.bi-dice-5-fill::before { content: "\f2fa"; } -.bi-dice-5::before { content: "\f2fb"; } -.bi-dice-6-fill::before { content: "\f2fc"; } -.bi-dice-6::before { content: "\f2fd"; } -.bi-disc-fill::before { content: "\f2fe"; } -.bi-disc::before { content: "\f2ff"; } -.bi-discord::before { content: "\f300"; } -.bi-display-fill::before { content: "\f301"; } -.bi-display::before { content: "\f302"; } -.bi-distribute-horizontal::before { content: "\f303"; } -.bi-distribute-vertical::before { content: "\f304"; } -.bi-door-closed-fill::before { content: "\f305"; } -.bi-door-closed::before { content: "\f306"; } -.bi-door-open-fill::before { content: "\f307"; } -.bi-door-open::before { content: "\f308"; } -.bi-dot::before { content: "\f309"; } -.bi-download::before { content: "\f30a"; } -.bi-droplet-fill::before { content: "\f30b"; } -.bi-droplet-half::before { content: "\f30c"; } -.bi-droplet::before { content: "\f30d"; } -.bi-earbuds::before { content: "\f30e"; } -.bi-easel-fill::before { content: "\f30f"; } -.bi-easel::before { content: "\f310"; } -.bi-egg-fill::before { content: "\f311"; } -.bi-egg-fried::before { content: "\f312"; } -.bi-egg::before { content: "\f313"; } -.bi-eject-fill::before { content: "\f314"; } -.bi-eject::before { content: "\f315"; } -.bi-emoji-angry-fill::before { content: "\f316"; } -.bi-emoji-angry::before { content: "\f317"; } -.bi-emoji-dizzy-fill::before { content: "\f318"; } -.bi-emoji-dizzy::before { content: "\f319"; } -.bi-emoji-expressionless-fill::before { content: "\f31a"; } -.bi-emoji-expressionless::before { content: "\f31b"; } -.bi-emoji-frown-fill::before { content: "\f31c"; } -.bi-emoji-frown::before { content: "\f31d"; } -.bi-emoji-heart-eyes-fill::before { content: "\f31e"; } -.bi-emoji-heart-eyes::before { content: "\f31f"; } -.bi-emoji-laughing-fill::before { content: "\f320"; } -.bi-emoji-laughing::before { content: "\f321"; } -.bi-emoji-neutral-fill::before { content: "\f322"; } -.bi-emoji-neutral::before { content: "\f323"; } -.bi-emoji-smile-fill::before { content: "\f324"; } -.bi-emoji-smile-upside-down-fill::before { content: "\f325"; } -.bi-emoji-smile-upside-down::before { content: "\f326"; } -.bi-emoji-smile::before { content: "\f327"; } -.bi-emoji-sunglasses-fill::before { content: "\f328"; } -.bi-emoji-sunglasses::before { content: "\f329"; } -.bi-emoji-wink-fill::before { content: "\f32a"; } -.bi-emoji-wink::before { content: "\f32b"; } -.bi-envelope-fill::before { content: "\f32c"; } -.bi-envelope-open-fill::before { content: "\f32d"; } -.bi-envelope-open::before { content: "\f32e"; } -.bi-envelope::before { content: "\f32f"; } -.bi-eraser-fill::before { content: "\f330"; } -.bi-eraser::before { content: "\f331"; } -.bi-exclamation-circle-fill::before { content: "\f332"; } -.bi-exclamation-circle::before { content: "\f333"; } -.bi-exclamation-diamond-fill::before { content: "\f334"; } -.bi-exclamation-diamond::before { content: "\f335"; } -.bi-exclamation-octagon-fill::before { content: "\f336"; } -.bi-exclamation-octagon::before { content: "\f337"; } -.bi-exclamation-square-fill::before { content: "\f338"; } -.bi-exclamation-square::before { content: "\f339"; } -.bi-exclamation-triangle-fill::before { content: "\f33a"; } -.bi-exclamation-triangle::before { content: "\f33b"; } -.bi-exclamation::before { content: "\f33c"; } -.bi-exclude::before { content: "\f33d"; } -.bi-eye-fill::before { content: "\f33e"; } -.bi-eye-slash-fill::before { content: "\f33f"; } -.bi-eye-slash::before { content: "\f340"; } -.bi-eye::before { content: "\f341"; } -.bi-eyedropper::before { content: "\f342"; } -.bi-eyeglasses::before { content: "\f343"; } -.bi-facebook::before { content: "\f344"; } -.bi-file-arrow-down-fill::before { content: "\f345"; } -.bi-file-arrow-down::before { content: "\f346"; } -.bi-file-arrow-up-fill::before { content: "\f347"; } -.bi-file-arrow-up::before { content: "\f348"; } -.bi-file-bar-graph-fill::before { content: "\f349"; } -.bi-file-bar-graph::before { content: "\f34a"; } -.bi-file-binary-fill::before { content: "\f34b"; } -.bi-file-binary::before { content: "\f34c"; } -.bi-file-break-fill::before { content: "\f34d"; } -.bi-file-break::before { content: "\f34e"; } -.bi-file-check-fill::before { content: "\f34f"; } -.bi-file-check::before { content: "\f350"; } -.bi-file-code-fill::before { content: "\f351"; } -.bi-file-code::before { content: "\f352"; } -.bi-file-diff-fill::before { content: "\f353"; } -.bi-file-diff::before { content: "\f354"; } -.bi-file-earmark-arrow-down-fill::before { content: "\f355"; } -.bi-file-earmark-arrow-down::before { content: "\f356"; } -.bi-file-earmark-arrow-up-fill::before { content: "\f357"; } -.bi-file-earmark-arrow-up::before { content: "\f358"; } -.bi-file-earmark-bar-graph-fill::before { content: "\f359"; } -.bi-file-earmark-bar-graph::before { content: "\f35a"; } -.bi-file-earmark-binary-fill::before { content: "\f35b"; } -.bi-file-earmark-binary::before { content: "\f35c"; } -.bi-file-earmark-break-fill::before { content: "\f35d"; } -.bi-file-earmark-break::before { content: "\f35e"; } -.bi-file-earmark-check-fill::before { content: "\f35f"; } -.bi-file-earmark-check::before { content: "\f360"; } -.bi-file-earmark-code-fill::before { content: "\f361"; } -.bi-file-earmark-code::before { content: "\f362"; } -.bi-file-earmark-diff-fill::before { content: "\f363"; } -.bi-file-earmark-diff::before { content: "\f364"; } -.bi-file-earmark-easel-fill::before { content: "\f365"; } -.bi-file-earmark-easel::before { content: "\f366"; } -.bi-file-earmark-excel-fill::before { content: "\f367"; } -.bi-file-earmark-excel::before { content: "\f368"; } -.bi-file-earmark-fill::before { content: "\f369"; } -.bi-file-earmark-font-fill::before { content: "\f36a"; } -.bi-file-earmark-font::before { content: "\f36b"; } -.bi-file-earmark-image-fill::before { content: "\f36c"; } -.bi-file-earmark-image::before { content: "\f36d"; } -.bi-file-earmark-lock-fill::before { content: "\f36e"; } -.bi-file-earmark-lock::before { content: "\f36f"; } -.bi-file-earmark-lock2-fill::before { content: "\f370"; } -.bi-file-earmark-lock2::before { content: "\f371"; } -.bi-file-earmark-medical-fill::before { content: "\f372"; } -.bi-file-earmark-medical::before { content: "\f373"; } -.bi-file-earmark-minus-fill::before { content: "\f374"; } -.bi-file-earmark-minus::before { content: "\f375"; } -.bi-file-earmark-music-fill::before { content: "\f376"; } -.bi-file-earmark-music::before { content: "\f377"; } -.bi-file-earmark-person-fill::before { content: "\f378"; } -.bi-file-earmark-person::before { content: "\f379"; } -.bi-file-earmark-play-fill::before { content: "\f37a"; } -.bi-file-earmark-play::before { content: "\f37b"; } -.bi-file-earmark-plus-fill::before { content: "\f37c"; } -.bi-file-earmark-plus::before { content: "\f37d"; } -.bi-file-earmark-post-fill::before { content: "\f37e"; } -.bi-file-earmark-post::before { content: "\f37f"; } -.bi-file-earmark-ppt-fill::before { content: "\f380"; } -.bi-file-earmark-ppt::before { content: "\f381"; } -.bi-file-earmark-richtext-fill::before { content: "\f382"; } -.bi-file-earmark-richtext::before { content: "\f383"; } -.bi-file-earmark-ruled-fill::before { content: "\f384"; } -.bi-file-earmark-ruled::before { content: "\f385"; } -.bi-file-earmark-slides-fill::before { content: "\f386"; } -.bi-file-earmark-slides::before { content: "\f387"; } -.bi-file-earmark-spreadsheet-fill::before { content: "\f388"; } -.bi-file-earmark-spreadsheet::before { content: "\f389"; } -.bi-file-earmark-text-fill::before { content: "\f38a"; } -.bi-file-earmark-text::before { content: "\f38b"; } -.bi-file-earmark-word-fill::before { content: "\f38c"; } -.bi-file-earmark-word::before { content: "\f38d"; } -.bi-file-earmark-x-fill::before { content: "\f38e"; } -.bi-file-earmark-x::before { content: "\f38f"; } -.bi-file-earmark-zip-fill::before { content: "\f390"; } -.bi-file-earmark-zip::before { content: "\f391"; } -.bi-file-earmark::before { content: "\f392"; } -.bi-file-easel-fill::before { content: "\f393"; } -.bi-file-easel::before { content: "\f394"; } -.bi-file-excel-fill::before { content: "\f395"; } -.bi-file-excel::before { content: "\f396"; } -.bi-file-fill::before { content: "\f397"; } -.bi-file-font-fill::before { content: "\f398"; } -.bi-file-font::before { content: "\f399"; } -.bi-file-image-fill::before { content: "\f39a"; } -.bi-file-image::before { content: "\f39b"; } -.bi-file-lock-fill::before { content: "\f39c"; } -.bi-file-lock::before { content: "\f39d"; } -.bi-file-lock2-fill::before { content: "\f39e"; } -.bi-file-lock2::before { content: "\f39f"; } -.bi-file-medical-fill::before { content: "\f3a0"; } -.bi-file-medical::before { content: "\f3a1"; } -.bi-file-minus-fill::before { content: "\f3a2"; } -.bi-file-minus::before { content: "\f3a3"; } -.bi-file-music-fill::before { content: "\f3a4"; } -.bi-file-music::before { content: "\f3a5"; } -.bi-file-person-fill::before { content: "\f3a6"; } -.bi-file-person::before { content: "\f3a7"; } -.bi-file-play-fill::before { content: "\f3a8"; } -.bi-file-play::before { content: "\f3a9"; } -.bi-file-plus-fill::before { content: "\f3aa"; } -.bi-file-plus::before { content: "\f3ab"; } -.bi-file-post-fill::before { content: "\f3ac"; } -.bi-file-post::before { content: "\f3ad"; } -.bi-file-ppt-fill::before { content: "\f3ae"; } -.bi-file-ppt::before { content: "\f3af"; } -.bi-file-richtext-fill::before { content: "\f3b0"; } -.bi-file-richtext::before { content: "\f3b1"; } -.bi-file-ruled-fill::before { content: "\f3b2"; } -.bi-file-ruled::before { content: "\f3b3"; } -.bi-file-slides-fill::before { content: "\f3b4"; } -.bi-file-slides::before { content: "\f3b5"; } -.bi-file-spreadsheet-fill::before { content: "\f3b6"; } -.bi-file-spreadsheet::before { content: "\f3b7"; } -.bi-file-text-fill::before { content: "\f3b8"; } -.bi-file-text::before { content: "\f3b9"; } -.bi-file-word-fill::before { content: "\f3ba"; } -.bi-file-word::before { content: "\f3bb"; } -.bi-file-x-fill::before { content: "\f3bc"; } -.bi-file-x::before { content: "\f3bd"; } -.bi-file-zip-fill::before { content: "\f3be"; } -.bi-file-zip::before { content: "\f3bf"; } -.bi-file::before { content: "\f3c0"; } -.bi-files-alt::before { content: "\f3c1"; } -.bi-files::before { content: "\f3c2"; } -.bi-film::before { content: "\f3c3"; } -.bi-filter-circle-fill::before { content: "\f3c4"; } -.bi-filter-circle::before { content: "\f3c5"; } -.bi-filter-left::before { content: "\f3c6"; } -.bi-filter-right::before { content: "\f3c7"; } -.bi-filter-square-fill::before { content: "\f3c8"; } -.bi-filter-square::before { content: "\f3c9"; } -.bi-filter::before { content: "\f3ca"; } -.bi-flag-fill::before { content: "\f3cb"; } -.bi-flag::before { content: "\f3cc"; } -.bi-flower1::before { content: "\f3cd"; } -.bi-flower2::before { content: "\f3ce"; } -.bi-flower3::before { content: "\f3cf"; } -.bi-folder-check::before { content: "\f3d0"; } -.bi-folder-fill::before { content: "\f3d1"; } -.bi-folder-minus::before { content: "\f3d2"; } -.bi-folder-plus::before { content: "\f3d3"; } -.bi-folder-symlink-fill::before { content: "\f3d4"; } -.bi-folder-symlink::before { content: "\f3d5"; } -.bi-folder-x::before { content: "\f3d6"; } -.bi-folder::before { content: "\f3d7"; } -.bi-folder2-open::before { content: "\f3d8"; } -.bi-folder2::before { content: "\f3d9"; } -.bi-fonts::before { content: "\f3da"; } -.bi-forward-fill::before { content: "\f3db"; } -.bi-forward::before { content: "\f3dc"; } -.bi-front::before { content: "\f3dd"; } -.bi-fullscreen-exit::before { content: "\f3de"; } -.bi-fullscreen::before { content: "\f3df"; } -.bi-funnel-fill::before { content: "\f3e0"; } -.bi-funnel::before { content: "\f3e1"; } -.bi-gear-fill::before { content: "\f3e2"; } -.bi-gear-wide-connected::before { content: "\f3e3"; } -.bi-gear-wide::before { content: "\f3e4"; } -.bi-gear::before { content: "\f3e5"; } -.bi-gem::before { content: "\f3e6"; } -.bi-geo-alt-fill::before { content: "\f3e7"; } -.bi-geo-alt::before { content: "\f3e8"; } -.bi-geo-fill::before { content: "\f3e9"; } -.bi-geo::before { content: "\f3ea"; } -.bi-gift-fill::before { content: "\f3eb"; } -.bi-gift::before { content: "\f3ec"; } -.bi-github::before { content: "\f3ed"; } -.bi-globe::before { content: "\f3ee"; } -.bi-globe2::before { content: "\f3ef"; } -.bi-google::before { content: "\f3f0"; } -.bi-graph-down::before { content: "\f3f1"; } -.bi-graph-up::before { content: "\f3f2"; } -.bi-grid-1x2-fill::before { content: "\f3f3"; } -.bi-grid-1x2::before { content: "\f3f4"; } -.bi-grid-3x2-gap-fill::before { content: "\f3f5"; } -.bi-grid-3x2-gap::before { content: "\f3f6"; } -.bi-grid-3x2::before { content: "\f3f7"; } -.bi-grid-3x3-gap-fill::before { content: "\f3f8"; } -.bi-grid-3x3-gap::before { content: "\f3f9"; } -.bi-grid-3x3::before { content: "\f3fa"; } -.bi-grid-fill::before { content: "\f3fb"; } -.bi-grid::before { content: "\f3fc"; } -.bi-grip-horizontal::before { content: "\f3fd"; } -.bi-grip-vertical::before { content: "\f3fe"; } -.bi-hammer::before { content: "\f3ff"; } -.bi-hand-index-fill::before { content: "\f400"; } -.bi-hand-index-thumb-fill::before { content: "\f401"; } -.bi-hand-index-thumb::before { content: "\f402"; } -.bi-hand-index::before { content: "\f403"; } -.bi-hand-thumbs-down-fill::before { content: "\f404"; } -.bi-hand-thumbs-down::before { content: "\f405"; } -.bi-hand-thumbs-up-fill::before { content: "\f406"; } -.bi-hand-thumbs-up::before { content: "\f407"; } -.bi-handbag-fill::before { content: "\f408"; } -.bi-handbag::before { content: "\f409"; } -.bi-hash::before { content: "\f40a"; } -.bi-hdd-fill::before { content: "\f40b"; } -.bi-hdd-network-fill::before { content: "\f40c"; } -.bi-hdd-network::before { content: "\f40d"; } -.bi-hdd-rack-fill::before { content: "\f40e"; } -.bi-hdd-rack::before { content: "\f40f"; } -.bi-hdd-stack-fill::before { content: "\f410"; } -.bi-hdd-stack::before { content: "\f411"; } -.bi-hdd::before { content: "\f412"; } -.bi-headphones::before { content: "\f413"; } -.bi-headset::before { content: "\f414"; } -.bi-heart-fill::before { content: "\f415"; } -.bi-heart-half::before { content: "\f416"; } -.bi-heart::before { content: "\f417"; } -.bi-heptagon-fill::before { content: "\f418"; } -.bi-heptagon-half::before { content: "\f419"; } -.bi-heptagon::before { content: "\f41a"; } -.bi-hexagon-fill::before { content: "\f41b"; } -.bi-hexagon-half::before { content: "\f41c"; } -.bi-hexagon::before { content: "\f41d"; } -.bi-hourglass-bottom::before { content: "\f41e"; } -.bi-hourglass-split::before { content: "\f41f"; } -.bi-hourglass-top::before { content: "\f420"; } -.bi-hourglass::before { content: "\f421"; } -.bi-house-door-fill::before { content: "\f422"; } -.bi-house-door::before { content: "\f423"; } -.bi-house-fill::before { content: "\f424"; } -.bi-house::before { content: "\f425"; } -.bi-hr::before { content: "\f426"; } -.bi-hurricane::before { content: "\f427"; } -.bi-image-alt::before { content: "\f428"; } -.bi-image-fill::before { content: "\f429"; } -.bi-image::before { content: "\f42a"; } -.bi-images::before { content: "\f42b"; } -.bi-inbox-fill::before { content: "\f42c"; } -.bi-inbox::before { content: "\f42d"; } -.bi-inboxes-fill::before { content: "\f42e"; } -.bi-inboxes::before { content: "\f42f"; } -.bi-info-circle-fill::before { content: "\f430"; } -.bi-info-circle::before { content: "\f431"; } -.bi-info-square-fill::before { content: "\f432"; } -.bi-info-square::before { content: "\f433"; } -.bi-info::before { content: "\f434"; } -.bi-input-cursor-text::before { content: "\f435"; } -.bi-input-cursor::before { content: "\f436"; } -.bi-instagram::before { content: "\f437"; } -.bi-intersect::before { content: "\f438"; } -.bi-journal-album::before { content: "\f439"; } -.bi-journal-arrow-down::before { content: "\f43a"; } -.bi-journal-arrow-up::before { content: "\f43b"; } -.bi-journal-bookmark-fill::before { content: "\f43c"; } -.bi-journal-bookmark::before { content: "\f43d"; } -.bi-journal-check::before { content: "\f43e"; } -.bi-journal-code::before { content: "\f43f"; } -.bi-journal-medical::before { content: "\f440"; } -.bi-journal-minus::before { content: "\f441"; } -.bi-journal-plus::before { content: "\f442"; } -.bi-journal-richtext::before { content: "\f443"; } -.bi-journal-text::before { content: "\f444"; } -.bi-journal-x::before { content: "\f445"; } -.bi-journal::before { content: "\f446"; } -.bi-journals::before { content: "\f447"; } -.bi-joystick::before { content: "\f448"; } -.bi-justify-left::before { content: "\f449"; } -.bi-justify-right::before { content: "\f44a"; } -.bi-justify::before { content: "\f44b"; } -.bi-kanban-fill::before { content: "\f44c"; } -.bi-kanban::before { content: "\f44d"; } -.bi-key-fill::before { content: "\f44e"; } -.bi-key::before { content: "\f44f"; } -.bi-keyboard-fill::before { content: "\f450"; } -.bi-keyboard::before { content: "\f451"; } -.bi-ladder::before { content: "\f452"; } -.bi-lamp-fill::before { content: "\f453"; } -.bi-lamp::before { content: "\f454"; } -.bi-laptop-fill::before { content: "\f455"; } -.bi-laptop::before { content: "\f456"; } -.bi-layer-backward::before { content: "\f457"; } -.bi-layer-forward::before { content: "\f458"; } -.bi-layers-fill::before { content: "\f459"; } -.bi-layers-half::before { content: "\f45a"; } -.bi-layers::before { content: "\f45b"; } -.bi-layout-sidebar-inset-reverse::before { content: "\f45c"; } -.bi-layout-sidebar-inset::before { content: "\f45d"; } -.bi-layout-sidebar-reverse::before { content: "\f45e"; } -.bi-layout-sidebar::before { content: "\f45f"; } -.bi-layout-split::before { content: "\f460"; } -.bi-layout-text-sidebar-reverse::before { content: "\f461"; } -.bi-layout-text-sidebar::before { content: "\f462"; } -.bi-layout-text-window-reverse::before { content: "\f463"; } -.bi-layout-text-window::before { content: "\f464"; } -.bi-layout-three-columns::before { content: "\f465"; } -.bi-layout-wtf::before { content: "\f466"; } -.bi-life-preserver::before { content: "\f467"; } -.bi-lightbulb-fill::before { content: "\f468"; } -.bi-lightbulb-off-fill::before { content: "\f469"; } -.bi-lightbulb-off::before { content: "\f46a"; } -.bi-lightbulb::before { content: "\f46b"; } -.bi-lightning-charge-fill::before { content: "\f46c"; } -.bi-lightning-charge::before { content: "\f46d"; } -.bi-lightning-fill::before { content: "\f46e"; } -.bi-lightning::before { content: "\f46f"; } -.bi-link-45deg::before { content: "\f470"; } -.bi-link::before { content: "\f471"; } -.bi-linkedin::before { content: "\f472"; } -.bi-list-check::before { content: "\f473"; } -.bi-list-nested::before { content: "\f474"; } -.bi-list-ol::before { content: "\f475"; } -.bi-list-stars::before { content: "\f476"; } -.bi-list-task::before { content: "\f477"; } -.bi-list-ul::before { content: "\f478"; } -.bi-list::before { content: "\f479"; } -.bi-lock-fill::before { content: "\f47a"; } -.bi-lock::before { content: "\f47b"; } -.bi-mailbox::before { content: "\f47c"; } -.bi-mailbox2::before { content: "\f47d"; } -.bi-map-fill::before { content: "\f47e"; } -.bi-map::before { content: "\f47f"; } -.bi-markdown-fill::before { content: "\f480"; } -.bi-markdown::before { content: "\f481"; } -.bi-mask::before { content: "\f482"; } -.bi-megaphone-fill::before { content: "\f483"; } -.bi-megaphone::before { content: "\f484"; } -.bi-menu-app-fill::before { content: "\f485"; } -.bi-menu-app::before { content: "\f486"; } -.bi-menu-button-fill::before { content: "\f487"; } -.bi-menu-button-wide-fill::before { content: "\f488"; } -.bi-menu-button-wide::before { content: "\f489"; } -.bi-menu-button::before { content: "\f48a"; } -.bi-menu-down::before { content: "\f48b"; } -.bi-menu-up::before { content: "\f48c"; } -.bi-mic-fill::before { content: "\f48d"; } -.bi-mic-mute-fill::before { content: "\f48e"; } -.bi-mic-mute::before { content: "\f48f"; } -.bi-mic::before { content: "\f490"; } -.bi-minecart-loaded::before { content: "\f491"; } -.bi-minecart::before { content: "\f492"; } -.bi-moisture::before { content: "\f493"; } -.bi-moon-fill::before { content: "\f494"; } -.bi-moon-stars-fill::before { content: "\f495"; } -.bi-moon-stars::before { content: "\f496"; } -.bi-moon::before { content: "\f497"; } -.bi-mouse-fill::before { content: "\f498"; } -.bi-mouse::before { content: "\f499"; } -.bi-mouse2-fill::before { content: "\f49a"; } -.bi-mouse2::before { content: "\f49b"; } -.bi-mouse3-fill::before { content: "\f49c"; } -.bi-mouse3::before { content: "\f49d"; } -.bi-music-note-beamed::before { content: "\f49e"; } -.bi-music-note-list::before { content: "\f49f"; } -.bi-music-note::before { content: "\f4a0"; } -.bi-music-player-fill::before { content: "\f4a1"; } -.bi-music-player::before { content: "\f4a2"; } -.bi-newspaper::before { content: "\f4a3"; } -.bi-node-minus-fill::before { content: "\f4a4"; } -.bi-node-minus::before { content: "\f4a5"; } -.bi-node-plus-fill::before { content: "\f4a6"; } -.bi-node-plus::before { content: "\f4a7"; } -.bi-nut-fill::before { content: "\f4a8"; } -.bi-nut::before { content: "\f4a9"; } -.bi-octagon-fill::before { content: "\f4aa"; } -.bi-octagon-half::before { content: "\f4ab"; } -.bi-octagon::before { content: "\f4ac"; } -.bi-option::before { content: "\f4ad"; } -.bi-outlet::before { content: "\f4ae"; } -.bi-paint-bucket::before { content: "\f4af"; } -.bi-palette-fill::before { content: "\f4b0"; } -.bi-palette::before { content: "\f4b1"; } -.bi-palette2::before { content: "\f4b2"; } -.bi-paperclip::before { content: "\f4b3"; } -.bi-paragraph::before { content: "\f4b4"; } -.bi-patch-check-fill::before { content: "\f4b5"; } -.bi-patch-check::before { content: "\f4b6"; } -.bi-patch-exclamation-fill::before { content: "\f4b7"; } -.bi-patch-exclamation::before { content: "\f4b8"; } -.bi-patch-minus-fill::before { content: "\f4b9"; } -.bi-patch-minus::before { content: "\f4ba"; } -.bi-patch-plus-fill::before { content: "\f4bb"; } -.bi-patch-plus::before { content: "\f4bc"; } -.bi-patch-question-fill::before { content: "\f4bd"; } -.bi-patch-question::before { content: "\f4be"; } -.bi-pause-btn-fill::before { content: "\f4bf"; } -.bi-pause-btn::before { content: "\f4c0"; } -.bi-pause-circle-fill::before { content: "\f4c1"; } -.bi-pause-circle::before { content: "\f4c2"; } -.bi-pause-fill::before { content: "\f4c3"; } -.bi-pause::before { content: "\f4c4"; } -.bi-peace-fill::before { content: "\f4c5"; } -.bi-peace::before { content: "\f4c6"; } -.bi-pen-fill::before { content: "\f4c7"; } -.bi-pen::before { content: "\f4c8"; } -.bi-pencil-fill::before { content: "\f4c9"; } -.bi-pencil-square::before { content: "\f4ca"; } -.bi-pencil::before { content: "\f4cb"; } -.bi-pentagon-fill::before { content: "\f4cc"; } -.bi-pentagon-half::before { content: "\f4cd"; } -.bi-pentagon::before { content: "\f4ce"; } -.bi-people-fill::before { content: "\f4cf"; } -.bi-people::before { content: "\f4d0"; } -.bi-percent::before { content: "\f4d1"; } -.bi-person-badge-fill::before { content: "\f4d2"; } -.bi-person-badge::before { content: "\f4d3"; } -.bi-person-bounding-box::before { content: "\f4d4"; } -.bi-person-check-fill::before { content: "\f4d5"; } -.bi-person-check::before { content: "\f4d6"; } -.bi-person-circle::before { content: "\f4d7"; } -.bi-person-dash-fill::before { content: "\f4d8"; } -.bi-person-dash::before { content: "\f4d9"; } -.bi-person-fill::before { content: "\f4da"; } -.bi-person-lines-fill::before { content: "\f4db"; } -.bi-person-plus-fill::before { content: "\f4dc"; } -.bi-person-plus::before { content: "\f4dd"; } -.bi-person-square::before { content: "\f4de"; } -.bi-person-x-fill::before { content: "\f4df"; } -.bi-person-x::before { content: "\f4e0"; } -.bi-person::before { content: "\f4e1"; } -.bi-phone-fill::before { content: "\f4e2"; } -.bi-phone-landscape-fill::before { content: "\f4e3"; } -.bi-phone-landscape::before { content: "\f4e4"; } -.bi-phone-vibrate-fill::before { content: "\f4e5"; } -.bi-phone-vibrate::before { content: "\f4e6"; } -.bi-phone::before { content: "\f4e7"; } -.bi-pie-chart-fill::before { content: "\f4e8"; } -.bi-pie-chart::before { content: "\f4e9"; } -.bi-pin-angle-fill::before { content: "\f4ea"; } -.bi-pin-angle::before { content: "\f4eb"; } -.bi-pin-fill::before { content: "\f4ec"; } -.bi-pin::before { content: "\f4ed"; } -.bi-pip-fill::before { content: "\f4ee"; } -.bi-pip::before { content: "\f4ef"; } -.bi-play-btn-fill::before { content: "\f4f0"; } -.bi-play-btn::before { content: "\f4f1"; } -.bi-play-circle-fill::before { content: "\f4f2"; } -.bi-play-circle::before { content: "\f4f3"; } -.bi-play-fill::before { content: "\f4f4"; } -.bi-play::before { content: "\f4f5"; } -.bi-plug-fill::before { content: "\f4f6"; } -.bi-plug::before { content: "\f4f7"; } -.bi-plus-circle-dotted::before { content: "\f4f8"; } -.bi-plus-circle-fill::before { content: "\f4f9"; } -.bi-plus-circle::before { content: "\f4fa"; } -.bi-plus-square-dotted::before { content: "\f4fb"; } -.bi-plus-square-fill::before { content: "\f4fc"; } -.bi-plus-square::before { content: "\f4fd"; } -.bi-plus::before { content: "\f4fe"; } -.bi-power::before { content: "\f4ff"; } -.bi-printer-fill::before { content: "\f500"; } -.bi-printer::before { content: "\f501"; } -.bi-puzzle-fill::before { content: "\f502"; } -.bi-puzzle::before { content: "\f503"; } -.bi-question-circle-fill::before { content: "\f504"; } -.bi-question-circle::before { content: "\f505"; } -.bi-question-diamond-fill::before { content: "\f506"; } -.bi-question-diamond::before { content: "\f507"; } -.bi-question-octagon-fill::before { content: "\f508"; } -.bi-question-octagon::before { content: "\f509"; } -.bi-question-square-fill::before { content: "\f50a"; } -.bi-question-square::before { content: "\f50b"; } -.bi-question::before { content: "\f50c"; } -.bi-rainbow::before { content: "\f50d"; } -.bi-receipt-cutoff::before { content: "\f50e"; } -.bi-receipt::before { content: "\f50f"; } -.bi-reception-0::before { content: "\f510"; } -.bi-reception-1::before { content: "\f511"; } -.bi-reception-2::before { content: "\f512"; } -.bi-reception-3::before { content: "\f513"; } -.bi-reception-4::before { content: "\f514"; } -.bi-record-btn-fill::before { content: "\f515"; } -.bi-record-btn::before { content: "\f516"; } -.bi-record-circle-fill::before { content: "\f517"; } -.bi-record-circle::before { content: "\f518"; } -.bi-record-fill::before { content: "\f519"; } -.bi-record::before { content: "\f51a"; } -.bi-record2-fill::before { content: "\f51b"; } -.bi-record2::before { content: "\f51c"; } -.bi-reply-all-fill::before { content: "\f51d"; } -.bi-reply-all::before { content: "\f51e"; } -.bi-reply-fill::before { content: "\f51f"; } -.bi-reply::before { content: "\f520"; } -.bi-rss-fill::before { content: "\f521"; } -.bi-rss::before { content: "\f522"; } -.bi-rulers::before { content: "\f523"; } -.bi-save-fill::before { content: "\f524"; } -.bi-save::before { content: "\f525"; } -.bi-save2-fill::before { content: "\f526"; } -.bi-save2::before { content: "\f527"; } -.bi-scissors::before { content: "\f528"; } -.bi-screwdriver::before { content: "\f529"; } -.bi-search::before { content: "\f52a"; } -.bi-segmented-nav::before { content: "\f52b"; } -.bi-server::before { content: "\f52c"; } -.bi-share-fill::before { content: "\f52d"; } -.bi-share::before { content: "\f52e"; } -.bi-shield-check::before { content: "\f52f"; } -.bi-shield-exclamation::before { content: "\f530"; } -.bi-shield-fill-check::before { content: "\f531"; } -.bi-shield-fill-exclamation::before { content: "\f532"; } -.bi-shield-fill-minus::before { content: "\f533"; } -.bi-shield-fill-plus::before { content: "\f534"; } -.bi-shield-fill-x::before { content: "\f535"; } -.bi-shield-fill::before { content: "\f536"; } -.bi-shield-lock-fill::before { content: "\f537"; } -.bi-shield-lock::before { content: "\f538"; } -.bi-shield-minus::before { content: "\f539"; } -.bi-shield-plus::before { content: "\f53a"; } -.bi-shield-shaded::before { content: "\f53b"; } -.bi-shield-slash-fill::before { content: "\f53c"; } -.bi-shield-slash::before { content: "\f53d"; } -.bi-shield-x::before { content: "\f53e"; } -.bi-shield::before { content: "\f53f"; } -.bi-shift-fill::before { content: "\f540"; } -.bi-shift::before { content: "\f541"; } -.bi-shop-window::before { content: "\f542"; } -.bi-shop::before { content: "\f543"; } -.bi-shuffle::before { content: "\f544"; } -.bi-signpost-2-fill::before { content: "\f545"; } -.bi-signpost-2::before { content: "\f546"; } -.bi-signpost-fill::before { content: "\f547"; } -.bi-signpost-split-fill::before { content: "\f548"; } -.bi-signpost-split::before { content: "\f549"; } -.bi-signpost::before { content: "\f54a"; } -.bi-sim-fill::before { content: "\f54b"; } -.bi-sim::before { content: "\f54c"; } -.bi-skip-backward-btn-fill::before { content: "\f54d"; } -.bi-skip-backward-btn::before { content: "\f54e"; } -.bi-skip-backward-circle-fill::before { content: "\f54f"; } -.bi-skip-backward-circle::before { content: "\f550"; } -.bi-skip-backward-fill::before { content: "\f551"; } -.bi-skip-backward::before { content: "\f552"; } -.bi-skip-end-btn-fill::before { content: "\f553"; } -.bi-skip-end-btn::before { content: "\f554"; } -.bi-skip-end-circle-fill::before { content: "\f555"; } -.bi-skip-end-circle::before { content: "\f556"; } -.bi-skip-end-fill::before { content: "\f557"; } -.bi-skip-end::before { content: "\f558"; } -.bi-skip-forward-btn-fill::before { content: "\f559"; } -.bi-skip-forward-btn::before { content: "\f55a"; } -.bi-skip-forward-circle-fill::before { content: "\f55b"; } -.bi-skip-forward-circle::before { content: "\f55c"; } -.bi-skip-forward-fill::before { content: "\f55d"; } -.bi-skip-forward::before { content: "\f55e"; } -.bi-skip-start-btn-fill::before { content: "\f55f"; } -.bi-skip-start-btn::before { content: "\f560"; } -.bi-skip-start-circle-fill::before { content: "\f561"; } -.bi-skip-start-circle::before { content: "\f562"; } -.bi-skip-start-fill::before { content: "\f563"; } -.bi-skip-start::before { content: "\f564"; } -.bi-slack::before { content: "\f565"; } -.bi-slash-circle-fill::before { content: "\f566"; } -.bi-slash-circle::before { content: "\f567"; } -.bi-slash-square-fill::before { content: "\f568"; } -.bi-slash-square::before { content: "\f569"; } -.bi-slash::before { content: "\f56a"; } -.bi-sliders::before { content: "\f56b"; } -.bi-smartwatch::before { content: "\f56c"; } -.bi-snow::before { content: "\f56d"; } -.bi-snow2::before { content: "\f56e"; } -.bi-snow3::before { content: "\f56f"; } -.bi-sort-alpha-down-alt::before { content: "\f570"; } -.bi-sort-alpha-down::before { content: "\f571"; } -.bi-sort-alpha-up-alt::before { content: "\f572"; } -.bi-sort-alpha-up::before { content: "\f573"; } -.bi-sort-down-alt::before { content: "\f574"; } -.bi-sort-down::before { content: "\f575"; } -.bi-sort-numeric-down-alt::before { content: "\f576"; } -.bi-sort-numeric-down::before { content: "\f577"; } -.bi-sort-numeric-up-alt::before { content: "\f578"; } -.bi-sort-numeric-up::before { content: "\f579"; } -.bi-sort-up-alt::before { content: "\f57a"; } -.bi-sort-up::before { content: "\f57b"; } -.bi-soundwave::before { content: "\f57c"; } -.bi-speaker-fill::before { content: "\f57d"; } -.bi-speaker::before { content: "\f57e"; } -.bi-speedometer::before { content: "\f57f"; } -.bi-speedometer2::before { content: "\f580"; } -.bi-spellcheck::before { content: "\f581"; } -.bi-square-fill::before { content: "\f582"; } -.bi-square-half::before { content: "\f583"; } -.bi-square::before { content: "\f584"; } -.bi-stack::before { content: "\f585"; } -.bi-star-fill::before { content: "\f586"; } -.bi-star-half::before { content: "\f587"; } -.bi-star::before { content: "\f588"; } -.bi-stars::before { content: "\f589"; } -.bi-stickies-fill::before { content: "\f58a"; } -.bi-stickies::before { content: "\f58b"; } -.bi-sticky-fill::before { content: "\f58c"; } -.bi-sticky::before { content: "\f58d"; } -.bi-stop-btn-fill::before { content: "\f58e"; } -.bi-stop-btn::before { content: "\f58f"; } -.bi-stop-circle-fill::before { content: "\f590"; } -.bi-stop-circle::before { content: "\f591"; } -.bi-stop-fill::before { content: "\f592"; } -.bi-stop::before { content: "\f593"; } -.bi-stoplights-fill::before { content: "\f594"; } -.bi-stoplights::before { content: "\f595"; } -.bi-stopwatch-fill::before { content: "\f596"; } -.bi-stopwatch::before { content: "\f597"; } -.bi-subtract::before { content: "\f598"; } -.bi-suit-club-fill::before { content: "\f599"; } -.bi-suit-club::before { content: "\f59a"; } -.bi-suit-diamond-fill::before { content: "\f59b"; } -.bi-suit-diamond::before { content: "\f59c"; } -.bi-suit-heart-fill::before { content: "\f59d"; } -.bi-suit-heart::before { content: "\f59e"; } -.bi-suit-spade-fill::before { content: "\f59f"; } -.bi-suit-spade::before { content: "\f5a0"; } -.bi-sun-fill::before { content: "\f5a1"; } -.bi-sun::before { content: "\f5a2"; } -.bi-sunglasses::before { content: "\f5a3"; } -.bi-sunrise-fill::before { content: "\f5a4"; } -.bi-sunrise::before { content: "\f5a5"; } -.bi-sunset-fill::before { content: "\f5a6"; } -.bi-sunset::before { content: "\f5a7"; } -.bi-symmetry-horizontal::before { content: "\f5a8"; } -.bi-symmetry-vertical::before { content: "\f5a9"; } -.bi-table::before { content: "\f5aa"; } -.bi-tablet-fill::before { content: "\f5ab"; } -.bi-tablet-landscape-fill::before { content: "\f5ac"; } -.bi-tablet-landscape::before { content: "\f5ad"; } -.bi-tablet::before { content: "\f5ae"; } -.bi-tag-fill::before { content: "\f5af"; } -.bi-tag::before { content: "\f5b0"; } -.bi-tags-fill::before { content: "\f5b1"; } -.bi-tags::before { content: "\f5b2"; } -.bi-telegram::before { content: "\f5b3"; } -.bi-telephone-fill::before { content: "\f5b4"; } -.bi-telephone-forward-fill::before { content: "\f5b5"; } -.bi-telephone-forward::before { content: "\f5b6"; } -.bi-telephone-inbound-fill::before { content: "\f5b7"; } -.bi-telephone-inbound::before { content: "\f5b8"; } -.bi-telephone-minus-fill::before { content: "\f5b9"; } -.bi-telephone-minus::before { content: "\f5ba"; } -.bi-telephone-outbound-fill::before { content: "\f5bb"; } -.bi-telephone-outbound::before { content: "\f5bc"; } -.bi-telephone-plus-fill::before { content: "\f5bd"; } -.bi-telephone-plus::before { content: "\f5be"; } -.bi-telephone-x-fill::before { content: "\f5bf"; } -.bi-telephone-x::before { content: "\f5c0"; } -.bi-telephone::before { content: "\f5c1"; } -.bi-terminal-fill::before { content: "\f5c2"; } -.bi-terminal::before { content: "\f5c3"; } -.bi-text-center::before { content: "\f5c4"; } -.bi-text-indent-left::before { content: "\f5c5"; } -.bi-text-indent-right::before { content: "\f5c6"; } -.bi-text-left::before { content: "\f5c7"; } -.bi-text-paragraph::before { content: "\f5c8"; } -.bi-text-right::before { content: "\f5c9"; } -.bi-textarea-resize::before { content: "\f5ca"; } -.bi-textarea-t::before { content: "\f5cb"; } -.bi-textarea::before { content: "\f5cc"; } -.bi-thermometer-half::before { content: "\f5cd"; } -.bi-thermometer-high::before { content: "\f5ce"; } -.bi-thermometer-low::before { content: "\f5cf"; } -.bi-thermometer-snow::before { content: "\f5d0"; } -.bi-thermometer-sun::before { content: "\f5d1"; } -.bi-thermometer::before { content: "\f5d2"; } -.bi-three-dots-vertical::before { content: "\f5d3"; } -.bi-three-dots::before { content: "\f5d4"; } -.bi-toggle-off::before { content: "\f5d5"; } -.bi-toggle-on::before { content: "\f5d6"; } -.bi-toggle2-off::before { content: "\f5d7"; } -.bi-toggle2-on::before { content: "\f5d8"; } -.bi-toggles::before { content: "\f5d9"; } -.bi-toggles2::before { content: "\f5da"; } -.bi-tools::before { content: "\f5db"; } -.bi-tornado::before { content: "\f5dc"; } -.bi-trash-fill::before { content: "\f5dd"; } -.bi-trash::before { content: "\f5de"; } -.bi-trash2-fill::before { content: "\f5df"; } -.bi-trash2::before { content: "\f5e0"; } -.bi-tree-fill::before { content: "\f5e1"; } -.bi-tree::before { content: "\f5e2"; } -.bi-triangle-fill::before { content: "\f5e3"; } -.bi-triangle-half::before { content: "\f5e4"; } -.bi-triangle::before { content: "\f5e5"; } -.bi-trophy-fill::before { content: "\f5e6"; } -.bi-trophy::before { content: "\f5e7"; } -.bi-tropical-storm::before { content: "\f5e8"; } -.bi-truck-flatbed::before { content: "\f5e9"; } -.bi-truck::before { content: "\f5ea"; } -.bi-tsunami::before { content: "\f5eb"; } -.bi-tv-fill::before { content: "\f5ec"; } -.bi-tv::before { content: "\f5ed"; } -.bi-twitch::before { content: "\f5ee"; } -.bi-twitter::before { content: "\f5ef"; } -.bi-type-bold::before { content: "\f5f0"; } -.bi-type-h1::before { content: "\f5f1"; } -.bi-type-h2::before { content: "\f5f2"; } -.bi-type-h3::before { content: "\f5f3"; } -.bi-type-italic::before { content: "\f5f4"; } -.bi-type-strikethrough::before { content: "\f5f5"; } -.bi-type-underline::before { content: "\f5f6"; } -.bi-type::before { content: "\f5f7"; } -.bi-ui-checks-grid::before { content: "\f5f8"; } -.bi-ui-checks::before { content: "\f5f9"; } -.bi-ui-radios-grid::before { content: "\f5fa"; } -.bi-ui-radios::before { content: "\f5fb"; } -.bi-umbrella-fill::before { content: "\f5fc"; } -.bi-umbrella::before { content: "\f5fd"; } -.bi-union::before { content: "\f5fe"; } -.bi-unlock-fill::before { content: "\f5ff"; } -.bi-unlock::before { content: "\f600"; } -.bi-upc-scan::before { content: "\f601"; } -.bi-upc::before { content: "\f602"; } -.bi-upload::before { content: "\f603"; } -.bi-vector-pen::before { content: "\f604"; } -.bi-view-list::before { content: "\f605"; } -.bi-view-stacked::before { content: "\f606"; } -.bi-vinyl-fill::before { content: "\f607"; } -.bi-vinyl::before { content: "\f608"; } -.bi-voicemail::before { content: "\f609"; } -.bi-volume-down-fill::before { content: "\f60a"; } -.bi-volume-down::before { content: "\f60b"; } -.bi-volume-mute-fill::before { content: "\f60c"; } -.bi-volume-mute::before { content: "\f60d"; } -.bi-volume-off-fill::before { content: "\f60e"; } -.bi-volume-off::before { content: "\f60f"; } -.bi-volume-up-fill::before { content: "\f610"; } -.bi-volume-up::before { content: "\f611"; } -.bi-vr::before { content: "\f612"; } -.bi-wallet-fill::before { content: "\f613"; } -.bi-wallet::before { content: "\f614"; } -.bi-wallet2::before { content: "\f615"; } -.bi-watch::before { content: "\f616"; } -.bi-water::before { content: "\f617"; } -.bi-whatsapp::before { content: "\f618"; } -.bi-wifi-1::before { content: "\f619"; } -.bi-wifi-2::before { content: "\f61a"; } -.bi-wifi-off::before { content: "\f61b"; } -.bi-wifi::before { content: "\f61c"; } -.bi-wind::before { content: "\f61d"; } -.bi-window-dock::before { content: "\f61e"; } -.bi-window-sidebar::before { content: "\f61f"; } -.bi-window::before { content: "\f620"; } -.bi-wrench::before { content: "\f621"; } -.bi-x-circle-fill::before { content: "\f622"; } -.bi-x-circle::before { content: "\f623"; } -.bi-x-diamond-fill::before { content: "\f624"; } -.bi-x-diamond::before { content: "\f625"; } -.bi-x-octagon-fill::before { content: "\f626"; } -.bi-x-octagon::before { content: "\f627"; } -.bi-x-square-fill::before { content: "\f628"; } -.bi-x-square::before { content: "\f629"; } -.bi-x::before { content: "\f62a"; } -.bi-youtube::before { content: "\f62b"; } -.bi-zoom-in::before { content: "\f62c"; } -.bi-zoom-out::before { content: "\f62d"; } -.bi-bank::before { content: "\f62e"; } -.bi-bank2::before { content: "\f62f"; } -.bi-bell-slash-fill::before { content: "\f630"; } -.bi-bell-slash::before { content: "\f631"; } -.bi-cash-coin::before { content: "\f632"; } -.bi-check-lg::before { content: "\f633"; } -.bi-coin::before { content: "\f634"; } -.bi-currency-bitcoin::before { content: "\f635"; } -.bi-currency-dollar::before { content: "\f636"; } -.bi-currency-euro::before { content: "\f637"; } -.bi-currency-exchange::before { content: "\f638"; } -.bi-currency-pound::before { content: "\f639"; } -.bi-currency-yen::before { content: "\f63a"; } -.bi-dash-lg::before { content: "\f63b"; } -.bi-exclamation-lg::before { content: "\f63c"; } -.bi-file-earmark-pdf-fill::before { content: "\f63d"; } -.bi-file-earmark-pdf::before { content: "\f63e"; } -.bi-file-pdf-fill::before { content: "\f63f"; } -.bi-file-pdf::before { content: "\f640"; } -.bi-gender-ambiguous::before { content: "\f641"; } -.bi-gender-female::before { content: "\f642"; } -.bi-gender-male::before { content: "\f643"; } -.bi-gender-trans::before { content: "\f644"; } -.bi-headset-vr::before { content: "\f645"; } -.bi-info-lg::before { content: "\f646"; } -.bi-mastodon::before { content: "\f647"; } -.bi-messenger::before { content: "\f648"; } -.bi-piggy-bank-fill::before { content: "\f649"; } -.bi-piggy-bank::before { content: "\f64a"; } -.bi-pin-map-fill::before { content: "\f64b"; } -.bi-pin-map::before { content: "\f64c"; } -.bi-plus-lg::before { content: "\f64d"; } -.bi-question-lg::before { content: "\f64e"; } -.bi-recycle::before { content: "\f64f"; } -.bi-reddit::before { content: "\f650"; } -.bi-safe-fill::before { content: "\f651"; } -.bi-safe2-fill::before { content: "\f652"; } -.bi-safe2::before { content: "\f653"; } -.bi-sd-card-fill::before { content: "\f654"; } -.bi-sd-card::before { content: "\f655"; } -.bi-skype::before { content: "\f656"; } -.bi-slash-lg::before { content: "\f657"; } -.bi-translate::before { content: "\f658"; } -.bi-x-lg::before { content: "\f659"; } -.bi-safe::before { content: "\f65a"; } -.bi-apple::before { content: "\f65b"; } -.bi-microsoft::before { content: "\f65d"; } -.bi-windows::before { content: "\f65e"; } -.bi-behance::before { content: "\f65c"; } -.bi-dribbble::before { content: "\f65f"; } -.bi-line::before { content: "\f660"; } -.bi-medium::before { content: "\f661"; } -.bi-paypal::before { content: "\f662"; } -.bi-pinterest::before { content: "\f663"; } -.bi-signal::before { content: "\f664"; } -.bi-snapchat::before { content: "\f665"; } -.bi-spotify::before { content: "\f666"; } -.bi-stack-overflow::before { content: "\f667"; } -.bi-strava::before { content: "\f668"; } -.bi-wordpress::before { content: "\f669"; } -.bi-vimeo::before { content: "\f66a"; } -.bi-activity::before { content: "\f66b"; } -.bi-easel2-fill::before { content: "\f66c"; } -.bi-easel2::before { content: "\f66d"; } -.bi-easel3-fill::before { content: "\f66e"; } -.bi-easel3::before { content: "\f66f"; } -.bi-fan::before { content: "\f670"; } -.bi-fingerprint::before { content: "\f671"; } -.bi-graph-down-arrow::before { content: "\f672"; } -.bi-graph-up-arrow::before { content: "\f673"; } -.bi-hypnotize::before { content: "\f674"; } -.bi-magic::before { content: "\f675"; } -.bi-person-rolodex::before { content: "\f676"; } -.bi-person-video::before { content: "\f677"; } -.bi-person-video2::before { content: "\f678"; } -.bi-person-video3::before { content: "\f679"; } -.bi-person-workspace::before { content: "\f67a"; } -.bi-radioactive::before { content: "\f67b"; } -.bi-webcam-fill::before { content: "\f67c"; } -.bi-webcam::before { content: "\f67d"; } -.bi-yin-yang::before { content: "\f67e"; } -.bi-bandaid-fill::before { content: "\f680"; } -.bi-bandaid::before { content: "\f681"; } -.bi-bluetooth::before { content: "\f682"; } -.bi-body-text::before { content: "\f683"; } -.bi-boombox::before { content: "\f684"; } -.bi-boxes::before { content: "\f685"; } -.bi-dpad-fill::before { content: "\f686"; } -.bi-dpad::before { content: "\f687"; } -.bi-ear-fill::before { content: "\f688"; } -.bi-ear::before { content: "\f689"; } -.bi-envelope-check-fill::before { content: "\f68b"; } -.bi-envelope-check::before { content: "\f68c"; } -.bi-envelope-dash-fill::before { content: "\f68e"; } -.bi-envelope-dash::before { content: "\f68f"; } -.bi-envelope-exclamation-fill::before { content: "\f691"; } -.bi-envelope-exclamation::before { content: "\f692"; } -.bi-envelope-plus-fill::before { content: "\f693"; } -.bi-envelope-plus::before { content: "\f694"; } -.bi-envelope-slash-fill::before { content: "\f696"; } -.bi-envelope-slash::before { content: "\f697"; } -.bi-envelope-x-fill::before { content: "\f699"; } -.bi-envelope-x::before { content: "\f69a"; } -.bi-explicit-fill::before { content: "\f69b"; } -.bi-explicit::before { content: "\f69c"; } -.bi-git::before { content: "\f69d"; } -.bi-infinity::before { content: "\f69e"; } -.bi-list-columns-reverse::before { content: "\f69f"; } -.bi-list-columns::before { content: "\f6a0"; } -.bi-meta::before { content: "\f6a1"; } -.bi-nintendo-switch::before { content: "\f6a4"; } -.bi-pc-display-horizontal::before { content: "\f6a5"; } -.bi-pc-display::before { content: "\f6a6"; } -.bi-pc-horizontal::before { content: "\f6a7"; } -.bi-pc::before { content: "\f6a8"; } -.bi-playstation::before { content: "\f6a9"; } -.bi-plus-slash-minus::before { content: "\f6aa"; } -.bi-projector-fill::before { content: "\f6ab"; } -.bi-projector::before { content: "\f6ac"; } -.bi-qr-code-scan::before { content: "\f6ad"; } -.bi-qr-code::before { content: "\f6ae"; } -.bi-quora::before { content: "\f6af"; } -.bi-quote::before { content: "\f6b0"; } -.bi-robot::before { content: "\f6b1"; } -.bi-send-check-fill::before { content: "\f6b2"; } -.bi-send-check::before { content: "\f6b3"; } -.bi-send-dash-fill::before { content: "\f6b4"; } -.bi-send-dash::before { content: "\f6b5"; } -.bi-send-exclamation-fill::before { content: "\f6b7"; } -.bi-send-exclamation::before { content: "\f6b8"; } -.bi-send-fill::before { content: "\f6b9"; } -.bi-send-plus-fill::before { content: "\f6ba"; } -.bi-send-plus::before { content: "\f6bb"; } -.bi-send-slash-fill::before { content: "\f6bc"; } -.bi-send-slash::before { content: "\f6bd"; } -.bi-send-x-fill::before { content: "\f6be"; } -.bi-send-x::before { content: "\f6bf"; } -.bi-send::before { content: "\f6c0"; } -.bi-steam::before { content: "\f6c1"; } -.bi-terminal-dash::before { content: "\f6c3"; } -.bi-terminal-plus::before { content: "\f6c4"; } -.bi-terminal-split::before { content: "\f6c5"; } -.bi-ticket-detailed-fill::before { content: "\f6c6"; } -.bi-ticket-detailed::before { content: "\f6c7"; } -.bi-ticket-fill::before { content: "\f6c8"; } -.bi-ticket-perforated-fill::before { content: "\f6c9"; } -.bi-ticket-perforated::before { content: "\f6ca"; } -.bi-ticket::before { content: "\f6cb"; } -.bi-tiktok::before { content: "\f6cc"; } -.bi-window-dash::before { content: "\f6cd"; } -.bi-window-desktop::before { content: "\f6ce"; } -.bi-window-fullscreen::before { content: "\f6cf"; } -.bi-window-plus::before { content: "\f6d0"; } -.bi-window-split::before { content: "\f6d1"; } -.bi-window-stack::before { content: "\f6d2"; } -.bi-window-x::before { content: "\f6d3"; } -.bi-xbox::before { content: "\f6d4"; } -.bi-ethernet::before { content: "\f6d5"; } -.bi-hdmi-fill::before { content: "\f6d6"; } -.bi-hdmi::before { content: "\f6d7"; } -.bi-usb-c-fill::before { content: "\f6d8"; } -.bi-usb-c::before { content: "\f6d9"; } -.bi-usb-fill::before { content: "\f6da"; } -.bi-usb-plug-fill::before { content: "\f6db"; } -.bi-usb-plug::before { content: "\f6dc"; } -.bi-usb-symbol::before { content: "\f6dd"; } -.bi-usb::before { content: "\f6de"; } -.bi-boombox-fill::before { content: "\f6df"; } -.bi-displayport::before { content: "\f6e1"; } -.bi-gpu-card::before { content: "\f6e2"; } -.bi-memory::before { content: "\f6e3"; } -.bi-modem-fill::before { content: "\f6e4"; } -.bi-modem::before { content: "\f6e5"; } -.bi-motherboard-fill::before { content: "\f6e6"; } -.bi-motherboard::before { content: "\f6e7"; } -.bi-optical-audio-fill::before { content: "\f6e8"; } -.bi-optical-audio::before { content: "\f6e9"; } -.bi-pci-card::before { content: "\f6ea"; } -.bi-router-fill::before { content: "\f6eb"; } -.bi-router::before { content: "\f6ec"; } -.bi-thunderbolt-fill::before { content: "\f6ef"; } -.bi-thunderbolt::before { content: "\f6f0"; } -.bi-usb-drive-fill::before { content: "\f6f1"; } -.bi-usb-drive::before { content: "\f6f2"; } -.bi-usb-micro-fill::before { content: "\f6f3"; } -.bi-usb-micro::before { content: "\f6f4"; } -.bi-usb-mini-fill::before { content: "\f6f5"; } -.bi-usb-mini::before { content: "\f6f6"; } -.bi-cloud-haze2::before { content: "\f6f7"; } -.bi-device-hdd-fill::before { content: "\f6f8"; } -.bi-device-hdd::before { content: "\f6f9"; } -.bi-device-ssd-fill::before { content: "\f6fa"; } -.bi-device-ssd::before { content: "\f6fb"; } -.bi-displayport-fill::before { content: "\f6fc"; } -.bi-mortarboard-fill::before { content: "\f6fd"; } -.bi-mortarboard::before { content: "\f6fe"; } -.bi-terminal-x::before { content: "\f6ff"; } -.bi-arrow-through-heart-fill::before { content: "\f700"; } -.bi-arrow-through-heart::before { content: "\f701"; } -.bi-badge-sd-fill::before { content: "\f702"; } -.bi-badge-sd::before { content: "\f703"; } -.bi-bag-heart-fill::before { content: "\f704"; } -.bi-bag-heart::before { content: "\f705"; } -.bi-balloon-fill::before { content: "\f706"; } -.bi-balloon-heart-fill::before { content: "\f707"; } -.bi-balloon-heart::before { content: "\f708"; } -.bi-balloon::before { content: "\f709"; } -.bi-box2-fill::before { content: "\f70a"; } -.bi-box2-heart-fill::before { content: "\f70b"; } -.bi-box2-heart::before { content: "\f70c"; } -.bi-box2::before { content: "\f70d"; } -.bi-braces-asterisk::before { content: "\f70e"; } -.bi-calendar-heart-fill::before { content: "\f70f"; } -.bi-calendar-heart::before { content: "\f710"; } -.bi-calendar2-heart-fill::before { content: "\f711"; } -.bi-calendar2-heart::before { content: "\f712"; } -.bi-chat-heart-fill::before { content: "\f713"; } -.bi-chat-heart::before { content: "\f714"; } -.bi-chat-left-heart-fill::before { content: "\f715"; } -.bi-chat-left-heart::before { content: "\f716"; } -.bi-chat-right-heart-fill::before { content: "\f717"; } -.bi-chat-right-heart::before { content: "\f718"; } -.bi-chat-square-heart-fill::before { content: "\f719"; } -.bi-chat-square-heart::before { content: "\f71a"; } -.bi-clipboard-check-fill::before { content: "\f71b"; } -.bi-clipboard-data-fill::before { content: "\f71c"; } -.bi-clipboard-fill::before { content: "\f71d"; } -.bi-clipboard-heart-fill::before { content: "\f71e"; } -.bi-clipboard-heart::before { content: "\f71f"; } -.bi-clipboard-minus-fill::before { content: "\f720"; } -.bi-clipboard-plus-fill::before { content: "\f721"; } -.bi-clipboard-pulse::before { content: "\f722"; } -.bi-clipboard-x-fill::before { content: "\f723"; } -.bi-clipboard2-check-fill::before { content: "\f724"; } -.bi-clipboard2-check::before { content: "\f725"; } -.bi-clipboard2-data-fill::before { content: "\f726"; } -.bi-clipboard2-data::before { content: "\f727"; } -.bi-clipboard2-fill::before { content: "\f728"; } -.bi-clipboard2-heart-fill::before { content: "\f729"; } -.bi-clipboard2-heart::before { content: "\f72a"; } -.bi-clipboard2-minus-fill::before { content: "\f72b"; } -.bi-clipboard2-minus::before { content: "\f72c"; } -.bi-clipboard2-plus-fill::before { content: "\f72d"; } -.bi-clipboard2-plus::before { content: "\f72e"; } -.bi-clipboard2-pulse-fill::before { content: "\f72f"; } -.bi-clipboard2-pulse::before { content: "\f730"; } -.bi-clipboard2-x-fill::before { content: "\f731"; } -.bi-clipboard2-x::before { content: "\f732"; } -.bi-clipboard2::before { content: "\f733"; } -.bi-emoji-kiss-fill::before { content: "\f734"; } -.bi-emoji-kiss::before { content: "\f735"; } -.bi-envelope-heart-fill::before { content: "\f736"; } -.bi-envelope-heart::before { content: "\f737"; } -.bi-envelope-open-heart-fill::before { content: "\f738"; } -.bi-envelope-open-heart::before { content: "\f739"; } -.bi-envelope-paper-fill::before { content: "\f73a"; } -.bi-envelope-paper-heart-fill::before { content: "\f73b"; } -.bi-envelope-paper-heart::before { content: "\f73c"; } -.bi-envelope-paper::before { content: "\f73d"; } -.bi-filetype-aac::before { content: "\f73e"; } -.bi-filetype-ai::before { content: "\f73f"; } -.bi-filetype-bmp::before { content: "\f740"; } -.bi-filetype-cs::before { content: "\f741"; } -.bi-filetype-css::before { content: "\f742"; } -.bi-filetype-csv::before { content: "\f743"; } -.bi-filetype-doc::before { content: "\f744"; } -.bi-filetype-docx::before { content: "\f745"; } -.bi-filetype-exe::before { content: "\f746"; } -.bi-filetype-gif::before { content: "\f747"; } -.bi-filetype-heic::before { content: "\f748"; } -.bi-filetype-html::before { content: "\f749"; } -.bi-filetype-java::before { content: "\f74a"; } -.bi-filetype-jpg::before { content: "\f74b"; } -.bi-filetype-js::before { content: "\f74c"; } -.bi-filetype-jsx::before { content: "\f74d"; } -.bi-filetype-key::before { content: "\f74e"; } -.bi-filetype-m4p::before { content: "\f74f"; } -.bi-filetype-md::before { content: "\f750"; } -.bi-filetype-mdx::before { content: "\f751"; } -.bi-filetype-mov::before { content: "\f752"; } -.bi-filetype-mp3::before { content: "\f753"; } -.bi-filetype-mp4::before { content: "\f754"; } -.bi-filetype-otf::before { content: "\f755"; } -.bi-filetype-pdf::before { content: "\f756"; } -.bi-filetype-php::before { content: "\f757"; } -.bi-filetype-png::before { content: "\f758"; } -.bi-filetype-ppt::before { content: "\f75a"; } -.bi-filetype-psd::before { content: "\f75b"; } -.bi-filetype-py::before { content: "\f75c"; } -.bi-filetype-raw::before { content: "\f75d"; } -.bi-filetype-rb::before { content: "\f75e"; } -.bi-filetype-sass::before { content: "\f75f"; } -.bi-filetype-scss::before { content: "\f760"; } -.bi-filetype-sh::before { content: "\f761"; } -.bi-filetype-svg::before { content: "\f762"; } -.bi-filetype-tiff::before { content: "\f763"; } -.bi-filetype-tsx::before { content: "\f764"; } -.bi-filetype-ttf::before { content: "\f765"; } -.bi-filetype-txt::before { content: "\f766"; } -.bi-filetype-wav::before { content: "\f767"; } -.bi-filetype-woff::before { content: "\f768"; } -.bi-filetype-xls::before { content: "\f76a"; } -.bi-filetype-xml::before { content: "\f76b"; } -.bi-filetype-yml::before { content: "\f76c"; } -.bi-heart-arrow::before { content: "\f76d"; } -.bi-heart-pulse-fill::before { content: "\f76e"; } -.bi-heart-pulse::before { content: "\f76f"; } -.bi-heartbreak-fill::before { content: "\f770"; } -.bi-heartbreak::before { content: "\f771"; } -.bi-hearts::before { content: "\f772"; } -.bi-hospital-fill::before { content: "\f773"; } -.bi-hospital::before { content: "\f774"; } -.bi-house-heart-fill::before { content: "\f775"; } -.bi-house-heart::before { content: "\f776"; } -.bi-incognito::before { content: "\f777"; } -.bi-magnet-fill::before { content: "\f778"; } -.bi-magnet::before { content: "\f779"; } -.bi-person-heart::before { content: "\f77a"; } -.bi-person-hearts::before { content: "\f77b"; } -.bi-phone-flip::before { content: "\f77c"; } -.bi-plugin::before { content: "\f77d"; } -.bi-postage-fill::before { content: "\f77e"; } -.bi-postage-heart-fill::before { content: "\f77f"; } -.bi-postage-heart::before { content: "\f780"; } -.bi-postage::before { content: "\f781"; } -.bi-postcard-fill::before { content: "\f782"; } -.bi-postcard-heart-fill::before { content: "\f783"; } -.bi-postcard-heart::before { content: "\f784"; } -.bi-postcard::before { content: "\f785"; } -.bi-search-heart-fill::before { content: "\f786"; } -.bi-search-heart::before { content: "\f787"; } -.bi-sliders2-vertical::before { content: "\f788"; } -.bi-sliders2::before { content: "\f789"; } -.bi-trash3-fill::before { content: "\f78a"; } -.bi-trash3::before { content: "\f78b"; } -.bi-valentine::before { content: "\f78c"; } -.bi-valentine2::before { content: "\f78d"; } -.bi-wrench-adjustable-circle-fill::before { content: "\f78e"; } -.bi-wrench-adjustable-circle::before { content: "\f78f"; } -.bi-wrench-adjustable::before { content: "\f790"; } -.bi-filetype-json::before { content: "\f791"; } -.bi-filetype-pptx::before { content: "\f792"; } -.bi-filetype-xlsx::before { content: "\f793"; } -.bi-1-circle-fill::before { content: "\f796"; } -.bi-1-circle::before { content: "\f797"; } -.bi-1-square-fill::before { content: "\f798"; } -.bi-1-square::before { content: "\f799"; } -.bi-2-circle-fill::before { content: "\f79c"; } -.bi-2-circle::before { content: "\f79d"; } -.bi-2-square-fill::before { content: "\f79e"; } -.bi-2-square::before { content: "\f79f"; } -.bi-3-circle-fill::before { content: "\f7a2"; } -.bi-3-circle::before { content: "\f7a3"; } -.bi-3-square-fill::before { content: "\f7a4"; } -.bi-3-square::before { content: "\f7a5"; } -.bi-4-circle-fill::before { content: "\f7a8"; } -.bi-4-circle::before { content: "\f7a9"; } -.bi-4-square-fill::before { content: "\f7aa"; } -.bi-4-square::before { content: "\f7ab"; } -.bi-5-circle-fill::before { content: "\f7ae"; } -.bi-5-circle::before { content: "\f7af"; } -.bi-5-square-fill::before { content: "\f7b0"; } -.bi-5-square::before { content: "\f7b1"; } -.bi-6-circle-fill::before { content: "\f7b4"; } -.bi-6-circle::before { content: "\f7b5"; } -.bi-6-square-fill::before { content: "\f7b6"; } -.bi-6-square::before { content: "\f7b7"; } -.bi-7-circle-fill::before { content: "\f7ba"; } -.bi-7-circle::before { content: "\f7bb"; } -.bi-7-square-fill::before { content: "\f7bc"; } -.bi-7-square::before { content: "\f7bd"; } -.bi-8-circle-fill::before { content: "\f7c0"; } -.bi-8-circle::before { content: "\f7c1"; } -.bi-8-square-fill::before { content: "\f7c2"; } -.bi-8-square::before { content: "\f7c3"; } -.bi-9-circle-fill::before { content: "\f7c6"; } -.bi-9-circle::before { content: "\f7c7"; } -.bi-9-square-fill::before { content: "\f7c8"; } -.bi-9-square::before { content: "\f7c9"; } -.bi-airplane-engines-fill::before { content: "\f7ca"; } -.bi-airplane-engines::before { content: "\f7cb"; } -.bi-airplane-fill::before { content: "\f7cc"; } -.bi-airplane::before { content: "\f7cd"; } -.bi-alexa::before { content: "\f7ce"; } -.bi-alipay::before { content: "\f7cf"; } -.bi-android::before { content: "\f7d0"; } -.bi-android2::before { content: "\f7d1"; } -.bi-box-fill::before { content: "\f7d2"; } -.bi-box-seam-fill::before { content: "\f7d3"; } -.bi-browser-chrome::before { content: "\f7d4"; } -.bi-browser-edge::before { content: "\f7d5"; } -.bi-browser-firefox::before { content: "\f7d6"; } -.bi-browser-safari::before { content: "\f7d7"; } -.bi-c-circle-fill::before { content: "\f7da"; } -.bi-c-circle::before { content: "\f7db"; } -.bi-c-square-fill::before { content: "\f7dc"; } -.bi-c-square::before { content: "\f7dd"; } -.bi-capsule-pill::before { content: "\f7de"; } -.bi-capsule::before { content: "\f7df"; } -.bi-car-front-fill::before { content: "\f7e0"; } -.bi-car-front::before { content: "\f7e1"; } -.bi-cassette-fill::before { content: "\f7e2"; } -.bi-cassette::before { content: "\f7e3"; } -.bi-cc-circle-fill::before { content: "\f7e6"; } -.bi-cc-circle::before { content: "\f7e7"; } -.bi-cc-square-fill::before { content: "\f7e8"; } -.bi-cc-square::before { content: "\f7e9"; } -.bi-cup-hot-fill::before { content: "\f7ea"; } -.bi-cup-hot::before { content: "\f7eb"; } -.bi-currency-rupee::before { content: "\f7ec"; } -.bi-dropbox::before { content: "\f7ed"; } -.bi-escape::before { content: "\f7ee"; } -.bi-fast-forward-btn-fill::before { content: "\f7ef"; } -.bi-fast-forward-btn::before { content: "\f7f0"; } -.bi-fast-forward-circle-fill::before { content: "\f7f1"; } -.bi-fast-forward-circle::before { content: "\f7f2"; } -.bi-fast-forward-fill::before { content: "\f7f3"; } -.bi-fast-forward::before { content: "\f7f4"; } -.bi-filetype-sql::before { content: "\f7f5"; } -.bi-fire::before { content: "\f7f6"; } -.bi-google-play::before { content: "\f7f7"; } -.bi-h-circle-fill::before { content: "\f7fa"; } -.bi-h-circle::before { content: "\f7fb"; } -.bi-h-square-fill::before { content: "\f7fc"; } -.bi-h-square::before { content: "\f7fd"; } -.bi-indent::before { content: "\f7fe"; } -.bi-lungs-fill::before { content: "\f7ff"; } -.bi-lungs::before { content: "\f800"; } -.bi-microsoft-teams::before { content: "\f801"; } -.bi-p-circle-fill::before { content: "\f804"; } -.bi-p-circle::before { content: "\f805"; } -.bi-p-square-fill::before { content: "\f806"; } -.bi-p-square::before { content: "\f807"; } -.bi-pass-fill::before { content: "\f808"; } -.bi-pass::before { content: "\f809"; } -.bi-prescription::before { content: "\f80a"; } -.bi-prescription2::before { content: "\f80b"; } -.bi-r-circle-fill::before { content: "\f80e"; } -.bi-r-circle::before { content: "\f80f"; } -.bi-r-square-fill::before { content: "\f810"; } -.bi-r-square::before { content: "\f811"; } -.bi-repeat-1::before { content: "\f812"; } -.bi-repeat::before { content: "\f813"; } -.bi-rewind-btn-fill::before { content: "\f814"; } -.bi-rewind-btn::before { content: "\f815"; } -.bi-rewind-circle-fill::before { content: "\f816"; } -.bi-rewind-circle::before { content: "\f817"; } -.bi-rewind-fill::before { content: "\f818"; } -.bi-rewind::before { content: "\f819"; } -.bi-train-freight-front-fill::before { content: "\f81a"; } -.bi-train-freight-front::before { content: "\f81b"; } -.bi-train-front-fill::before { content: "\f81c"; } -.bi-train-front::before { content: "\f81d"; } -.bi-train-lightrail-front-fill::before { content: "\f81e"; } -.bi-train-lightrail-front::before { content: "\f81f"; } -.bi-truck-front-fill::before { content: "\f820"; } -.bi-truck-front::before { content: "\f821"; } -.bi-ubuntu::before { content: "\f822"; } -.bi-unindent::before { content: "\f823"; } -.bi-unity::before { content: "\f824"; } -.bi-universal-access-circle::before { content: "\f825"; } -.bi-universal-access::before { content: "\f826"; } -.bi-virus::before { content: "\f827"; } -.bi-virus2::before { content: "\f828"; } -.bi-wechat::before { content: "\f829"; } -.bi-yelp::before { content: "\f82a"; } -.bi-sign-stop-fill::before { content: "\f82b"; } -.bi-sign-stop-lights-fill::before { content: "\f82c"; } -.bi-sign-stop-lights::before { content: "\f82d"; } -.bi-sign-stop::before { content: "\f82e"; } -.bi-sign-turn-left-fill::before { content: "\f82f"; } -.bi-sign-turn-left::before { content: "\f830"; } -.bi-sign-turn-right-fill::before { content: "\f831"; } -.bi-sign-turn-right::before { content: "\f832"; } -.bi-sign-turn-slight-left-fill::before { content: "\f833"; } -.bi-sign-turn-slight-left::before { content: "\f834"; } -.bi-sign-turn-slight-right-fill::before { content: "\f835"; } -.bi-sign-turn-slight-right::before { content: "\f836"; } -.bi-sign-yield-fill::before { content: "\f837"; } -.bi-sign-yield::before { content: "\f838"; } -.bi-ev-station-fill::before { content: "\f839"; } -.bi-ev-station::before { content: "\f83a"; } -.bi-fuel-pump-diesel-fill::before { content: "\f83b"; } -.bi-fuel-pump-diesel::before { content: "\f83c"; } -.bi-fuel-pump-fill::before { content: "\f83d"; } -.bi-fuel-pump::before { content: "\f83e"; } -.bi-0-circle-fill::before { content: "\f83f"; } -.bi-0-circle::before { content: "\f840"; } -.bi-0-square-fill::before { content: "\f841"; } -.bi-0-square::before { content: "\f842"; } -.bi-rocket-fill::before { content: "\f843"; } -.bi-rocket-takeoff-fill::before { content: "\f844"; } -.bi-rocket-takeoff::before { content: "\f845"; } -.bi-rocket::before { content: "\f846"; } -.bi-stripe::before { content: "\f847"; } -.bi-subscript::before { content: "\f848"; } -.bi-superscript::before { content: "\f849"; } -.bi-trello::before { content: "\f84a"; } -.bi-envelope-at-fill::before { content: "\f84b"; } -.bi-envelope-at::before { content: "\f84c"; } -.bi-regex::before { content: "\f84d"; } -.bi-text-wrap::before { content: "\f84e"; } -.bi-sign-dead-end-fill::before { content: "\f84f"; } -.bi-sign-dead-end::before { content: "\f850"; } -.bi-sign-do-not-enter-fill::before { content: "\f851"; } -.bi-sign-do-not-enter::before { content: "\f852"; } -.bi-sign-intersection-fill::before { content: "\f853"; } -.bi-sign-intersection-side-fill::before { content: "\f854"; } -.bi-sign-intersection-side::before { content: "\f855"; } -.bi-sign-intersection-t-fill::before { content: "\f856"; } -.bi-sign-intersection-t::before { content: "\f857"; } -.bi-sign-intersection-y-fill::before { content: "\f858"; } -.bi-sign-intersection-y::before { content: "\f859"; } -.bi-sign-intersection::before { content: "\f85a"; } -.bi-sign-merge-left-fill::before { content: "\f85b"; } -.bi-sign-merge-left::before { content: "\f85c"; } -.bi-sign-merge-right-fill::before { content: "\f85d"; } -.bi-sign-merge-right::before { content: "\f85e"; } -.bi-sign-no-left-turn-fill::before { content: "\f85f"; } -.bi-sign-no-left-turn::before { content: "\f860"; } -.bi-sign-no-parking-fill::before { content: "\f861"; } -.bi-sign-no-parking::before { content: "\f862"; } -.bi-sign-no-right-turn-fill::before { content: "\f863"; } -.bi-sign-no-right-turn::before { content: "\f864"; } -.bi-sign-railroad-fill::before { content: "\f865"; } -.bi-sign-railroad::before { content: "\f866"; } -.bi-building-add::before { content: "\f867"; } -.bi-building-check::before { content: "\f868"; } -.bi-building-dash::before { content: "\f869"; } -.bi-building-down::before { content: "\f86a"; } -.bi-building-exclamation::before { content: "\f86b"; } -.bi-building-fill-add::before { content: "\f86c"; } -.bi-building-fill-check::before { content: "\f86d"; } -.bi-building-fill-dash::before { content: "\f86e"; } -.bi-building-fill-down::before { content: "\f86f"; } -.bi-building-fill-exclamation::before { content: "\f870"; } -.bi-building-fill-gear::before { content: "\f871"; } -.bi-building-fill-lock::before { content: "\f872"; } -.bi-building-fill-slash::before { content: "\f873"; } -.bi-building-fill-up::before { content: "\f874"; } -.bi-building-fill-x::before { content: "\f875"; } -.bi-building-fill::before { content: "\f876"; } -.bi-building-gear::before { content: "\f877"; } -.bi-building-lock::before { content: "\f878"; } -.bi-building-slash::before { content: "\f879"; } -.bi-building-up::before { content: "\f87a"; } -.bi-building-x::before { content: "\f87b"; } -.bi-buildings-fill::before { content: "\f87c"; } -.bi-buildings::before { content: "\f87d"; } -.bi-bus-front-fill::before { content: "\f87e"; } -.bi-bus-front::before { content: "\f87f"; } -.bi-ev-front-fill::before { content: "\f880"; } -.bi-ev-front::before { content: "\f881"; } -.bi-globe-americas::before { content: "\f882"; } -.bi-globe-asia-australia::before { content: "\f883"; } -.bi-globe-central-south-asia::before { content: "\f884"; } -.bi-globe-europe-africa::before { content: "\f885"; } -.bi-house-add-fill::before { content: "\f886"; } -.bi-house-add::before { content: "\f887"; } -.bi-house-check-fill::before { content: "\f888"; } -.bi-house-check::before { content: "\f889"; } -.bi-house-dash-fill::before { content: "\f88a"; } -.bi-house-dash::before { content: "\f88b"; } -.bi-house-down-fill::before { content: "\f88c"; } -.bi-house-down::before { content: "\f88d"; } -.bi-house-exclamation-fill::before { content: "\f88e"; } -.bi-house-exclamation::before { content: "\f88f"; } -.bi-house-gear-fill::before { content: "\f890"; } -.bi-house-gear::before { content: "\f891"; } -.bi-house-lock-fill::before { content: "\f892"; } -.bi-house-lock::before { content: "\f893"; } -.bi-house-slash-fill::before { content: "\f894"; } -.bi-house-slash::before { content: "\f895"; } -.bi-house-up-fill::before { content: "\f896"; } -.bi-house-up::before { content: "\f897"; } -.bi-house-x-fill::before { content: "\f898"; } -.bi-house-x::before { content: "\f899"; } -.bi-person-add::before { content: "\f89a"; } -.bi-person-down::before { content: "\f89b"; } -.bi-person-exclamation::before { content: "\f89c"; } -.bi-person-fill-add::before { content: "\f89d"; } -.bi-person-fill-check::before { content: "\f89e"; } -.bi-person-fill-dash::before { content: "\f89f"; } -.bi-person-fill-down::before { content: "\f8a0"; } -.bi-person-fill-exclamation::before { content: "\f8a1"; } -.bi-person-fill-gear::before { content: "\f8a2"; } -.bi-person-fill-lock::before { content: "\f8a3"; } -.bi-person-fill-slash::before { content: "\f8a4"; } -.bi-person-fill-up::before { content: "\f8a5"; } -.bi-person-fill-x::before { content: "\f8a6"; } -.bi-person-gear::before { content: "\f8a7"; } -.bi-person-lock::before { content: "\f8a8"; } -.bi-person-slash::before { content: "\f8a9"; } -.bi-person-up::before { content: "\f8aa"; } -.bi-scooter::before { content: "\f8ab"; } -.bi-taxi-front-fill::before { content: "\f8ac"; } -.bi-taxi-front::before { content: "\f8ad"; } -.bi-amd::before { content: "\f8ae"; } -.bi-database-add::before { content: "\f8af"; } -.bi-database-check::before { content: "\f8b0"; } -.bi-database-dash::before { content: "\f8b1"; } -.bi-database-down::before { content: "\f8b2"; } -.bi-database-exclamation::before { content: "\f8b3"; } -.bi-database-fill-add::before { content: "\f8b4"; } -.bi-database-fill-check::before { content: "\f8b5"; } -.bi-database-fill-dash::before { content: "\f8b6"; } -.bi-database-fill-down::before { content: "\f8b7"; } -.bi-database-fill-exclamation::before { content: "\f8b8"; } -.bi-database-fill-gear::before { content: "\f8b9"; } -.bi-database-fill-lock::before { content: "\f8ba"; } -.bi-database-fill-slash::before { content: "\f8bb"; } -.bi-database-fill-up::before { content: "\f8bc"; } -.bi-database-fill-x::before { content: "\f8bd"; } -.bi-database-fill::before { content: "\f8be"; } -.bi-database-gear::before { content: "\f8bf"; } -.bi-database-lock::before { content: "\f8c0"; } -.bi-database-slash::before { content: "\f8c1"; } -.bi-database-up::before { content: "\f8c2"; } -.bi-database-x::before { content: "\f8c3"; } -.bi-database::before { content: "\f8c4"; } -.bi-houses-fill::before { content: "\f8c5"; } -.bi-houses::before { content: "\f8c6"; } -.bi-nvidia::before { content: "\f8c7"; } -.bi-person-vcard-fill::before { content: "\f8c8"; } -.bi-person-vcard::before { content: "\f8c9"; } -.bi-sina-weibo::before { content: "\f8ca"; } -.bi-tencent-qq::before { content: "\f8cb"; } -.bi-wikipedia::before { content: "\f8cc"; } -.bi-alphabet-uppercase::before { content: "\f2a5"; } -.bi-alphabet::before { content: "\f68a"; } -.bi-amazon::before { content: "\f68d"; } -.bi-arrows-collapse-vertical::before { content: "\f690"; } -.bi-arrows-expand-vertical::before { content: "\f695"; } -.bi-arrows-vertical::before { content: "\f698"; } -.bi-arrows::before { content: "\f6a2"; } -.bi-ban-fill::before { content: "\f6a3"; } -.bi-ban::before { content: "\f6b6"; } -.bi-bing::before { content: "\f6c2"; } -.bi-cake::before { content: "\f6e0"; } -.bi-cake2::before { content: "\f6ed"; } -.bi-cookie::before { content: "\f6ee"; } -.bi-copy::before { content: "\f759"; } -.bi-crosshair::before { content: "\f769"; } -.bi-crosshair2::before { content: "\f794"; } -.bi-emoji-astonished-fill::before { content: "\f795"; } -.bi-emoji-astonished::before { content: "\f79a"; } -.bi-emoji-grimace-fill::before { content: "\f79b"; } -.bi-emoji-grimace::before { content: "\f7a0"; } -.bi-emoji-grin-fill::before { content: "\f7a1"; } -.bi-emoji-grin::before { content: "\f7a6"; } -.bi-emoji-surprise-fill::before { content: "\f7a7"; } -.bi-emoji-surprise::before { content: "\f7ac"; } -.bi-emoji-tear-fill::before { content: "\f7ad"; } -.bi-emoji-tear::before { content: "\f7b2"; } -.bi-envelope-arrow-down-fill::before { content: "\f7b3"; } -.bi-envelope-arrow-down::before { content: "\f7b8"; } -.bi-envelope-arrow-up-fill::before { content: "\f7b9"; } -.bi-envelope-arrow-up::before { content: "\f7be"; } -.bi-feather::before { content: "\f7bf"; } -.bi-feather2::before { content: "\f7c4"; } -.bi-floppy-fill::before { content: "\f7c5"; } -.bi-floppy::before { content: "\f7d8"; } -.bi-floppy2-fill::before { content: "\f7d9"; } -.bi-floppy2::before { content: "\f7e4"; } -.bi-gitlab::before { content: "\f7e5"; } -.bi-highlighter::before { content: "\f7f8"; } -.bi-marker-tip::before { content: "\f802"; } -.bi-nvme-fill::before { content: "\f803"; } -.bi-nvme::before { content: "\f80c"; } -.bi-opencollective::before { content: "\f80d"; } -.bi-pci-card-network::before { content: "\f8cd"; } -.bi-pci-card-sound::before { content: "\f8ce"; } -.bi-radar::before { content: "\f8cf"; } -.bi-send-arrow-down-fill::before { content: "\f8d0"; } -.bi-send-arrow-down::before { content: "\f8d1"; } -.bi-send-arrow-up-fill::before { content: "\f8d2"; } -.bi-send-arrow-up::before { content: "\f8d3"; } -.bi-sim-slash-fill::before { content: "\f8d4"; } -.bi-sim-slash::before { content: "\f8d5"; } -.bi-sourceforge::before { content: "\f8d6"; } -.bi-substack::before { content: "\f8d7"; } -.bi-threads-fill::before { content: "\f8d8"; } -.bi-threads::before { content: "\f8d9"; } -.bi-transparency::before { content: "\f8da"; } -.bi-twitter-x::before { content: "\f8db"; } -.bi-type-h4::before { content: "\f8dc"; } -.bi-type-h5::before { content: "\f8dd"; } -.bi-type-h6::before { content: "\f8de"; } -.bi-backpack-fill::before { content: "\f8df"; } -.bi-backpack::before { content: "\f8e0"; } -.bi-backpack2-fill::before { content: "\f8e1"; } -.bi-backpack2::before { content: "\f8e2"; } -.bi-backpack3-fill::before { content: "\f8e3"; } -.bi-backpack3::before { content: "\f8e4"; } -.bi-backpack4-fill::before { content: "\f8e5"; } -.bi-backpack4::before { content: "\f8e6"; } -.bi-brilliance::before { content: "\f8e7"; } -.bi-cake-fill::before { content: "\f8e8"; } -.bi-cake2-fill::before { content: "\f8e9"; } -.bi-duffle-fill::before { content: "\f8ea"; } -.bi-duffle::before { content: "\f8eb"; } -.bi-exposure::before { content: "\f8ec"; } -.bi-gender-neuter::before { content: "\f8ed"; } -.bi-highlights::before { content: "\f8ee"; } -.bi-luggage-fill::before { content: "\f8ef"; } -.bi-luggage::before { content: "\f8f0"; } -.bi-mailbox-flag::before { content: "\f8f1"; } -.bi-mailbox2-flag::before { content: "\f8f2"; } -.bi-noise-reduction::before { content: "\f8f3"; } -.bi-passport-fill::before { content: "\f8f4"; } -.bi-passport::before { content: "\f8f5"; } -.bi-person-arms-up::before { content: "\f8f6"; } -.bi-person-raised-hand::before { content: "\f8f7"; } -.bi-person-standing-dress::before { content: "\f8f8"; } -.bi-person-standing::before { content: "\f8f9"; } -.bi-person-walking::before { content: "\f8fa"; } -.bi-person-wheelchair::before { content: "\f8fb"; } -.bi-shadows::before { content: "\f8fc"; } -.bi-suitcase-fill::before { content: "\f8fd"; } -.bi-suitcase-lg-fill::before { content: "\f8fe"; } -.bi-suitcase-lg::before { content: "\f8ff"; } -.bi-suitcase::before { content: "\f900"; } -.bi-suitcase2-fill::before { content: "\f901"; } -.bi-suitcase2::before { content: "\f902"; } -.bi-vignette::before { content: "\f903"; } diff --git a/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/uncertainty_files/libs/bootstrap/bootstrap-icons.woff b/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/uncertainty_files/libs/bootstrap/bootstrap-icons.woff deleted file mode 100644 index dbeeb0556..000000000 Binary files a/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/uncertainty_files/libs/bootstrap/bootstrap-icons.woff and /dev/null differ diff --git a/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/uncertainty_files/libs/bootstrap/bootstrap.min.css b/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/uncertainty_files/libs/bootstrap/bootstrap.min.css deleted file mode 100644 index d6947f2ce..000000000 --- a/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/uncertainty_files/libs/bootstrap/bootstrap.min.css +++ /dev/null @@ -1,12 +0,0 @@ -/*! - * Bootstrap v5.3.1 (https://getbootstrap.com/) - * Copyright 2011-2023 The Bootstrap Authors - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) - */:root,[data-bs-theme=light]{--bs-blue: #0d6efd;--bs-indigo: #6610f2;--bs-purple: #6f42c1;--bs-pink: #d63384;--bs-red: #dc3545;--bs-orange: #fd7e14;--bs-yellow: #ffc107;--bs-green: #198754;--bs-teal: #20c997;--bs-cyan: #0dcaf0;--bs-black: #000;--bs-white: #ffffff;--bs-gray: #6c757d;--bs-gray-dark: #343a40;--bs-gray-100: #f8f9fa;--bs-gray-200: #e9ecef;--bs-gray-300: #dee2e6;--bs-gray-400: #ced4da;--bs-gray-500: #adb5bd;--bs-gray-600: #6c757d;--bs-gray-700: #495057;--bs-gray-800: #343a40;--bs-gray-900: #212529;--bs-default: #dee2e6;--bs-primary: #0d6efd;--bs-secondary: #6c757d;--bs-success: #198754;--bs-info: #0dcaf0;--bs-warning: #ffc107;--bs-danger: #dc3545;--bs-light: #f8f9fa;--bs-dark: #212529;--bs-default-rgb: 222, 226, 230;--bs-primary-rgb: 13, 110, 253;--bs-secondary-rgb: 108, 117, 125;--bs-success-rgb: 25, 135, 84;--bs-info-rgb: 13, 202, 240;--bs-warning-rgb: 255, 193, 7;--bs-danger-rgb: 220, 53, 69;--bs-light-rgb: 248, 249, 250;--bs-dark-rgb: 33, 37, 41;--bs-primary-text-emphasis: #052c65;--bs-secondary-text-emphasis: #2b2f32;--bs-success-text-emphasis: #0a3622;--bs-info-text-emphasis: #055160;--bs-warning-text-emphasis: #664d03;--bs-danger-text-emphasis: #58151c;--bs-light-text-emphasis: #495057;--bs-dark-text-emphasis: #495057;--bs-primary-bg-subtle: #cfe2ff;--bs-secondary-bg-subtle: #e2e3e5;--bs-success-bg-subtle: #d1e7dd;--bs-info-bg-subtle: #cff4fc;--bs-warning-bg-subtle: #fff3cd;--bs-danger-bg-subtle: #f8d7da;--bs-light-bg-subtle: #fcfcfd;--bs-dark-bg-subtle: #ced4da;--bs-primary-border-subtle: #9ec5fe;--bs-secondary-border-subtle: #c4c8cb;--bs-success-border-subtle: #a3cfbb;--bs-info-border-subtle: #9eeaf9;--bs-warning-border-subtle: #ffe69c;--bs-danger-border-subtle: #f1aeb5;--bs-light-border-subtle: #e9ecef;--bs-dark-border-subtle: #adb5bd;--bs-white-rgb: 255, 255, 255;--bs-black-rgb: 0, 0, 0;--bs-font-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));--bs-root-font-size: 17px;--bs-body-font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--bs-body-font-size:1rem;--bs-body-font-weight: 400;--bs-body-line-height: 1.5;--bs-body-color: #212529;--bs-body-color-rgb: 33, 37, 41;--bs-body-bg: #ffffff;--bs-body-bg-rgb: 255, 255, 255;--bs-emphasis-color: #000;--bs-emphasis-color-rgb: 0, 0, 0;--bs-secondary-color: rgba(33, 37, 41, 0.75);--bs-secondary-color-rgb: 33, 37, 41;--bs-secondary-bg: #e9ecef;--bs-secondary-bg-rgb: 233, 236, 239;--bs-tertiary-color: rgba(33, 37, 41, 0.5);--bs-tertiary-color-rgb: 33, 37, 41;--bs-tertiary-bg: #f8f9fa;--bs-tertiary-bg-rgb: 248, 249, 250;--bs-heading-color: inherit;--bs-link-color: #0d6efd;--bs-link-color-rgb: 13, 110, 253;--bs-link-decoration: underline;--bs-link-hover-color: #0a58ca;--bs-link-hover-color-rgb: 10, 88, 202;--bs-code-color: #7d12ba;--bs-highlight-bg: #fff3cd;--bs-border-width: 1px;--bs-border-style: solid;--bs-border-color: #dee2e6;--bs-border-color-translucent: rgba(0, 0, 0, 0.175);--bs-border-radius: 0.375rem;--bs-border-radius-sm: 0.25rem;--bs-border-radius-lg: 0.5rem;--bs-border-radius-xl: 1rem;--bs-border-radius-xxl: 2rem;--bs-border-radius-2xl: var(--bs-border-radius-xxl);--bs-border-radius-pill: 50rem;--bs-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);--bs-box-shadow-sm: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);--bs-box-shadow-lg: 0 1rem 3rem rgba(0, 0, 0, 0.175);--bs-box-shadow-inset: inset 0 1px 2px rgba(0, 0, 0, 0.075);--bs-focus-ring-width: 0.25rem;--bs-focus-ring-opacity: 0.25;--bs-focus-ring-color: rgba(13, 110, 253, 0.25);--bs-form-valid-color: #198754;--bs-form-valid-border-color: #198754;--bs-form-invalid-color: #dc3545;--bs-form-invalid-border-color: #dc3545}[data-bs-theme=dark]{color-scheme:dark;--bs-body-color: #dee2e6;--bs-body-color-rgb: 222, 226, 230;--bs-body-bg: #212529;--bs-body-bg-rgb: 33, 37, 41;--bs-emphasis-color: #ffffff;--bs-emphasis-color-rgb: 255, 255, 255;--bs-secondary-color: rgba(222, 226, 230, 0.75);--bs-secondary-color-rgb: 222, 226, 230;--bs-secondary-bg: #343a40;--bs-secondary-bg-rgb: 52, 58, 64;--bs-tertiary-color: rgba(222, 226, 230, 0.5);--bs-tertiary-color-rgb: 222, 226, 230;--bs-tertiary-bg: #2b3035;--bs-tertiary-bg-rgb: 43, 48, 53;--bs-primary-text-emphasis: #6ea8fe;--bs-secondary-text-emphasis: #a7acb1;--bs-success-text-emphasis: #75b798;--bs-info-text-emphasis: #6edff6;--bs-warning-text-emphasis: #ffda6a;--bs-danger-text-emphasis: #ea868f;--bs-light-text-emphasis: #f8f9fa;--bs-dark-text-emphasis: #dee2e6;--bs-primary-bg-subtle: #031633;--bs-secondary-bg-subtle: #161719;--bs-success-bg-subtle: #051b11;--bs-info-bg-subtle: #032830;--bs-warning-bg-subtle: #332701;--bs-danger-bg-subtle: #2c0b0e;--bs-light-bg-subtle: #343a40;--bs-dark-bg-subtle: #1a1d20;--bs-primary-border-subtle: #084298;--bs-secondary-border-subtle: #41464b;--bs-success-border-subtle: #0f5132;--bs-info-border-subtle: #087990;--bs-warning-border-subtle: #997404;--bs-danger-border-subtle: #842029;--bs-light-border-subtle: #495057;--bs-dark-border-subtle: #343a40;--bs-heading-color: inherit;--bs-link-color: #6ea8fe;--bs-link-hover-color: #8bb9fe;--bs-link-color-rgb: 110, 168, 254;--bs-link-hover-color-rgb: 139, 185, 254;--bs-code-color: white;--bs-border-color: #495057;--bs-border-color-translucent: rgba(255, 255, 255, 0.15);--bs-form-valid-color: #75b798;--bs-form-valid-border-color: #75b798;--bs-form-invalid-color: #ea868f;--bs-form-invalid-border-color: #ea868f}*,*::before,*::after{box-sizing:border-box}:root{font-size:var(--bs-root-font-size)}body{margin:0;font-family:var(--bs-body-font-family);font-size:var(--bs-body-font-size);font-weight:var(--bs-body-font-weight);line-height:var(--bs-body-line-height);color:var(--bs-body-color);text-align:var(--bs-body-text-align);background-color:var(--bs-body-bg);-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:rgba(0,0,0,0)}hr{margin:1rem 0;color:inherit;border:0;border-top:1px solid;opacity:.25}h6,.h6,h5,.h5,h4,.h4,h3,.h3,h2,.h2,h1,.h1{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2;color:var(--bs-heading-color)}h1,.h1{font-size:calc(1.325rem + 0.9vw)}@media(min-width: 1200px){h1,.h1{font-size:2rem}}h2,.h2{font-size:calc(1.29rem + 0.48vw)}@media(min-width: 1200px){h2,.h2{font-size:1.65rem}}h3,.h3{font-size:calc(1.27rem + 0.24vw)}@media(min-width: 1200px){h3,.h3{font-size:1.45rem}}h4,.h4{font-size:1.25rem}h5,.h5{font-size:1.1rem}h6,.h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[title]{text-decoration:underline dotted;-webkit-text-decoration:underline dotted;-moz-text-decoration:underline dotted;-ms-text-decoration:underline dotted;-o-text-decoration:underline dotted;cursor:help;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}ol,ul,dl{margin-top:0;margin-bottom:1rem}ol ol,ul ul,ol ul,ul ol{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem;padding:.625rem 1.25rem;border-left:.25rem solid #e9ecef}blockquote p:last-child,blockquote ul:last-child,blockquote ol:last-child{margin-bottom:0}b,strong{font-weight:bolder}small,.small{font-size:0.875em}mark,.mark{padding:.1875em;background-color:var(--bs-highlight-bg)}sub,sup{position:relative;font-size:0.75em;line-height:0;vertical-align:baseline}sub{bottom:-0.25em}sup{top:-0.5em}a{color:rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 1));text-decoration:underline;-webkit-text-decoration:underline;-moz-text-decoration:underline;-ms-text-decoration:underline;-o-text-decoration:underline}a:hover{--bs-link-color-rgb: var(--bs-link-hover-color-rgb)}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}pre,code,kbd,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:0.875em;color:#000;background-color:#f8f9fa;padding:.5rem;border:1px solid var(--bs-border-color, #dee2e6);border-radius:.375rem}pre code{background-color:rgba(0,0,0,0);font-size:inherit;color:inherit;word-break:normal}code{font-size:0.875em;color:var(--bs-code-color);background-color:#f8f9fa;border-radius:.375rem;padding:.125rem .25rem;word-wrap:break-word}a>code{color:inherit}kbd{padding:.4rem .4rem;font-size:0.875em;color:#fff;background-color:#212529;border-radius:.25rem}kbd kbd{padding:0;font-size:1em}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:rgba(33,37,41,.75);text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}thead,tbody,tfoot,tr,td,th{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}input,button,select,optgroup,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]:not([type=date]):not([type=datetime-local]):not([type=month]):not([type=week]):not([type=time])::-webkit-calendar-picker-indicator{display:none !important}button,[type=button],[type=reset],[type=submit]{-webkit-appearance:button}button:not(:disabled),[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:left;width:100%;padding:0;margin-bottom:.5rem;font-size:calc(1.275rem + 0.3vw);line-height:inherit}@media(min-width: 1200px){legend{font-size:1.5rem}}legend+*{clear:left}::-webkit-datetime-edit-fields-wrapper,::-webkit-datetime-edit-text,::-webkit-datetime-edit-minute,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-year-field{padding:0}::-webkit-inner-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::file-selector-button{font:inherit;-webkit-appearance:button}output{display:inline-block}iframe{border:0}summary{display:list-item;cursor:pointer}progress{vertical-align:baseline}[hidden]{display:none !important}.lead{font-size:1.25rem;font-weight:300}.display-1{font-size:calc(1.625rem + 4.5vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-1{font-size:5rem}}.display-2{font-size:calc(1.575rem + 3.9vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-2{font-size:4.5rem}}.display-3{font-size:calc(1.525rem + 3.3vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-3{font-size:4rem}}.display-4{font-size:calc(1.475rem + 2.7vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-4{font-size:3.5rem}}.display-5{font-size:calc(1.425rem + 2.1vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-5{font-size:3rem}}.display-6{font-size:calc(1.375rem + 1.5vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-6{font-size:2.5rem}}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:.5rem}.initialism{font-size:0.875em;text-transform:uppercase}.blockquote{margin-bottom:1rem;font-size:1.25rem}.blockquote>:last-child{margin-bottom:0}.blockquote-footer{margin-top:-1rem;margin-bottom:1rem;font-size:0.875em;color:#6c757d}.blockquote-footer::before{content:"— "}.img-fluid{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:#fff;border:1px solid #dee2e6;border-radius:.375rem;max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:0.875em;color:rgba(33,37,41,.75)}.container,.container-fluid,.container-xxl,.container-xl,.container-lg,.container-md,.container-sm{--bs-gutter-x: 1.5rem;--bs-gutter-y: 0;width:100%;padding-right:calc(var(--bs-gutter-x)*.5);padding-left:calc(var(--bs-gutter-x)*.5);margin-right:auto;margin-left:auto}@media(min-width: 576px){.container-sm,.container{max-width:540px}}@media(min-width: 768px){.container-md,.container-sm,.container{max-width:720px}}@media(min-width: 992px){.container-lg,.container-md,.container-sm,.container{max-width:960px}}@media(min-width: 1200px){.container-xl,.container-lg,.container-md,.container-sm,.container{max-width:1140px}}@media(min-width: 1400px){.container-xxl,.container-xl,.container-lg,.container-md,.container-sm,.container{max-width:1320px}}:root{--bs-breakpoint-xs: 0;--bs-breakpoint-sm: 576px;--bs-breakpoint-md: 768px;--bs-breakpoint-lg: 992px;--bs-breakpoint-xl: 1200px;--bs-breakpoint-xxl: 1400px}.grid{display:grid;grid-template-rows:repeat(var(--bs-rows, 1), 1fr);grid-template-columns:repeat(var(--bs-columns, 12), 1fr);gap:var(--bs-gap, 1.5rem)}.grid .g-col-1{grid-column:auto/span 1}.grid .g-col-2{grid-column:auto/span 2}.grid .g-col-3{grid-column:auto/span 3}.grid .g-col-4{grid-column:auto/span 4}.grid .g-col-5{grid-column:auto/span 5}.grid .g-col-6{grid-column:auto/span 6}.grid .g-col-7{grid-column:auto/span 7}.grid .g-col-8{grid-column:auto/span 8}.grid .g-col-9{grid-column:auto/span 9}.grid .g-col-10{grid-column:auto/span 10}.grid .g-col-11{grid-column:auto/span 11}.grid .g-col-12{grid-column:auto/span 12}.grid .g-start-1{grid-column-start:1}.grid .g-start-2{grid-column-start:2}.grid .g-start-3{grid-column-start:3}.grid .g-start-4{grid-column-start:4}.grid .g-start-5{grid-column-start:5}.grid .g-start-6{grid-column-start:6}.grid .g-start-7{grid-column-start:7}.grid .g-start-8{grid-column-start:8}.grid .g-start-9{grid-column-start:9}.grid .g-start-10{grid-column-start:10}.grid .g-start-11{grid-column-start:11}@media(min-width: 576px){.grid .g-col-sm-1{grid-column:auto/span 1}.grid .g-col-sm-2{grid-column:auto/span 2}.grid .g-col-sm-3{grid-column:auto/span 3}.grid .g-col-sm-4{grid-column:auto/span 4}.grid .g-col-sm-5{grid-column:auto/span 5}.grid .g-col-sm-6{grid-column:auto/span 6}.grid .g-col-sm-7{grid-column:auto/span 7}.grid .g-col-sm-8{grid-column:auto/span 8}.grid .g-col-sm-9{grid-column:auto/span 9}.grid .g-col-sm-10{grid-column:auto/span 10}.grid .g-col-sm-11{grid-column:auto/span 11}.grid .g-col-sm-12{grid-column:auto/span 12}.grid .g-start-sm-1{grid-column-start:1}.grid .g-start-sm-2{grid-column-start:2}.grid .g-start-sm-3{grid-column-start:3}.grid .g-start-sm-4{grid-column-start:4}.grid .g-start-sm-5{grid-column-start:5}.grid .g-start-sm-6{grid-column-start:6}.grid .g-start-sm-7{grid-column-start:7}.grid .g-start-sm-8{grid-column-start:8}.grid .g-start-sm-9{grid-column-start:9}.grid .g-start-sm-10{grid-column-start:10}.grid .g-start-sm-11{grid-column-start:11}}@media(min-width: 768px){.grid .g-col-md-1{grid-column:auto/span 1}.grid .g-col-md-2{grid-column:auto/span 2}.grid .g-col-md-3{grid-column:auto/span 3}.grid .g-col-md-4{grid-column:auto/span 4}.grid .g-col-md-5{grid-column:auto/span 5}.grid .g-col-md-6{grid-column:auto/span 6}.grid .g-col-md-7{grid-column:auto/span 7}.grid .g-col-md-8{grid-column:auto/span 8}.grid .g-col-md-9{grid-column:auto/span 9}.grid .g-col-md-10{grid-column:auto/span 10}.grid .g-col-md-11{grid-column:auto/span 11}.grid .g-col-md-12{grid-column:auto/span 12}.grid .g-start-md-1{grid-column-start:1}.grid .g-start-md-2{grid-column-start:2}.grid .g-start-md-3{grid-column-start:3}.grid .g-start-md-4{grid-column-start:4}.grid .g-start-md-5{grid-column-start:5}.grid .g-start-md-6{grid-column-start:6}.grid .g-start-md-7{grid-column-start:7}.grid .g-start-md-8{grid-column-start:8}.grid .g-start-md-9{grid-column-start:9}.grid .g-start-md-10{grid-column-start:10}.grid .g-start-md-11{grid-column-start:11}}@media(min-width: 992px){.grid .g-col-lg-1{grid-column:auto/span 1}.grid .g-col-lg-2{grid-column:auto/span 2}.grid .g-col-lg-3{grid-column:auto/span 3}.grid .g-col-lg-4{grid-column:auto/span 4}.grid .g-col-lg-5{grid-column:auto/span 5}.grid .g-col-lg-6{grid-column:auto/span 6}.grid .g-col-lg-7{grid-column:auto/span 7}.grid .g-col-lg-8{grid-column:auto/span 8}.grid .g-col-lg-9{grid-column:auto/span 9}.grid .g-col-lg-10{grid-column:auto/span 10}.grid .g-col-lg-11{grid-column:auto/span 11}.grid .g-col-lg-12{grid-column:auto/span 12}.grid .g-start-lg-1{grid-column-start:1}.grid .g-start-lg-2{grid-column-start:2}.grid .g-start-lg-3{grid-column-start:3}.grid .g-start-lg-4{grid-column-start:4}.grid .g-start-lg-5{grid-column-start:5}.grid .g-start-lg-6{grid-column-start:6}.grid .g-start-lg-7{grid-column-start:7}.grid .g-start-lg-8{grid-column-start:8}.grid .g-start-lg-9{grid-column-start:9}.grid .g-start-lg-10{grid-column-start:10}.grid .g-start-lg-11{grid-column-start:11}}@media(min-width: 1200px){.grid .g-col-xl-1{grid-column:auto/span 1}.grid .g-col-xl-2{grid-column:auto/span 2}.grid .g-col-xl-3{grid-column:auto/span 3}.grid .g-col-xl-4{grid-column:auto/span 4}.grid .g-col-xl-5{grid-column:auto/span 5}.grid .g-col-xl-6{grid-column:auto/span 6}.grid .g-col-xl-7{grid-column:auto/span 7}.grid .g-col-xl-8{grid-column:auto/span 8}.grid .g-col-xl-9{grid-column:auto/span 9}.grid .g-col-xl-10{grid-column:auto/span 10}.grid .g-col-xl-11{grid-column:auto/span 11}.grid .g-col-xl-12{grid-column:auto/span 12}.grid .g-start-xl-1{grid-column-start:1}.grid .g-start-xl-2{grid-column-start:2}.grid .g-start-xl-3{grid-column-start:3}.grid .g-start-xl-4{grid-column-start:4}.grid .g-start-xl-5{grid-column-start:5}.grid .g-start-xl-6{grid-column-start:6}.grid .g-start-xl-7{grid-column-start:7}.grid .g-start-xl-8{grid-column-start:8}.grid .g-start-xl-9{grid-column-start:9}.grid .g-start-xl-10{grid-column-start:10}.grid .g-start-xl-11{grid-column-start:11}}@media(min-width: 1400px){.grid .g-col-xxl-1{grid-column:auto/span 1}.grid .g-col-xxl-2{grid-column:auto/span 2}.grid .g-col-xxl-3{grid-column:auto/span 3}.grid .g-col-xxl-4{grid-column:auto/span 4}.grid .g-col-xxl-5{grid-column:auto/span 5}.grid .g-col-xxl-6{grid-column:auto/span 6}.grid .g-col-xxl-7{grid-column:auto/span 7}.grid .g-col-xxl-8{grid-column:auto/span 8}.grid .g-col-xxl-9{grid-column:auto/span 9}.grid .g-col-xxl-10{grid-column:auto/span 10}.grid .g-col-xxl-11{grid-column:auto/span 11}.grid .g-col-xxl-12{grid-column:auto/span 12}.grid .g-start-xxl-1{grid-column-start:1}.grid .g-start-xxl-2{grid-column-start:2}.grid .g-start-xxl-3{grid-column-start:3}.grid .g-start-xxl-4{grid-column-start:4}.grid .g-start-xxl-5{grid-column-start:5}.grid .g-start-xxl-6{grid-column-start:6}.grid .g-start-xxl-7{grid-column-start:7}.grid .g-start-xxl-8{grid-column-start:8}.grid .g-start-xxl-9{grid-column-start:9}.grid .g-start-xxl-10{grid-column-start:10}.grid .g-start-xxl-11{grid-column-start:11}}.table{--bs-table-color-type: initial;--bs-table-bg-type: initial;--bs-table-color-state: initial;--bs-table-bg-state: initial;--bs-table-color: #212529;--bs-table-bg: #ffffff;--bs-table-border-color: #dee2e6;--bs-table-accent-bg: transparent;--bs-table-striped-color: #212529;--bs-table-striped-bg: rgba(0, 0, 0, 0.05);--bs-table-active-color: #212529;--bs-table-active-bg: rgba(0, 0, 0, 0.1);--bs-table-hover-color: #212529;--bs-table-hover-bg: rgba(0, 0, 0, 0.075);width:100%;margin-bottom:1rem;vertical-align:top;border-color:var(--bs-table-border-color)}.table>:not(caption)>*>*{padding:.5rem .5rem;color:var(--bs-table-color-state, var(--bs-table-color-type, var(--bs-table-color)));background-color:var(--bs-table-bg);border-bottom-width:1px;box-shadow:inset 0 0 0 9999px var(--bs-table-bg-state, var(--bs-table-bg-type, var(--bs-table-accent-bg)))}.table>tbody{vertical-align:inherit}.table>thead{vertical-align:bottom}.table-group-divider{border-top:calc(1px*2) solid #9ba5ae}.caption-top{caption-side:top}.table-sm>:not(caption)>*>*{padding:.25rem .25rem}.table-bordered>:not(caption)>*{border-width:1px 0}.table-bordered>:not(caption)>*>*{border-width:0 1px}.table-borderless>:not(caption)>*>*{border-bottom-width:0}.table-borderless>:not(:first-child){border-top-width:0}.table-striped>tbody>tr:nth-of-type(odd)>*{--bs-table-color-type: var(--bs-table-striped-color);--bs-table-bg-type: var(--bs-table-striped-bg)}.table-striped-columns>:not(caption)>tr>:nth-child(even){--bs-table-color-type: var(--bs-table-striped-color);--bs-table-bg-type: var(--bs-table-striped-bg)}.table-active{--bs-table-color-state: var(--bs-table-active-color);--bs-table-bg-state: var(--bs-table-active-bg)}.table-hover>tbody>tr:hover>*{--bs-table-color-state: var(--bs-table-hover-color);--bs-table-bg-state: var(--bs-table-hover-bg)}.table-primary{--bs-table-color: #000;--bs-table-bg: #cfe2ff;--bs-table-border-color: #bacbe6;--bs-table-striped-bg: #c5d7f2;--bs-table-striped-color: #000;--bs-table-active-bg: #bacbe6;--bs-table-active-color: #000;--bs-table-hover-bg: #bfd1ec;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-secondary{--bs-table-color: #000;--bs-table-bg: #e2e3e5;--bs-table-border-color: #cbccce;--bs-table-striped-bg: #d7d8da;--bs-table-striped-color: #000;--bs-table-active-bg: #cbccce;--bs-table-active-color: #000;--bs-table-hover-bg: #d1d2d4;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-success{--bs-table-color: #000;--bs-table-bg: #d1e7dd;--bs-table-border-color: #bcd0c7;--bs-table-striped-bg: #c7dbd2;--bs-table-striped-color: #000;--bs-table-active-bg: #bcd0c7;--bs-table-active-color: #000;--bs-table-hover-bg: #c1d6cc;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-info{--bs-table-color: #000;--bs-table-bg: #cff4fc;--bs-table-border-color: #badce3;--bs-table-striped-bg: #c5e8ef;--bs-table-striped-color: #000;--bs-table-active-bg: #badce3;--bs-table-active-color: #000;--bs-table-hover-bg: #bfe2e9;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-warning{--bs-table-color: #000;--bs-table-bg: #fff3cd;--bs-table-border-color: #e6dbb9;--bs-table-striped-bg: #f2e7c3;--bs-table-striped-color: #000;--bs-table-active-bg: #e6dbb9;--bs-table-active-color: #000;--bs-table-hover-bg: #ece1be;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-danger{--bs-table-color: #000;--bs-table-bg: #f8d7da;--bs-table-border-color: #dfc2c4;--bs-table-striped-bg: #eccccf;--bs-table-striped-color: #000;--bs-table-active-bg: #dfc2c4;--bs-table-active-color: #000;--bs-table-hover-bg: #e5c7ca;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-light{--bs-table-color: #000;--bs-table-bg: #f8f9fa;--bs-table-border-color: #dfe0e1;--bs-table-striped-bg: #ecedee;--bs-table-striped-color: #000;--bs-table-active-bg: #dfe0e1;--bs-table-active-color: #000;--bs-table-hover-bg: #e5e6e7;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-dark{--bs-table-color: #ffffff;--bs-table-bg: #212529;--bs-table-border-color: #373b3e;--bs-table-striped-bg: #2c3034;--bs-table-striped-color: #ffffff;--bs-table-active-bg: #373b3e;--bs-table-active-color: #ffffff;--bs-table-hover-bg: #323539;--bs-table-hover-color: #ffffff;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-responsive{overflow-x:auto;-webkit-overflow-scrolling:touch}@media(max-width: 575.98px){.table-responsive-sm{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media(max-width: 767.98px){.table-responsive-md{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media(max-width: 991.98px){.table-responsive-lg{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media(max-width: 1199.98px){.table-responsive-xl{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media(max-width: 1399.98px){.table-responsive-xxl{overflow-x:auto;-webkit-overflow-scrolling:touch}}.form-label,.shiny-input-container .control-label{margin-bottom:.5rem}.col-form-label{padding-top:calc(0.375rem + 1px);padding-bottom:calc(0.375rem + 1px);margin-bottom:0;font-size:inherit;line-height:1.5}.col-form-label-lg{padding-top:calc(0.5rem + 1px);padding-bottom:calc(0.5rem + 1px);font-size:1.25rem}.col-form-label-sm{padding-top:calc(0.25rem + 1px);padding-bottom:calc(0.25rem + 1px);font-size:0.875rem}.form-text{margin-top:.25rem;font-size:0.875em;color:rgba(33,37,41,.75)}.form-control{display:block;width:100%;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#212529;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none;background-color:#fff;background-clip:padding-box;border:1px solid #dee2e6;border-radius:.375rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.form-control{transition:none}}.form-control[type=file]{overflow:hidden}.form-control[type=file]:not(:disabled):not([readonly]){cursor:pointer}.form-control:focus{color:#212529;background-color:#fff;border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-control::-webkit-date-and-time-value{min-width:85px;height:1.5em;margin:0}.form-control::-webkit-datetime-edit{display:block;padding:0}.form-control::placeholder{color:rgba(33,37,41,.75);opacity:1}.form-control:disabled{background-color:#e9ecef;opacity:1}.form-control::file-selector-button{padding:.375rem .75rem;margin:-0.375rem -0.75rem;margin-inline-end:.75rem;color:#212529;background-color:#f8f9fa;pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:1px;border-radius:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.form-control::file-selector-button{transition:none}}.form-control:hover:not(:disabled):not([readonly])::file-selector-button{background-color:#e9ecef}.form-control-plaintext{display:block;width:100%;padding:.375rem 0;margin-bottom:0;line-height:1.5;color:#212529;background-color:rgba(0,0,0,0);border:solid rgba(0,0,0,0);border-width:1px 0}.form-control-plaintext:focus{outline:0}.form-control-plaintext.form-control-sm,.form-control-plaintext.form-control-lg{padding-right:0;padding-left:0}.form-control-sm{min-height:calc(1.5em + 0.5rem + calc(1px * 2));padding:.25rem .5rem;font-size:0.875rem;border-radius:.25rem}.form-control-sm::file-selector-button{padding:.25rem .5rem;margin:-0.25rem -0.5rem;margin-inline-end:.5rem}.form-control-lg{min-height:calc(1.5em + 1rem + calc(1px * 2));padding:.5rem 1rem;font-size:1.25rem;border-radius:.5rem}.form-control-lg::file-selector-button{padding:.5rem 1rem;margin:-0.5rem -1rem;margin-inline-end:1rem}textarea.form-control{min-height:calc(1.5em + 0.75rem + calc(1px * 2))}textarea.form-control-sm{min-height:calc(1.5em + 0.5rem + calc(1px * 2))}textarea.form-control-lg{min-height:calc(1.5em + 1rem + calc(1px * 2))}.form-control-color{width:3rem;height:calc(1.5em + 0.75rem + calc(1px * 2));padding:.375rem}.form-control-color:not(:disabled):not([readonly]){cursor:pointer}.form-control-color::-moz-color-swatch{border:0 !important;border-radius:.375rem}.form-control-color::-webkit-color-swatch{border:0 !important;border-radius:.375rem}.form-control-color.form-control-sm{height:calc(1.5em + 0.5rem + calc(1px * 2))}.form-control-color.form-control-lg{height:calc(1.5em + 1rem + calc(1px * 2))}.form-select{--bs-form-select-bg-img: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e");display:block;width:100%;padding:.375rem 2.25rem .375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#212529;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none;background-color:#fff;background-image:var(--bs-form-select-bg-img),var(--bs-form-select-bg-icon, none);background-repeat:no-repeat;background-position:right .75rem center;background-size:16px 12px;border:1px solid #dee2e6;border-radius:.375rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.form-select{transition:none}}.form-select:focus{border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-select[multiple],.form-select[size]:not([size="1"]){padding-right:.75rem;background-image:none}.form-select:disabled{background-color:#e9ecef}.form-select:-moz-focusring{color:rgba(0,0,0,0);text-shadow:0 0 0 #212529}.form-select-sm{padding-top:.25rem;padding-bottom:.25rem;padding-left:.5rem;font-size:0.875rem;border-radius:.25rem}.form-select-lg{padding-top:.5rem;padding-bottom:.5rem;padding-left:1rem;font-size:1.25rem;border-radius:.5rem}[data-bs-theme=dark] .form-select{--bs-form-select-bg-img: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23dee2e6' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e")}.form-check,.shiny-input-container .checkbox,.shiny-input-container .radio{display:block;min-height:1.5rem;padding-left:0;margin-bottom:.125rem}.form-check .form-check-input,.form-check .shiny-input-container .checkbox input,.form-check .shiny-input-container .radio input,.shiny-input-container .checkbox .form-check-input,.shiny-input-container .checkbox .shiny-input-container .checkbox input,.shiny-input-container .checkbox .shiny-input-container .radio input,.shiny-input-container .radio .form-check-input,.shiny-input-container .radio .shiny-input-container .checkbox input,.shiny-input-container .radio .shiny-input-container .radio input{float:left;margin-left:0}.form-check-reverse{padding-right:0;padding-left:0;text-align:right}.form-check-reverse .form-check-input{float:right;margin-right:0;margin-left:0}.form-check-input,.shiny-input-container .checkbox input,.shiny-input-container .checkbox-inline input,.shiny-input-container .radio input,.shiny-input-container .radio-inline input{--bs-form-check-bg: #ffffff;width:1em;height:1em;margin-top:.25em;vertical-align:top;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none;background-color:var(--bs-form-check-bg);background-image:var(--bs-form-check-bg-image);background-repeat:no-repeat;background-position:center;background-size:contain;border:1px solid #dee2e6;print-color-adjust:exact}.form-check-input[type=checkbox],.shiny-input-container .checkbox input[type=checkbox],.shiny-input-container .checkbox-inline input[type=checkbox],.shiny-input-container .radio input[type=checkbox],.shiny-input-container .radio-inline input[type=checkbox]{border-radius:.25em}.form-check-input[type=radio],.shiny-input-container .checkbox input[type=radio],.shiny-input-container .checkbox-inline input[type=radio],.shiny-input-container .radio input[type=radio],.shiny-input-container .radio-inline input[type=radio]{border-radius:50%}.form-check-input:active,.shiny-input-container .checkbox input:active,.shiny-input-container .checkbox-inline input:active,.shiny-input-container .radio input:active,.shiny-input-container .radio-inline input:active{filter:brightness(90%)}.form-check-input:focus,.shiny-input-container .checkbox input:focus,.shiny-input-container .checkbox-inline input:focus,.shiny-input-container .radio input:focus,.shiny-input-container .radio-inline input:focus{border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-check-input:checked,.shiny-input-container .checkbox input:checked,.shiny-input-container .checkbox-inline input:checked,.shiny-input-container .radio input:checked,.shiny-input-container .radio-inline input:checked{background-color:#0d6efd;border-color:#0d6efd}.form-check-input:checked[type=checkbox],.shiny-input-container .checkbox input:checked[type=checkbox],.shiny-input-container .checkbox-inline input:checked[type=checkbox],.shiny-input-container .radio input:checked[type=checkbox],.shiny-input-container .radio-inline input:checked[type=checkbox]{--bs-form-check-bg-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23ffffff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='m6 10 3 3 6-6'/%3e%3c/svg%3e")}.form-check-input:checked[type=radio],.shiny-input-container .checkbox input:checked[type=radio],.shiny-input-container .checkbox-inline input:checked[type=radio],.shiny-input-container .radio input:checked[type=radio],.shiny-input-container .radio-inline input:checked[type=radio]{--bs-form-check-bg-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='2' fill='%23ffffff'/%3e%3c/svg%3e")}.form-check-input[type=checkbox]:indeterminate,.shiny-input-container .checkbox input[type=checkbox]:indeterminate,.shiny-input-container .checkbox-inline input[type=checkbox]:indeterminate,.shiny-input-container .radio input[type=checkbox]:indeterminate,.shiny-input-container .radio-inline input[type=checkbox]:indeterminate{background-color:#0d6efd;border-color:#0d6efd;--bs-form-check-bg-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23ffffff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10h8'/%3e%3c/svg%3e")}.form-check-input:disabled,.shiny-input-container .checkbox input:disabled,.shiny-input-container .checkbox-inline input:disabled,.shiny-input-container .radio input:disabled,.shiny-input-container .radio-inline input:disabled{pointer-events:none;filter:none;opacity:.5}.form-check-input[disabled]~.form-check-label,.form-check-input[disabled]~span,.form-check-input:disabled~.form-check-label,.form-check-input:disabled~span,.shiny-input-container .checkbox input[disabled]~.form-check-label,.shiny-input-container .checkbox input[disabled]~span,.shiny-input-container .checkbox input:disabled~.form-check-label,.shiny-input-container .checkbox input:disabled~span,.shiny-input-container .checkbox-inline input[disabled]~.form-check-label,.shiny-input-container .checkbox-inline input[disabled]~span,.shiny-input-container .checkbox-inline input:disabled~.form-check-label,.shiny-input-container .checkbox-inline input:disabled~span,.shiny-input-container .radio input[disabled]~.form-check-label,.shiny-input-container .radio input[disabled]~span,.shiny-input-container .radio input:disabled~.form-check-label,.shiny-input-container .radio input:disabled~span,.shiny-input-container .radio-inline input[disabled]~.form-check-label,.shiny-input-container .radio-inline input[disabled]~span,.shiny-input-container .radio-inline input:disabled~.form-check-label,.shiny-input-container .radio-inline input:disabled~span{cursor:default;opacity:.5}.form-check-label,.shiny-input-container .checkbox label,.shiny-input-container .checkbox-inline label,.shiny-input-container .radio label,.shiny-input-container .radio-inline label{cursor:pointer}.form-switch{padding-left:2.5em}.form-switch .form-check-input{--bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%280, 0, 0, 0.25%29'/%3e%3c/svg%3e");width:2em;margin-left:-2.5em;background-image:var(--bs-form-switch-bg);background-position:left center;border-radius:2em;transition:background-position .15s ease-in-out}@media(prefers-reduced-motion: reduce){.form-switch .form-check-input{transition:none}}.form-switch .form-check-input:focus{--bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%2386b7fe'/%3e%3c/svg%3e")}.form-switch .form-check-input:checked{background-position:right center;--bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23ffffff'/%3e%3c/svg%3e")}.form-switch.form-check-reverse{padding-right:2.5em;padding-left:0}.form-switch.form-check-reverse .form-check-input{margin-right:-2.5em;margin-left:0}.form-check-inline{display:inline-block;margin-right:1rem}.btn-check{position:absolute;clip:rect(0, 0, 0, 0);pointer-events:none}.btn-check[disabled]+.btn,.btn-check:disabled+.btn{pointer-events:none;filter:none;opacity:.65}[data-bs-theme=dark] .form-switch .form-check-input:not(:checked):not(:focus){--bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%28255, 255, 255, 0.25%29'/%3e%3c/svg%3e")}.form-range{width:100%;height:1.5rem;padding:0;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none;background-color:rgba(0,0,0,0)}.form-range:focus{outline:0}.form-range:focus::-webkit-slider-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(13,110,253,.25)}.form-range:focus::-moz-range-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(13,110,253,.25)}.form-range::-moz-focus-outer{border:0}.form-range::-webkit-slider-thumb{width:1rem;height:1rem;margin-top:-0.25rem;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none;background-color:#0d6efd;border:0;border-radius:1rem;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.form-range::-webkit-slider-thumb{transition:none}}.form-range::-webkit-slider-thumb:active{background-color:#b6d4fe}.form-range::-webkit-slider-runnable-track{width:100%;height:.5rem;color:rgba(0,0,0,0);cursor:pointer;background-color:#f8f9fa;border-color:rgba(0,0,0,0);border-radius:1rem}.form-range::-moz-range-thumb{width:1rem;height:1rem;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none;background-color:#0d6efd;border:0;border-radius:1rem;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.form-range::-moz-range-thumb{transition:none}}.form-range::-moz-range-thumb:active{background-color:#b6d4fe}.form-range::-moz-range-track{width:100%;height:.5rem;color:rgba(0,0,0,0);cursor:pointer;background-color:#f8f9fa;border-color:rgba(0,0,0,0);border-radius:1rem}.form-range:disabled{pointer-events:none}.form-range:disabled::-webkit-slider-thumb{background-color:rgba(33,37,41,.75)}.form-range:disabled::-moz-range-thumb{background-color:rgba(33,37,41,.75)}.form-floating{position:relative}.form-floating>.form-control,.form-floating>.form-control-plaintext,.form-floating>.form-select{height:calc(3.5rem + calc(1px * 2));min-height:calc(3.5rem + calc(1px * 2));line-height:1.25}.form-floating>label{position:absolute;top:0;left:0;z-index:2;height:100%;padding:1rem .75rem;overflow:hidden;text-align:start;text-overflow:ellipsis;white-space:nowrap;pointer-events:none;border:1px solid rgba(0,0,0,0);transform-origin:0 0;transition:opacity .1s ease-in-out,transform .1s ease-in-out}@media(prefers-reduced-motion: reduce){.form-floating>label{transition:none}}.form-floating>.form-control,.form-floating>.form-control-plaintext{padding:1rem .75rem}.form-floating>.form-control::placeholder,.form-floating>.form-control-plaintext::placeholder{color:rgba(0,0,0,0)}.form-floating>.form-control:focus,.form-floating>.form-control:not(:placeholder-shown),.form-floating>.form-control-plaintext:focus,.form-floating>.form-control-plaintext:not(:placeholder-shown){padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:-webkit-autofill,.form-floating>.form-control-plaintext:-webkit-autofill{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-select{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:focus~label,.form-floating>.form-control:not(:placeholder-shown)~label,.form-floating>.form-control-plaintext~label,.form-floating>.form-select~label{color:rgba(var(--bs-body-color-rgb), 0.65);transform:scale(0.85) translateY(-0.5rem) translateX(0.15rem)}.form-floating>.form-control:focus~label::after,.form-floating>.form-control:not(:placeholder-shown)~label::after,.form-floating>.form-control-plaintext~label::after,.form-floating>.form-select~label::after{position:absolute;inset:1rem .375rem;z-index:-1;height:1.5em;content:"";background-color:#fff;border-radius:.375rem}.form-floating>.form-control:-webkit-autofill~label{color:rgba(var(--bs-body-color-rgb), 0.65);transform:scale(0.85) translateY(-0.5rem) translateX(0.15rem)}.form-floating>.form-control-plaintext~label{border-width:1px 0}.form-floating>:disabled~label,.form-floating>.form-control:disabled~label{color:#6c757d}.form-floating>:disabled~label::after,.form-floating>.form-control:disabled~label::after{background-color:#e9ecef}.input-group{position:relative;display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;align-items:stretch;-webkit-align-items:stretch;width:100%}.input-group>.form-control,.input-group>.form-select,.input-group>.form-floating{position:relative;flex:1 1 auto;-webkit-flex:1 1 auto;width:1%;min-width:0}.input-group>.form-control:focus,.input-group>.form-select:focus,.input-group>.form-floating:focus-within{z-index:5}.input-group .btn{position:relative;z-index:2}.input-group .btn:focus{z-index:5}.input-group-text{display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:center;white-space:nowrap;background-color:#f8f9fa;border:1px solid #dee2e6;border-radius:.375rem}.input-group-lg>.form-control,.input-group-lg>.form-select,.input-group-lg>.input-group-text,.input-group-lg>.btn{padding:.5rem 1rem;font-size:1.25rem;border-radius:.5rem}.input-group-sm>.form-control,.input-group-sm>.form-select,.input-group-sm>.input-group-text,.input-group-sm>.btn{padding:.25rem .5rem;font-size:0.875rem;border-radius:.25rem}.input-group-lg>.form-select,.input-group-sm>.form-select{padding-right:3rem}.input-group:not(.has-validation)>:not(:last-child):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating),.input-group:not(.has-validation)>.dropdown-toggle:nth-last-child(n+3),.input-group:not(.has-validation)>.form-floating:not(:last-child)>.form-control,.input-group:not(.has-validation)>.form-floating:not(:last-child)>.form-select{border-top-right-radius:0;border-bottom-right-radius:0}.input-group.has-validation>:nth-last-child(n+3):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating),.input-group.has-validation>.dropdown-toggle:nth-last-child(n+4),.input-group.has-validation>.form-floating:nth-last-child(n+3)>.form-control,.input-group.has-validation>.form-floating:nth-last-child(n+3)>.form-select{border-top-right-radius:0;border-bottom-right-radius:0}.input-group>:not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback){margin-left:calc(1px*-1);border-top-left-radius:0;border-bottom-left-radius:0}.input-group>.form-floating:not(:first-child)>.form-control,.input-group>.form-floating:not(:first-child)>.form-select{border-top-left-radius:0;border-bottom-left-radius:0}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:0.875em;color:#198754}.valid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:0.875rem;color:#fff;background-color:#198754;border-radius:.375rem}.was-validated :valid~.valid-feedback,.was-validated :valid~.valid-tooltip,.is-valid~.valid-feedback,.is-valid~.valid-tooltip{display:block}.was-validated .form-control:valid,.form-control.is-valid{border-color:#198754;padding-right:calc(1.5em + 0.75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(0.375em + 0.1875rem) center;background-size:calc(0.75em + 0.375rem) calc(0.75em + 0.375rem)}.was-validated .form-control:valid:focus,.form-control.is-valid:focus{border-color:#198754;box-shadow:0 0 0 .25rem rgba(25,135,84,.25)}.was-validated textarea.form-control:valid,textarea.form-control.is-valid{padding-right:calc(1.5em + 0.75rem);background-position:top calc(0.375em + 0.1875rem) right calc(0.375em + 0.1875rem)}.was-validated .form-select:valid,.form-select.is-valid{border-color:#198754}.was-validated .form-select:valid:not([multiple]):not([size]),.was-validated .form-select:valid:not([multiple])[size="1"],.form-select.is-valid:not([multiple]):not([size]),.form-select.is-valid:not([multiple])[size="1"]{--bs-form-select-bg-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");padding-right:4.125rem;background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(0.75em + 0.375rem) calc(0.75em + 0.375rem)}.was-validated .form-select:valid:focus,.form-select.is-valid:focus{border-color:#198754;box-shadow:0 0 0 .25rem rgba(25,135,84,.25)}.was-validated .form-control-color:valid,.form-control-color.is-valid{width:calc(3rem + calc(1.5em + 0.75rem))}.was-validated .form-check-input:valid,.form-check-input.is-valid{border-color:#198754}.was-validated .form-check-input:valid:checked,.form-check-input.is-valid:checked{background-color:#198754}.was-validated .form-check-input:valid:focus,.form-check-input.is-valid:focus{box-shadow:0 0 0 .25rem rgba(25,135,84,.25)}.was-validated .form-check-input:valid~.form-check-label,.form-check-input.is-valid~.form-check-label{color:#198754}.form-check-inline .form-check-input~.valid-feedback{margin-left:.5em}.was-validated .input-group>.form-control:not(:focus):valid,.input-group>.form-control:not(:focus).is-valid,.was-validated .input-group>.form-select:not(:focus):valid,.input-group>.form-select:not(:focus).is-valid,.was-validated .input-group>.form-floating:not(:focus-within):valid,.input-group>.form-floating:not(:focus-within).is-valid{z-index:3}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:0.875em;color:#dc3545}.invalid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:0.875rem;color:#fff;background-color:#dc3545;border-radius:.375rem}.was-validated :invalid~.invalid-feedback,.was-validated :invalid~.invalid-tooltip,.is-invalid~.invalid-feedback,.is-invalid~.invalid-tooltip{display:block}.was-validated .form-control:invalid,.form-control.is-invalid{border-color:#dc3545;padding-right:calc(1.5em + 0.75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(0.375em + 0.1875rem) center;background-size:calc(0.75em + 0.375rem) calc(0.75em + 0.375rem)}.was-validated .form-control:invalid:focus,.form-control.is-invalid:focus{border-color:#dc3545;box-shadow:0 0 0 .25rem rgba(220,53,69,.25)}.was-validated textarea.form-control:invalid,textarea.form-control.is-invalid{padding-right:calc(1.5em + 0.75rem);background-position:top calc(0.375em + 0.1875rem) right calc(0.375em + 0.1875rem)}.was-validated .form-select:invalid,.form-select.is-invalid{border-color:#dc3545}.was-validated .form-select:invalid:not([multiple]):not([size]),.was-validated .form-select:invalid:not([multiple])[size="1"],.form-select.is-invalid:not([multiple]):not([size]),.form-select.is-invalid:not([multiple])[size="1"]{--bs-form-select-bg-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");padding-right:4.125rem;background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(0.75em + 0.375rem) calc(0.75em + 0.375rem)}.was-validated .form-select:invalid:focus,.form-select.is-invalid:focus{border-color:#dc3545;box-shadow:0 0 0 .25rem rgba(220,53,69,.25)}.was-validated .form-control-color:invalid,.form-control-color.is-invalid{width:calc(3rem + calc(1.5em + 0.75rem))}.was-validated .form-check-input:invalid,.form-check-input.is-invalid{border-color:#dc3545}.was-validated .form-check-input:invalid:checked,.form-check-input.is-invalid:checked{background-color:#dc3545}.was-validated .form-check-input:invalid:focus,.form-check-input.is-invalid:focus{box-shadow:0 0 0 .25rem rgba(220,53,69,.25)}.was-validated .form-check-input:invalid~.form-check-label,.form-check-input.is-invalid~.form-check-label{color:#dc3545}.form-check-inline .form-check-input~.invalid-feedback{margin-left:.5em}.was-validated .input-group>.form-control:not(:focus):invalid,.input-group>.form-control:not(:focus).is-invalid,.was-validated .input-group>.form-select:not(:focus):invalid,.input-group>.form-select:not(:focus).is-invalid,.was-validated .input-group>.form-floating:not(:focus-within):invalid,.input-group>.form-floating:not(:focus-within).is-invalid{z-index:4}.btn{--bs-btn-padding-x: 0.75rem;--bs-btn-padding-y: 0.375rem;--bs-btn-font-family: ;--bs-btn-font-size:1rem;--bs-btn-font-weight: 400;--bs-btn-line-height: 1.5;--bs-btn-color: #212529;--bs-btn-bg: transparent;--bs-btn-border-width: 1px;--bs-btn-border-color: transparent;--bs-btn-border-radius: 0.375rem;--bs-btn-hover-border-color: transparent;--bs-btn-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075);--bs-btn-disabled-opacity: 0.65;--bs-btn-focus-box-shadow: 0 0 0 0.25rem rgba(var(--bs-btn-focus-shadow-rgb), .5);display:inline-block;padding:var(--bs-btn-padding-y) var(--bs-btn-padding-x);font-family:var(--bs-btn-font-family);font-size:var(--bs-btn-font-size);font-weight:var(--bs-btn-font-weight);line-height:var(--bs-btn-line-height);color:var(--bs-btn-color);text-align:center;text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;vertical-align:middle;cursor:pointer;user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;border:var(--bs-btn-border-width) solid var(--bs-btn-border-color);border-radius:var(--bs-btn-border-radius);background-color:var(--bs-btn-bg);transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.btn{transition:none}}.btn:hover{color:var(--bs-btn-hover-color);background-color:var(--bs-btn-hover-bg);border-color:var(--bs-btn-hover-border-color)}.btn-check+.btn:hover{color:var(--bs-btn-color);background-color:var(--bs-btn-bg);border-color:var(--bs-btn-border-color)}.btn:focus-visible{color:var(--bs-btn-hover-color);background-color:var(--bs-btn-hover-bg);border-color:var(--bs-btn-hover-border-color);outline:0;box-shadow:var(--bs-btn-focus-box-shadow)}.btn-check:focus-visible+.btn{border-color:var(--bs-btn-hover-border-color);outline:0;box-shadow:var(--bs-btn-focus-box-shadow)}.btn-check:checked+.btn,:not(.btn-check)+.btn:active,.btn:first-child:active,.btn.active,.btn.show{color:var(--bs-btn-active-color);background-color:var(--bs-btn-active-bg);border-color:var(--bs-btn-active-border-color)}.btn-check:checked+.btn:focus-visible,:not(.btn-check)+.btn:active:focus-visible,.btn:first-child:active:focus-visible,.btn.active:focus-visible,.btn.show:focus-visible{box-shadow:var(--bs-btn-focus-box-shadow)}.btn:disabled,.btn.disabled,fieldset:disabled .btn{color:var(--bs-btn-disabled-color);pointer-events:none;background-color:var(--bs-btn-disabled-bg);border-color:var(--bs-btn-disabled-border-color);opacity:var(--bs-btn-disabled-opacity)}.btn-default{--bs-btn-color: #000;--bs-btn-bg: #dee2e6;--bs-btn-border-color: #dee2e6;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #e3e6ea;--bs-btn-hover-border-color: #e1e5e9;--bs-btn-focus-shadow-rgb: 189, 192, 196;--bs-btn-active-color: #000;--bs-btn-active-bg: #e5e8eb;--bs-btn-active-border-color: #e1e5e9;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #000;--bs-btn-disabled-bg: #dee2e6;--bs-btn-disabled-border-color: #dee2e6}.btn-primary{--bs-btn-color: #ffffff;--bs-btn-bg: #0d6efd;--bs-btn-border-color: #0d6efd;--bs-btn-hover-color: #ffffff;--bs-btn-hover-bg: #0b5ed7;--bs-btn-hover-border-color: #0a58ca;--bs-btn-focus-shadow-rgb: 49, 132, 253;--bs-btn-active-color: #ffffff;--bs-btn-active-bg: #0a58ca;--bs-btn-active-border-color: #0a53be;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #ffffff;--bs-btn-disabled-bg: #0d6efd;--bs-btn-disabled-border-color: #0d6efd}.btn-secondary{--bs-btn-color: #ffffff;--bs-btn-bg: #6c757d;--bs-btn-border-color: #6c757d;--bs-btn-hover-color: #ffffff;--bs-btn-hover-bg: #5c636a;--bs-btn-hover-border-color: #565e64;--bs-btn-focus-shadow-rgb: 130, 138, 145;--bs-btn-active-color: #ffffff;--bs-btn-active-bg: #565e64;--bs-btn-active-border-color: #51585e;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #ffffff;--bs-btn-disabled-bg: #6c757d;--bs-btn-disabled-border-color: #6c757d}.btn-success{--bs-btn-color: #ffffff;--bs-btn-bg: #198754;--bs-btn-border-color: #198754;--bs-btn-hover-color: #ffffff;--bs-btn-hover-bg: #157347;--bs-btn-hover-border-color: #146c43;--bs-btn-focus-shadow-rgb: 60, 153, 110;--bs-btn-active-color: #ffffff;--bs-btn-active-bg: #146c43;--bs-btn-active-border-color: #13653f;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #ffffff;--bs-btn-disabled-bg: #198754;--bs-btn-disabled-border-color: #198754}.btn-info{--bs-btn-color: #000;--bs-btn-bg: #0dcaf0;--bs-btn-border-color: #0dcaf0;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #31d2f2;--bs-btn-hover-border-color: #25cff2;--bs-btn-focus-shadow-rgb: 11, 172, 204;--bs-btn-active-color: #000;--bs-btn-active-bg: #3dd5f3;--bs-btn-active-border-color: #25cff2;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #000;--bs-btn-disabled-bg: #0dcaf0;--bs-btn-disabled-border-color: #0dcaf0}.btn-warning{--bs-btn-color: #000;--bs-btn-bg: #ffc107;--bs-btn-border-color: #ffc107;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #ffca2c;--bs-btn-hover-border-color: #ffc720;--bs-btn-focus-shadow-rgb: 217, 164, 6;--bs-btn-active-color: #000;--bs-btn-active-bg: #ffcd39;--bs-btn-active-border-color: #ffc720;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #000;--bs-btn-disabled-bg: #ffc107;--bs-btn-disabled-border-color: #ffc107}.btn-danger{--bs-btn-color: #ffffff;--bs-btn-bg: #dc3545;--bs-btn-border-color: #dc3545;--bs-btn-hover-color: #ffffff;--bs-btn-hover-bg: #bb2d3b;--bs-btn-hover-border-color: #b02a37;--bs-btn-focus-shadow-rgb: 225, 83, 97;--bs-btn-active-color: #ffffff;--bs-btn-active-bg: #b02a37;--bs-btn-active-border-color: #a52834;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #ffffff;--bs-btn-disabled-bg: #dc3545;--bs-btn-disabled-border-color: #dc3545}.btn-light{--bs-btn-color: #000;--bs-btn-bg: #f8f9fa;--bs-btn-border-color: #f8f9fa;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #d3d4d5;--bs-btn-hover-border-color: #c6c7c8;--bs-btn-focus-shadow-rgb: 211, 212, 213;--bs-btn-active-color: #000;--bs-btn-active-bg: #c6c7c8;--bs-btn-active-border-color: #babbbc;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #000;--bs-btn-disabled-bg: #f8f9fa;--bs-btn-disabled-border-color: #f8f9fa}.btn-dark{--bs-btn-color: #ffffff;--bs-btn-bg: #212529;--bs-btn-border-color: #212529;--bs-btn-hover-color: #ffffff;--bs-btn-hover-bg: #424649;--bs-btn-hover-border-color: #373b3e;--bs-btn-focus-shadow-rgb: 66, 70, 73;--bs-btn-active-color: #ffffff;--bs-btn-active-bg: #4d5154;--bs-btn-active-border-color: #373b3e;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #ffffff;--bs-btn-disabled-bg: #212529;--bs-btn-disabled-border-color: #212529}.btn-outline-default{--bs-btn-color: #dee2e6;--bs-btn-border-color: #dee2e6;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #dee2e6;--bs-btn-hover-border-color: #dee2e6;--bs-btn-focus-shadow-rgb: 222, 226, 230;--bs-btn-active-color: #000;--bs-btn-active-bg: #dee2e6;--bs-btn-active-border-color: #dee2e6;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #dee2e6;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #dee2e6;--bs-btn-bg: transparent;--bs-gradient: none}.btn-outline-primary{--bs-btn-color: #0d6efd;--bs-btn-border-color: #0d6efd;--bs-btn-hover-color: #ffffff;--bs-btn-hover-bg: #0d6efd;--bs-btn-hover-border-color: #0d6efd;--bs-btn-focus-shadow-rgb: 13, 110, 253;--bs-btn-active-color: #ffffff;--bs-btn-active-bg: #0d6efd;--bs-btn-active-border-color: #0d6efd;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #0d6efd;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #0d6efd;--bs-btn-bg: transparent;--bs-gradient: none}.btn-outline-secondary{--bs-btn-color: #6c757d;--bs-btn-border-color: #6c757d;--bs-btn-hover-color: #ffffff;--bs-btn-hover-bg: #6c757d;--bs-btn-hover-border-color: #6c757d;--bs-btn-focus-shadow-rgb: 108, 117, 125;--bs-btn-active-color: #ffffff;--bs-btn-active-bg: #6c757d;--bs-btn-active-border-color: #6c757d;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #6c757d;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #6c757d;--bs-btn-bg: transparent;--bs-gradient: none}.btn-outline-success{--bs-btn-color: #198754;--bs-btn-border-color: #198754;--bs-btn-hover-color: #ffffff;--bs-btn-hover-bg: #198754;--bs-btn-hover-border-color: #198754;--bs-btn-focus-shadow-rgb: 25, 135, 84;--bs-btn-active-color: #ffffff;--bs-btn-active-bg: #198754;--bs-btn-active-border-color: #198754;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #198754;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #198754;--bs-btn-bg: transparent;--bs-gradient: none}.btn-outline-info{--bs-btn-color: #0dcaf0;--bs-btn-border-color: #0dcaf0;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #0dcaf0;--bs-btn-hover-border-color: #0dcaf0;--bs-btn-focus-shadow-rgb: 13, 202, 240;--bs-btn-active-color: #000;--bs-btn-active-bg: #0dcaf0;--bs-btn-active-border-color: #0dcaf0;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #0dcaf0;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #0dcaf0;--bs-btn-bg: transparent;--bs-gradient: none}.btn-outline-warning{--bs-btn-color: #ffc107;--bs-btn-border-color: #ffc107;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #ffc107;--bs-btn-hover-border-color: #ffc107;--bs-btn-focus-shadow-rgb: 255, 193, 7;--bs-btn-active-color: #000;--bs-btn-active-bg: #ffc107;--bs-btn-active-border-color: #ffc107;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #ffc107;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #ffc107;--bs-btn-bg: transparent;--bs-gradient: none}.btn-outline-danger{--bs-btn-color: #dc3545;--bs-btn-border-color: #dc3545;--bs-btn-hover-color: #ffffff;--bs-btn-hover-bg: #dc3545;--bs-btn-hover-border-color: #dc3545;--bs-btn-focus-shadow-rgb: 220, 53, 69;--bs-btn-active-color: #ffffff;--bs-btn-active-bg: #dc3545;--bs-btn-active-border-color: #dc3545;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #dc3545;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #dc3545;--bs-btn-bg: transparent;--bs-gradient: none}.btn-outline-light{--bs-btn-color: #f8f9fa;--bs-btn-border-color: #f8f9fa;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #f8f9fa;--bs-btn-hover-border-color: #f8f9fa;--bs-btn-focus-shadow-rgb: 248, 249, 250;--bs-btn-active-color: #000;--bs-btn-active-bg: #f8f9fa;--bs-btn-active-border-color: #f8f9fa;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #f8f9fa;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #f8f9fa;--bs-btn-bg: transparent;--bs-gradient: none}.btn-outline-dark{--bs-btn-color: #212529;--bs-btn-border-color: #212529;--bs-btn-hover-color: #ffffff;--bs-btn-hover-bg: #212529;--bs-btn-hover-border-color: #212529;--bs-btn-focus-shadow-rgb: 33, 37, 41;--bs-btn-active-color: #ffffff;--bs-btn-active-bg: #212529;--bs-btn-active-border-color: #212529;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #212529;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #212529;--bs-btn-bg: transparent;--bs-gradient: none}.btn-link{--bs-btn-font-weight: 400;--bs-btn-color: #0d6efd;--bs-btn-bg: transparent;--bs-btn-border-color: transparent;--bs-btn-hover-color: #0a58ca;--bs-btn-hover-border-color: transparent;--bs-btn-active-color: #0a58ca;--bs-btn-active-border-color: transparent;--bs-btn-disabled-color: #6c757d;--bs-btn-disabled-border-color: transparent;--bs-btn-box-shadow: 0 0 0 #000;--bs-btn-focus-shadow-rgb: 49, 132, 253;text-decoration:underline;-webkit-text-decoration:underline;-moz-text-decoration:underline;-ms-text-decoration:underline;-o-text-decoration:underline}.btn-link:focus-visible{color:var(--bs-btn-color)}.btn-link:hover{color:var(--bs-btn-hover-color)}.btn-lg,.btn-group-lg>.btn{--bs-btn-padding-y: 0.5rem;--bs-btn-padding-x: 1rem;--bs-btn-font-size:1.25rem;--bs-btn-border-radius: 0.5rem}.btn-sm,.btn-group-sm>.btn{--bs-btn-padding-y: 0.25rem;--bs-btn-padding-x: 0.5rem;--bs-btn-font-size:0.875rem;--bs-btn-border-radius: 0.25rem}.fade{transition:opacity .15s linear}@media(prefers-reduced-motion: reduce){.fade{transition:none}}.fade:not(.show){opacity:0}.collapse:not(.show){display:none}.collapsing{height:0;overflow:hidden;transition:height .2s ease}@media(prefers-reduced-motion: reduce){.collapsing{transition:none}}.collapsing.collapse-horizontal{width:0;height:auto;transition:width .35s ease}@media(prefers-reduced-motion: reduce){.collapsing.collapse-horizontal{transition:none}}.dropup,.dropend,.dropdown,.dropstart,.dropup-center,.dropdown-center{position:relative}.dropdown-toggle{white-space:nowrap}.dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid rgba(0,0,0,0);border-bottom:0;border-left:.3em solid rgba(0,0,0,0)}.dropdown-toggle:empty::after{margin-left:0}.dropdown-menu{--bs-dropdown-zindex: 1000;--bs-dropdown-min-width: 10rem;--bs-dropdown-padding-x: 0;--bs-dropdown-padding-y: 0.5rem;--bs-dropdown-spacer: 0.125rem;--bs-dropdown-font-size:1rem;--bs-dropdown-color: #212529;--bs-dropdown-bg: #ffffff;--bs-dropdown-border-color: rgba(0, 0, 0, 0.175);--bs-dropdown-border-radius: 0.375rem;--bs-dropdown-border-width: 1px;--bs-dropdown-inner-border-radius: calc(0.375rem - 1px);--bs-dropdown-divider-bg: rgba(0, 0, 0, 0.175);--bs-dropdown-divider-margin-y: 0.5rem;--bs-dropdown-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);--bs-dropdown-link-color: #212529;--bs-dropdown-link-hover-color: #212529;--bs-dropdown-link-hover-bg: #f8f9fa;--bs-dropdown-link-active-color: #ffffff;--bs-dropdown-link-active-bg: #0d6efd;--bs-dropdown-link-disabled-color: rgba(33, 37, 41, 0.5);--bs-dropdown-item-padding-x: 1rem;--bs-dropdown-item-padding-y: 0.25rem;--bs-dropdown-header-color: #6c757d;--bs-dropdown-header-padding-x: 1rem;--bs-dropdown-header-padding-y: 0.5rem;position:absolute;z-index:var(--bs-dropdown-zindex);display:none;min-width:var(--bs-dropdown-min-width);padding:var(--bs-dropdown-padding-y) var(--bs-dropdown-padding-x);margin:0;font-size:var(--bs-dropdown-font-size);color:var(--bs-dropdown-color);text-align:left;list-style:none;background-color:var(--bs-dropdown-bg);background-clip:padding-box;border:var(--bs-dropdown-border-width) solid var(--bs-dropdown-border-color);border-radius:var(--bs-dropdown-border-radius)}.dropdown-menu[data-bs-popper]{top:100%;left:0;margin-top:var(--bs-dropdown-spacer)}.dropdown-menu-start{--bs-position: start}.dropdown-menu-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-end{--bs-position: end}.dropdown-menu-end[data-bs-popper]{right:0;left:auto}@media(min-width: 576px){.dropdown-menu-sm-start{--bs-position: start}.dropdown-menu-sm-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-sm-end{--bs-position: end}.dropdown-menu-sm-end[data-bs-popper]{right:0;left:auto}}@media(min-width: 768px){.dropdown-menu-md-start{--bs-position: start}.dropdown-menu-md-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-md-end{--bs-position: end}.dropdown-menu-md-end[data-bs-popper]{right:0;left:auto}}@media(min-width: 992px){.dropdown-menu-lg-start{--bs-position: start}.dropdown-menu-lg-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-lg-end{--bs-position: end}.dropdown-menu-lg-end[data-bs-popper]{right:0;left:auto}}@media(min-width: 1200px){.dropdown-menu-xl-start{--bs-position: start}.dropdown-menu-xl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xl-end{--bs-position: end}.dropdown-menu-xl-end[data-bs-popper]{right:0;left:auto}}@media(min-width: 1400px){.dropdown-menu-xxl-start{--bs-position: start}.dropdown-menu-xxl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xxl-end{--bs-position: end}.dropdown-menu-xxl-end[data-bs-popper]{right:0;left:auto}}.dropup .dropdown-menu[data-bs-popper]{top:auto;bottom:100%;margin-top:0;margin-bottom:var(--bs-dropdown-spacer)}.dropup .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid rgba(0,0,0,0);border-bottom:.3em solid;border-left:.3em solid rgba(0,0,0,0)}.dropup .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-menu[data-bs-popper]{top:0;right:auto;left:100%;margin-top:0;margin-left:var(--bs-dropdown-spacer)}.dropend .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid rgba(0,0,0,0);border-right:0;border-bottom:.3em solid rgba(0,0,0,0);border-left:.3em solid}.dropend .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-toggle::after{vertical-align:0}.dropstart .dropdown-menu[data-bs-popper]{top:0;right:100%;left:auto;margin-top:0;margin-right:var(--bs-dropdown-spacer)}.dropstart .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:""}.dropstart .dropdown-toggle::after{display:none}.dropstart .dropdown-toggle::before{display:inline-block;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid rgba(0,0,0,0);border-right:.3em solid;border-bottom:.3em solid rgba(0,0,0,0)}.dropstart .dropdown-toggle:empty::after{margin-left:0}.dropstart .dropdown-toggle::before{vertical-align:0}.dropdown-divider{height:0;margin:var(--bs-dropdown-divider-margin-y) 0;overflow:hidden;border-top:1px solid var(--bs-dropdown-divider-bg);opacity:1}.dropdown-item{display:block;width:100%;padding:var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x);clear:both;font-weight:400;color:var(--bs-dropdown-link-color);text-align:inherit;text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;white-space:nowrap;background-color:rgba(0,0,0,0);border:0;border-radius:var(--bs-dropdown-item-border-radius, 0)}.dropdown-item:hover,.dropdown-item:focus{color:var(--bs-dropdown-link-hover-color);background-color:var(--bs-dropdown-link-hover-bg)}.dropdown-item.active,.dropdown-item:active{color:var(--bs-dropdown-link-active-color);text-decoration:none;background-color:var(--bs-dropdown-link-active-bg)}.dropdown-item.disabled,.dropdown-item:disabled{color:var(--bs-dropdown-link-disabled-color);pointer-events:none;background-color:rgba(0,0,0,0)}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:var(--bs-dropdown-header-padding-y) var(--bs-dropdown-header-padding-x);margin-bottom:0;font-size:0.875rem;color:var(--bs-dropdown-header-color);white-space:nowrap}.dropdown-item-text{display:block;padding:var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x);color:var(--bs-dropdown-link-color)}.dropdown-menu-dark{--bs-dropdown-color: #dee2e6;--bs-dropdown-bg: #343a40;--bs-dropdown-border-color: rgba(0, 0, 0, 0.175);--bs-dropdown-box-shadow: ;--bs-dropdown-link-color: #dee2e6;--bs-dropdown-link-hover-color: #ffffff;--bs-dropdown-divider-bg: rgba(0, 0, 0, 0.175);--bs-dropdown-link-hover-bg: rgba(255, 255, 255, 0.15);--bs-dropdown-link-active-color: #ffffff;--bs-dropdown-link-active-bg: #0d6efd;--bs-dropdown-link-disabled-color: #adb5bd;--bs-dropdown-header-color: #adb5bd}.btn-group,.btn-group-vertical{position:relative;display:inline-flex;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;flex:1 1 auto;-webkit-flex:1 1 auto}.btn-group>.btn-check:checked+.btn,.btn-group>.btn-check:focus+.btn,.btn-group>.btn:hover,.btn-group>.btn:focus,.btn-group>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn-check:checked+.btn,.btn-group-vertical>.btn-check:focus+.btn,.btn-group-vertical>.btn:hover,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn.active{z-index:1}.btn-toolbar{display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;justify-content:flex-start;-webkit-justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group{border-radius:.375rem}.btn-group>:not(.btn-check:first-child)+.btn,.btn-group>.btn-group:not(:first-child){margin-left:calc(1px*-1)}.btn-group>.btn:not(:last-child):not(.dropdown-toggle),.btn-group>.btn.dropdown-toggle-split:first-child,.btn-group>.btn-group:not(:last-child)>.btn{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:nth-child(n+3),.btn-group>:not(.btn-check)+.btn,.btn-group>.btn-group:not(:first-child)>.btn{border-top-left-radius:0;border-bottom-left-radius:0}.dropdown-toggle-split{padding-right:.5625rem;padding-left:.5625rem}.dropdown-toggle-split::after,.dropup .dropdown-toggle-split::after,.dropend .dropdown-toggle-split::after{margin-left:0}.dropstart .dropdown-toggle-split::before{margin-right:0}.btn-sm+.dropdown-toggle-split,.btn-group-sm>.btn+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-lg+.dropdown-toggle-split,.btn-group-lg>.btn+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.btn-group-vertical{flex-direction:column;-webkit-flex-direction:column;align-items:flex-start;-webkit-align-items:flex-start;justify-content:center;-webkit-justify-content:center}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group{width:100%}.btn-group-vertical>.btn:not(:first-child),.btn-group-vertical>.btn-group:not(:first-child){margin-top:calc(1px*-1)}.btn-group-vertical>.btn:not(:last-child):not(.dropdown-toggle),.btn-group-vertical>.btn-group:not(:last-child)>.btn{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn~.btn,.btn-group-vertical>.btn-group:not(:first-child)>.btn{border-top-left-radius:0;border-top-right-radius:0}.nav{--bs-nav-link-padding-x: 1rem;--bs-nav-link-padding-y: 0.5rem;--bs-nav-link-font-weight: ;--bs-nav-link-color: #0d6efd;--bs-nav-link-hover-color: #0a58ca;--bs-nav-link-disabled-color: rgba(33, 37, 41, 0.75);display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:var(--bs-nav-link-padding-y) var(--bs-nav-link-padding-x);font-size:var(--bs-nav-link-font-size);font-weight:var(--bs-nav-link-font-weight);color:var(--bs-nav-link-color);text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;background:none;border:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out}@media(prefers-reduced-motion: reduce){.nav-link{transition:none}}.nav-link:hover,.nav-link:focus{color:var(--bs-nav-link-hover-color)}.nav-link:focus-visible{outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.nav-link.disabled,.nav-link:disabled{color:var(--bs-nav-link-disabled-color);pointer-events:none;cursor:default}.nav-tabs{--bs-nav-tabs-border-width: 1px;--bs-nav-tabs-border-color: #dee2e6;--bs-nav-tabs-border-radius: 0.375rem;--bs-nav-tabs-link-hover-border-color: #e9ecef #e9ecef #dee2e6;--bs-nav-tabs-link-active-color: #000;--bs-nav-tabs-link-active-bg: #ffffff;--bs-nav-tabs-link-active-border-color: #dee2e6 #dee2e6 #ffffff;border-bottom:var(--bs-nav-tabs-border-width) solid var(--bs-nav-tabs-border-color)}.nav-tabs .nav-link{margin-bottom:calc(-1*var(--bs-nav-tabs-border-width));border:var(--bs-nav-tabs-border-width) solid rgba(0,0,0,0);border-top-left-radius:var(--bs-nav-tabs-border-radius);border-top-right-radius:var(--bs-nav-tabs-border-radius)}.nav-tabs .nav-link:hover,.nav-tabs .nav-link:focus{isolation:isolate;border-color:var(--bs-nav-tabs-link-hover-border-color)}.nav-tabs .nav-link.active,.nav-tabs .nav-item.show .nav-link{color:var(--bs-nav-tabs-link-active-color);background-color:var(--bs-nav-tabs-link-active-bg);border-color:var(--bs-nav-tabs-link-active-border-color)}.nav-tabs .dropdown-menu{margin-top:calc(-1*var(--bs-nav-tabs-border-width));border-top-left-radius:0;border-top-right-radius:0}.nav-pills{--bs-nav-pills-border-radius: 0.375rem;--bs-nav-pills-link-active-color: #ffffff;--bs-nav-pills-link-active-bg: #0d6efd}.nav-pills .nav-link{border-radius:var(--bs-nav-pills-border-radius)}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:var(--bs-nav-pills-link-active-color);background-color:var(--bs-nav-pills-link-active-bg)}.nav-underline{--bs-nav-underline-gap: 1rem;--bs-nav-underline-border-width: 0.125rem;--bs-nav-underline-link-active-color: #000;gap:var(--bs-nav-underline-gap)}.nav-underline .nav-link{padding-right:0;padding-left:0;border-bottom:var(--bs-nav-underline-border-width) solid rgba(0,0,0,0)}.nav-underline .nav-link:hover,.nav-underline .nav-link:focus{border-bottom-color:currentcolor}.nav-underline .nav-link.active,.nav-underline .show>.nav-link{font-weight:700;color:var(--bs-nav-underline-link-active-color);border-bottom-color:currentcolor}.nav-fill>.nav-link,.nav-fill .nav-item{flex:1 1 auto;-webkit-flex:1 1 auto;text-align:center}.nav-justified>.nav-link,.nav-justified .nav-item{flex-basis:0;-webkit-flex-basis:0;flex-grow:1;-webkit-flex-grow:1;text-align:center}.nav-fill .nav-item .nav-link,.nav-justified .nav-item .nav-link{width:100%}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{--bs-navbar-padding-x: 0;--bs-navbar-padding-y: 0.5rem;--bs-navbar-color: #fdfefe;--bs-navbar-hover-color: rgba(253, 254, 255, 0.8);--bs-navbar-disabled-color: rgba(253, 254, 254, 0.75);--bs-navbar-active-color: #fdfeff;--bs-navbar-brand-padding-y: 0.3125rem;--bs-navbar-brand-margin-end: 1rem;--bs-navbar-brand-font-size: 1.25rem;--bs-navbar-brand-color: #fdfefe;--bs-navbar-brand-hover-color: #fdfeff;--bs-navbar-nav-link-padding-x: 0.5rem;--bs-navbar-toggler-padding-y: 0.25;--bs-navbar-toggler-padding-x: 0;--bs-navbar-toggler-font-size: 1.25rem;--bs-navbar-toggler-icon-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='%23fdfefe' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e");--bs-navbar-toggler-border-color: rgba(253, 254, 254, 0);--bs-navbar-toggler-border-radius: 0.375rem;--bs-navbar-toggler-focus-width: 0.25rem;--bs-navbar-toggler-transition: box-shadow 0.15s ease-in-out;position:relative;display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;align-items:center;-webkit-align-items:center;justify-content:space-between;-webkit-justify-content:space-between;padding:var(--bs-navbar-padding-y) var(--bs-navbar-padding-x)}.navbar>.container,.navbar>.container-fluid,.navbar>.container-sm,.navbar>.container-md,.navbar>.container-lg,.navbar>.container-xl,.navbar>.container-xxl{display:flex;display:-webkit-flex;flex-wrap:inherit;-webkit-flex-wrap:inherit;align-items:center;-webkit-align-items:center;justify-content:space-between;-webkit-justify-content:space-between}.navbar-brand{padding-top:var(--bs-navbar-brand-padding-y);padding-bottom:var(--bs-navbar-brand-padding-y);margin-right:var(--bs-navbar-brand-margin-end);font-size:var(--bs-navbar-brand-font-size);color:var(--bs-navbar-brand-color);text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;white-space:nowrap}.navbar-brand:hover,.navbar-brand:focus{color:var(--bs-navbar-brand-hover-color)}.navbar-nav{--bs-nav-link-padding-x: 0;--bs-nav-link-padding-y: 0.5rem;--bs-nav-link-font-weight: ;--bs-nav-link-color: var(--bs-navbar-color);--bs-nav-link-hover-color: var(--bs-navbar-hover-color);--bs-nav-link-disabled-color: var(--bs-navbar-disabled-color);display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link.active,.navbar-nav .nav-link.show{color:var(--bs-navbar-active-color)}.navbar-nav .dropdown-menu{position:static}.navbar-text{padding-top:.5rem;padding-bottom:.5rem;color:var(--bs-navbar-color)}.navbar-text a,.navbar-text a:hover,.navbar-text a:focus{color:var(--bs-navbar-active-color)}.navbar-collapse{flex-basis:100%;-webkit-flex-basis:100%;flex-grow:1;-webkit-flex-grow:1;align-items:center;-webkit-align-items:center}.navbar-toggler{padding:var(--bs-navbar-toggler-padding-y) var(--bs-navbar-toggler-padding-x);font-size:var(--bs-navbar-toggler-font-size);line-height:1;color:var(--bs-navbar-color);background-color:rgba(0,0,0,0);border:var(--bs-border-width) solid var(--bs-navbar-toggler-border-color);border-radius:var(--bs-navbar-toggler-border-radius);transition:var(--bs-navbar-toggler-transition)}@media(prefers-reduced-motion: reduce){.navbar-toggler{transition:none}}.navbar-toggler:hover{text-decoration:none}.navbar-toggler:focus{text-decoration:none;outline:0;box-shadow:0 0 0 var(--bs-navbar-toggler-focus-width)}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;background-image:var(--bs-navbar-toggler-icon-bg);background-repeat:no-repeat;background-position:center;background-size:100%}.navbar-nav-scroll{max-height:var(--bs-scroll-height, 75vh);overflow-y:auto}@media(min-width: 576px){.navbar-expand-sm{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand-sm .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-sm .navbar-nav-scroll{overflow:visible}.navbar-expand-sm .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}.navbar-expand-sm .offcanvas{position:static;z-index:auto;flex-grow:1;-webkit-flex-grow:1;width:auto !important;height:auto !important;visibility:visible !important;background-color:rgba(0,0,0,0) !important;border:0 !important;transform:none !important;transition:none}.navbar-expand-sm .offcanvas .offcanvas-header{display:none}.navbar-expand-sm .offcanvas .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}}@media(min-width: 768px){.navbar-expand-md{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand-md .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-md .navbar-nav-scroll{overflow:visible}.navbar-expand-md .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}.navbar-expand-md .offcanvas{position:static;z-index:auto;flex-grow:1;-webkit-flex-grow:1;width:auto !important;height:auto !important;visibility:visible !important;background-color:rgba(0,0,0,0) !important;border:0 !important;transform:none !important;transition:none}.navbar-expand-md .offcanvas .offcanvas-header{display:none}.navbar-expand-md .offcanvas .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}}@media(min-width: 992px){.navbar-expand-lg{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand-lg .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-lg .navbar-nav-scroll{overflow:visible}.navbar-expand-lg .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}.navbar-expand-lg .offcanvas{position:static;z-index:auto;flex-grow:1;-webkit-flex-grow:1;width:auto !important;height:auto !important;visibility:visible !important;background-color:rgba(0,0,0,0) !important;border:0 !important;transform:none !important;transition:none}.navbar-expand-lg .offcanvas .offcanvas-header{display:none}.navbar-expand-lg .offcanvas .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}}@media(min-width: 1200px){.navbar-expand-xl{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand-xl .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-xl .navbar-nav-scroll{overflow:visible}.navbar-expand-xl .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}.navbar-expand-xl .offcanvas{position:static;z-index:auto;flex-grow:1;-webkit-flex-grow:1;width:auto !important;height:auto !important;visibility:visible !important;background-color:rgba(0,0,0,0) !important;border:0 !important;transform:none !important;transition:none}.navbar-expand-xl .offcanvas .offcanvas-header{display:none}.navbar-expand-xl .offcanvas .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}}@media(min-width: 1400px){.navbar-expand-xxl{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand-xxl .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand-xxl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xxl .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-xxl .navbar-nav-scroll{overflow:visible}.navbar-expand-xxl .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand-xxl .navbar-toggler{display:none}.navbar-expand-xxl .offcanvas{position:static;z-index:auto;flex-grow:1;-webkit-flex-grow:1;width:auto !important;height:auto !important;visibility:visible !important;background-color:rgba(0,0,0,0) !important;border:0 !important;transform:none !important;transition:none}.navbar-expand-xxl .offcanvas .offcanvas-header{display:none}.navbar-expand-xxl .offcanvas .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}}.navbar-expand{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand .navbar-nav-scroll{overflow:visible}.navbar-expand .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-expand .offcanvas{position:static;z-index:auto;flex-grow:1;-webkit-flex-grow:1;width:auto !important;height:auto !important;visibility:visible !important;background-color:rgba(0,0,0,0) !important;border:0 !important;transform:none !important;transition:none}.navbar-expand .offcanvas .offcanvas-header{display:none}.navbar-expand .offcanvas .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}.navbar-dark,.navbar[data-bs-theme=dark]{--bs-navbar-color: #fdfefe;--bs-navbar-hover-color: rgba(253, 254, 255, 0.8);--bs-navbar-disabled-color: rgba(253, 254, 254, 0.75);--bs-navbar-active-color: #fdfeff;--bs-navbar-brand-color: #fdfefe;--bs-navbar-brand-hover-color: #fdfeff;--bs-navbar-toggler-border-color: rgba(253, 254, 254, 0);--bs-navbar-toggler-icon-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='%23fdfefe' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}[data-bs-theme=dark] .navbar-toggler-icon{--bs-navbar-toggler-icon-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='%23fdfefe' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.card{--bs-card-spacer-y: 1rem;--bs-card-spacer-x: 1rem;--bs-card-title-spacer-y: 0.5rem;--bs-card-title-color: ;--bs-card-subtitle-color: ;--bs-card-border-width: 1px;--bs-card-border-color: rgba(0, 0, 0, 0.175);--bs-card-border-radius: 0.375rem;--bs-card-box-shadow: ;--bs-card-inner-border-radius: calc(0.375rem - 1px);--bs-card-cap-padding-y: 0.5rem;--bs-card-cap-padding-x: 1rem;--bs-card-cap-bg: rgba(33, 37, 41, 0.03);--bs-card-cap-color: ;--bs-card-height: ;--bs-card-color: ;--bs-card-bg: #ffffff;--bs-card-img-overlay-padding: 1rem;--bs-card-group-margin: 0.75rem;position:relative;display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;min-width:0;height:var(--bs-card-height);color:var(--bs-body-color);word-wrap:break-word;background-color:var(--bs-card-bg);background-clip:border-box;border:var(--bs-card-border-width) solid var(--bs-card-border-color);border-radius:var(--bs-card-border-radius)}.card>hr{margin-right:0;margin-left:0}.card>.list-group{border-top:inherit;border-bottom:inherit}.card>.list-group:first-child{border-top-width:0;border-top-left-radius:var(--bs-card-inner-border-radius);border-top-right-radius:var(--bs-card-inner-border-radius)}.card>.list-group:last-child{border-bottom-width:0;border-bottom-right-radius:var(--bs-card-inner-border-radius);border-bottom-left-radius:var(--bs-card-inner-border-radius)}.card>.card-header+.list-group,.card>.list-group+.card-footer{border-top:0}.card-body{flex:1 1 auto;-webkit-flex:1 1 auto;padding:var(--bs-card-spacer-y) var(--bs-card-spacer-x);color:var(--bs-card-color)}.card-title{margin-bottom:var(--bs-card-title-spacer-y);color:var(--bs-card-title-color)}.card-subtitle{margin-top:calc(-0.5*var(--bs-card-title-spacer-y));margin-bottom:0;color:var(--bs-card-subtitle-color)}.card-text:last-child{margin-bottom:0}.card-link+.card-link{margin-left:var(--bs-card-spacer-x)}.card-header{padding:var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x);margin-bottom:0;color:var(--bs-card-cap-color);background-color:var(--bs-card-cap-bg);border-bottom:var(--bs-card-border-width) solid var(--bs-card-border-color)}.card-header:first-child{border-radius:var(--bs-card-inner-border-radius) var(--bs-card-inner-border-radius) 0 0}.card-footer{padding:var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x);color:var(--bs-card-cap-color);background-color:var(--bs-card-cap-bg);border-top:var(--bs-card-border-width) solid var(--bs-card-border-color)}.card-footer:last-child{border-radius:0 0 var(--bs-card-inner-border-radius) var(--bs-card-inner-border-radius)}.card-header-tabs{margin-right:calc(-0.5*var(--bs-card-cap-padding-x));margin-bottom:calc(-1*var(--bs-card-cap-padding-y));margin-left:calc(-0.5*var(--bs-card-cap-padding-x));border-bottom:0}.card-header-tabs .nav-link.active{background-color:var(--bs-card-bg);border-bottom-color:var(--bs-card-bg)}.card-header-pills{margin-right:calc(-0.5*var(--bs-card-cap-padding-x));margin-left:calc(-0.5*var(--bs-card-cap-padding-x))}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:var(--bs-card-img-overlay-padding);border-radius:var(--bs-card-inner-border-radius)}.card-img,.card-img-top,.card-img-bottom{width:100%}.card-img,.card-img-top{border-top-left-radius:var(--bs-card-inner-border-radius);border-top-right-radius:var(--bs-card-inner-border-radius)}.card-img,.card-img-bottom{border-bottom-right-radius:var(--bs-card-inner-border-radius);border-bottom-left-radius:var(--bs-card-inner-border-radius)}.card-group>.card{margin-bottom:var(--bs-card-group-margin)}@media(min-width: 576px){.card-group{display:flex;display:-webkit-flex;flex-flow:row wrap;-webkit-flex-flow:row wrap}.card-group>.card{flex:1 0 0%;-webkit-flex:1 0 0%;margin-bottom:0}.card-group>.card+.card{margin-left:0;border-left:0}.card-group>.card:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.card-group>.card:not(:last-child) .card-img-top,.card-group>.card:not(:last-child) .card-header{border-top-right-radius:0}.card-group>.card:not(:last-child) .card-img-bottom,.card-group>.card:not(:last-child) .card-footer{border-bottom-right-radius:0}.card-group>.card:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.card-group>.card:not(:first-child) .card-img-top,.card-group>.card:not(:first-child) .card-header{border-top-left-radius:0}.card-group>.card:not(:first-child) .card-img-bottom,.card-group>.card:not(:first-child) .card-footer{border-bottom-left-radius:0}}.accordion{--bs-accordion-color: #212529;--bs-accordion-bg: #ffffff;--bs-accordion-transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out, border-radius 0.15s ease;--bs-accordion-border-color: #dee2e6;--bs-accordion-border-width: 1px;--bs-accordion-border-radius: 0.375rem;--bs-accordion-inner-border-radius: calc(0.375rem - 1px);--bs-accordion-btn-padding-x: 1.25rem;--bs-accordion-btn-padding-y: 1rem;--bs-accordion-btn-color: #212529;--bs-accordion-btn-bg: #ffffff;--bs-accordion-btn-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23212529'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");--bs-accordion-btn-icon-width: 1.25rem;--bs-accordion-btn-icon-transform: rotate(-180deg);--bs-accordion-btn-icon-transition: transform 0.2s ease-in-out;--bs-accordion-btn-active-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23052c65'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");--bs-accordion-btn-focus-border-color: #86b7fe;--bs-accordion-btn-focus-box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);--bs-accordion-body-padding-x: 1.25rem;--bs-accordion-body-padding-y: 1rem;--bs-accordion-active-color: #052c65;--bs-accordion-active-bg: #cfe2ff}.accordion-button{position:relative;display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;width:100%;padding:var(--bs-accordion-btn-padding-y) var(--bs-accordion-btn-padding-x);font-size:1rem;color:var(--bs-accordion-btn-color);text-align:left;background-color:var(--bs-accordion-btn-bg);border:0;border-radius:0;overflow-anchor:none;transition:var(--bs-accordion-transition)}@media(prefers-reduced-motion: reduce){.accordion-button{transition:none}}.accordion-button:not(.collapsed){color:var(--bs-accordion-active-color);background-color:var(--bs-accordion-active-bg);box-shadow:inset 0 calc(-1*var(--bs-accordion-border-width)) 0 var(--bs-accordion-border-color)}.accordion-button:not(.collapsed)::after{background-image:var(--bs-accordion-btn-active-icon);transform:var(--bs-accordion-btn-icon-transform)}.accordion-button::after{flex-shrink:0;-webkit-flex-shrink:0;width:var(--bs-accordion-btn-icon-width);height:var(--bs-accordion-btn-icon-width);margin-left:auto;content:"";background-image:var(--bs-accordion-btn-icon);background-repeat:no-repeat;background-size:var(--bs-accordion-btn-icon-width);transition:var(--bs-accordion-btn-icon-transition)}@media(prefers-reduced-motion: reduce){.accordion-button::after{transition:none}}.accordion-button:hover{z-index:2}.accordion-button:focus{z-index:3;border-color:var(--bs-accordion-btn-focus-border-color);outline:0;box-shadow:var(--bs-accordion-btn-focus-box-shadow)}.accordion-header{margin-bottom:0}.accordion-item{color:var(--bs-accordion-color);background-color:var(--bs-accordion-bg);border:var(--bs-accordion-border-width) solid var(--bs-accordion-border-color)}.accordion-item:first-of-type{border-top-left-radius:var(--bs-accordion-border-radius);border-top-right-radius:var(--bs-accordion-border-radius)}.accordion-item:first-of-type .accordion-button{border-top-left-radius:var(--bs-accordion-inner-border-radius);border-top-right-radius:var(--bs-accordion-inner-border-radius)}.accordion-item:not(:first-of-type){border-top:0}.accordion-item:last-of-type{border-bottom-right-radius:var(--bs-accordion-border-radius);border-bottom-left-radius:var(--bs-accordion-border-radius)}.accordion-item:last-of-type .accordion-button.collapsed{border-bottom-right-radius:var(--bs-accordion-inner-border-radius);border-bottom-left-radius:var(--bs-accordion-inner-border-radius)}.accordion-item:last-of-type .accordion-collapse{border-bottom-right-radius:var(--bs-accordion-border-radius);border-bottom-left-radius:var(--bs-accordion-border-radius)}.accordion-body{padding:var(--bs-accordion-body-padding-y) var(--bs-accordion-body-padding-x)}.accordion-flush .accordion-collapse{border-width:0}.accordion-flush .accordion-item{border-right:0;border-left:0;border-radius:0}.accordion-flush .accordion-item:first-child{border-top:0}.accordion-flush .accordion-item:last-child{border-bottom:0}.accordion-flush .accordion-item .accordion-button,.accordion-flush .accordion-item .accordion-button.collapsed{border-radius:0}[data-bs-theme=dark] .accordion-button::after{--bs-accordion-btn-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%236ea8fe'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");--bs-accordion-btn-active-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%236ea8fe'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e")}.breadcrumb{--bs-breadcrumb-padding-x: 0;--bs-breadcrumb-padding-y: 0;--bs-breadcrumb-margin-bottom: 1rem;--bs-breadcrumb-bg: ;--bs-breadcrumb-border-radius: ;--bs-breadcrumb-divider-color: rgba(33, 37, 41, 0.75);--bs-breadcrumb-item-padding-x: 0.5rem;--bs-breadcrumb-item-active-color: rgba(33, 37, 41, 0.75);display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;padding:var(--bs-breadcrumb-padding-y) var(--bs-breadcrumb-padding-x);margin-bottom:var(--bs-breadcrumb-margin-bottom);font-size:var(--bs-breadcrumb-font-size);list-style:none;background-color:var(--bs-breadcrumb-bg);border-radius:var(--bs-breadcrumb-border-radius)}.breadcrumb-item+.breadcrumb-item{padding-left:var(--bs-breadcrumb-item-padding-x)}.breadcrumb-item+.breadcrumb-item::before{float:left;padding-right:var(--bs-breadcrumb-item-padding-x);color:var(--bs-breadcrumb-divider-color);content:var(--bs-breadcrumb-divider, ">") /* rtl: var(--bs-breadcrumb-divider, ">") */}.breadcrumb-item.active{color:var(--bs-breadcrumb-item-active-color)}.pagination{--bs-pagination-padding-x: 0.75rem;--bs-pagination-padding-y: 0.375rem;--bs-pagination-font-size:1rem;--bs-pagination-color: #0d6efd;--bs-pagination-bg: #ffffff;--bs-pagination-border-width: 1px;--bs-pagination-border-color: #dee2e6;--bs-pagination-border-radius: 0.375rem;--bs-pagination-hover-color: #0a58ca;--bs-pagination-hover-bg: #f8f9fa;--bs-pagination-hover-border-color: #dee2e6;--bs-pagination-focus-color: #0a58ca;--bs-pagination-focus-bg: #e9ecef;--bs-pagination-focus-box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);--bs-pagination-active-color: #ffffff;--bs-pagination-active-bg: #0d6efd;--bs-pagination-active-border-color: #0d6efd;--bs-pagination-disabled-color: rgba(33, 37, 41, 0.75);--bs-pagination-disabled-bg: #e9ecef;--bs-pagination-disabled-border-color: #dee2e6;display:flex;display:-webkit-flex;padding-left:0;list-style:none}.page-link{position:relative;display:block;padding:var(--bs-pagination-padding-y) var(--bs-pagination-padding-x);font-size:var(--bs-pagination-font-size);color:var(--bs-pagination-color);text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;background-color:var(--bs-pagination-bg);border:var(--bs-pagination-border-width) solid var(--bs-pagination-border-color);transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.page-link{transition:none}}.page-link:hover{z-index:2;color:var(--bs-pagination-hover-color);background-color:var(--bs-pagination-hover-bg);border-color:var(--bs-pagination-hover-border-color)}.page-link:focus{z-index:3;color:var(--bs-pagination-focus-color);background-color:var(--bs-pagination-focus-bg);outline:0;box-shadow:var(--bs-pagination-focus-box-shadow)}.page-link.active,.active>.page-link{z-index:3;color:var(--bs-pagination-active-color);background-color:var(--bs-pagination-active-bg);border-color:var(--bs-pagination-active-border-color)}.page-link.disabled,.disabled>.page-link{color:var(--bs-pagination-disabled-color);pointer-events:none;background-color:var(--bs-pagination-disabled-bg);border-color:var(--bs-pagination-disabled-border-color)}.page-item:not(:first-child) .page-link{margin-left:calc(1px*-1)}.page-item:first-child .page-link{border-top-left-radius:var(--bs-pagination-border-radius);border-bottom-left-radius:var(--bs-pagination-border-radius)}.page-item:last-child .page-link{border-top-right-radius:var(--bs-pagination-border-radius);border-bottom-right-radius:var(--bs-pagination-border-radius)}.pagination-lg{--bs-pagination-padding-x: 1.5rem;--bs-pagination-padding-y: 0.75rem;--bs-pagination-font-size:1.25rem;--bs-pagination-border-radius: 0.5rem}.pagination-sm{--bs-pagination-padding-x: 0.5rem;--bs-pagination-padding-y: 0.25rem;--bs-pagination-font-size:0.875rem;--bs-pagination-border-radius: 0.25rem}.badge{--bs-badge-padding-x: 0.65em;--bs-badge-padding-y: 0.35em;--bs-badge-font-size:0.75em;--bs-badge-font-weight: 700;--bs-badge-color: #ffffff;--bs-badge-border-radius: 0.375rem;display:inline-block;padding:var(--bs-badge-padding-y) var(--bs-badge-padding-x);font-size:var(--bs-badge-font-size);font-weight:var(--bs-badge-font-weight);line-height:1;color:var(--bs-badge-color);text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:var(--bs-badge-border-radius)}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.alert{--bs-alert-bg: transparent;--bs-alert-padding-x: 1rem;--bs-alert-padding-y: 1rem;--bs-alert-margin-bottom: 1rem;--bs-alert-color: inherit;--bs-alert-border-color: transparent;--bs-alert-border: 1px solid var(--bs-alert-border-color);--bs-alert-border-radius: 0.375rem;--bs-alert-link-color: inherit;position:relative;padding:var(--bs-alert-padding-y) var(--bs-alert-padding-x);margin-bottom:var(--bs-alert-margin-bottom);color:var(--bs-alert-color);background-color:var(--bs-alert-bg);border:var(--bs-alert-border);border-radius:var(--bs-alert-border-radius)}.alert-heading{color:inherit}.alert-link{font-weight:700;color:var(--bs-alert-link-color)}.alert-dismissible{padding-right:3rem}.alert-dismissible .btn-close{position:absolute;top:0;right:0;z-index:2;padding:1.25rem 1rem}.alert-default{--bs-alert-color: var(--bs-default-text-emphasis);--bs-alert-bg: var(--bs-default-bg-subtle);--bs-alert-border-color: var(--bs-default-border-subtle);--bs-alert-link-color: var(--bs-default-text-emphasis)}.alert-primary{--bs-alert-color: var(--bs-primary-text-emphasis);--bs-alert-bg: var(--bs-primary-bg-subtle);--bs-alert-border-color: var(--bs-primary-border-subtle);--bs-alert-link-color: var(--bs-primary-text-emphasis)}.alert-secondary{--bs-alert-color: var(--bs-secondary-text-emphasis);--bs-alert-bg: var(--bs-secondary-bg-subtle);--bs-alert-border-color: var(--bs-secondary-border-subtle);--bs-alert-link-color: var(--bs-secondary-text-emphasis)}.alert-success{--bs-alert-color: var(--bs-success-text-emphasis);--bs-alert-bg: var(--bs-success-bg-subtle);--bs-alert-border-color: var(--bs-success-border-subtle);--bs-alert-link-color: var(--bs-success-text-emphasis)}.alert-info{--bs-alert-color: var(--bs-info-text-emphasis);--bs-alert-bg: var(--bs-info-bg-subtle);--bs-alert-border-color: var(--bs-info-border-subtle);--bs-alert-link-color: var(--bs-info-text-emphasis)}.alert-warning{--bs-alert-color: var(--bs-warning-text-emphasis);--bs-alert-bg: var(--bs-warning-bg-subtle);--bs-alert-border-color: var(--bs-warning-border-subtle);--bs-alert-link-color: var(--bs-warning-text-emphasis)}.alert-danger{--bs-alert-color: var(--bs-danger-text-emphasis);--bs-alert-bg: var(--bs-danger-bg-subtle);--bs-alert-border-color: var(--bs-danger-border-subtle);--bs-alert-link-color: var(--bs-danger-text-emphasis)}.alert-light{--bs-alert-color: var(--bs-light-text-emphasis);--bs-alert-bg: var(--bs-light-bg-subtle);--bs-alert-border-color: var(--bs-light-border-subtle);--bs-alert-link-color: var(--bs-light-text-emphasis)}.alert-dark{--bs-alert-color: var(--bs-dark-text-emphasis);--bs-alert-bg: var(--bs-dark-bg-subtle);--bs-alert-border-color: var(--bs-dark-border-subtle);--bs-alert-link-color: var(--bs-dark-text-emphasis)}@keyframes progress-bar-stripes{0%{background-position-x:1rem}}.progress,.progress-stacked{--bs-progress-height: 1rem;--bs-progress-font-size:0.75rem;--bs-progress-bg: #e9ecef;--bs-progress-border-radius: 0.375rem;--bs-progress-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.075);--bs-progress-bar-color: #ffffff;--bs-progress-bar-bg: #0d6efd;--bs-progress-bar-transition: width 0.6s ease;display:flex;display:-webkit-flex;height:var(--bs-progress-height);overflow:hidden;font-size:var(--bs-progress-font-size);background-color:var(--bs-progress-bg);border-radius:var(--bs-progress-border-radius)}.progress-bar{display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;justify-content:center;-webkit-justify-content:center;overflow:hidden;color:var(--bs-progress-bar-color);text-align:center;white-space:nowrap;background-color:var(--bs-progress-bar-bg);transition:var(--bs-progress-bar-transition)}@media(prefers-reduced-motion: reduce){.progress-bar{transition:none}}.progress-bar-striped{background-image:linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-size:var(--bs-progress-height) var(--bs-progress-height)}.progress-stacked>.progress{overflow:visible}.progress-stacked>.progress>.progress-bar{width:100%}.progress-bar-animated{animation:1s linear infinite progress-bar-stripes}@media(prefers-reduced-motion: reduce){.progress-bar-animated{animation:none}}.list-group{--bs-list-group-color: #212529;--bs-list-group-bg: #ffffff;--bs-list-group-border-color: #dee2e6;--bs-list-group-border-width: 1px;--bs-list-group-border-radius: 0.375rem;--bs-list-group-item-padding-x: 1rem;--bs-list-group-item-padding-y: 0.5rem;--bs-list-group-action-color: rgba(33, 37, 41, 0.75);--bs-list-group-action-hover-color: #000;--bs-list-group-action-hover-bg: #f8f9fa;--bs-list-group-action-active-color: #212529;--bs-list-group-action-active-bg: #e9ecef;--bs-list-group-disabled-color: rgba(33, 37, 41, 0.75);--bs-list-group-disabled-bg: #ffffff;--bs-list-group-active-color: #ffffff;--bs-list-group-active-bg: #0d6efd;--bs-list-group-active-border-color: #0d6efd;display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;padding-left:0;margin-bottom:0;border-radius:var(--bs-list-group-border-radius)}.list-group-numbered{list-style-type:none;counter-reset:section}.list-group-numbered>.list-group-item::before{content:counters(section, ".") ". ";counter-increment:section}.list-group-item-action{width:100%;color:var(--bs-list-group-action-color);text-align:inherit}.list-group-item-action:hover,.list-group-item-action:focus{z-index:1;color:var(--bs-list-group-action-hover-color);text-decoration:none;background-color:var(--bs-list-group-action-hover-bg)}.list-group-item-action:active{color:var(--bs-list-group-action-active-color);background-color:var(--bs-list-group-action-active-bg)}.list-group-item{position:relative;display:block;padding:var(--bs-list-group-item-padding-y) var(--bs-list-group-item-padding-x);color:var(--bs-list-group-color);text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;background-color:var(--bs-list-group-bg);border:var(--bs-list-group-border-width) solid var(--bs-list-group-border-color)}.list-group-item:first-child{border-top-left-radius:inherit;border-top-right-radius:inherit}.list-group-item:last-child{border-bottom-right-radius:inherit;border-bottom-left-radius:inherit}.list-group-item.disabled,.list-group-item:disabled{color:var(--bs-list-group-disabled-color);pointer-events:none;background-color:var(--bs-list-group-disabled-bg)}.list-group-item.active{z-index:2;color:var(--bs-list-group-active-color);background-color:var(--bs-list-group-active-bg);border-color:var(--bs-list-group-active-border-color)}.list-group-item+.list-group-item{border-top-width:0}.list-group-item+.list-group-item.active{margin-top:calc(-1*var(--bs-list-group-border-width));border-top-width:var(--bs-list-group-border-width)}.list-group-horizontal{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal>.list-group-item.active{margin-top:0}.list-group-horizontal>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal>.list-group-item+.list-group-item.active{margin-left:calc(-1*var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}@media(min-width: 576px){.list-group-horizontal-sm{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal-sm>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-sm>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-sm>.list-group-item.active{margin-top:0}.list-group-horizontal-sm>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-sm>.list-group-item+.list-group-item.active{margin-left:calc(-1*var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media(min-width: 768px){.list-group-horizontal-md{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal-md>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-md>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-md>.list-group-item.active{margin-top:0}.list-group-horizontal-md>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-md>.list-group-item+.list-group-item.active{margin-left:calc(-1*var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media(min-width: 992px){.list-group-horizontal-lg{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal-lg>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-lg>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-lg>.list-group-item.active{margin-top:0}.list-group-horizontal-lg>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-lg>.list-group-item+.list-group-item.active{margin-left:calc(-1*var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media(min-width: 1200px){.list-group-horizontal-xl{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal-xl>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-xl>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-xl>.list-group-item.active{margin-top:0}.list-group-horizontal-xl>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-xl>.list-group-item+.list-group-item.active{margin-left:calc(-1*var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media(min-width: 1400px){.list-group-horizontal-xxl{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal-xxl>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-xxl>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-xxl>.list-group-item.active{margin-top:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item.active{margin-left:calc(-1*var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}.list-group-flush{border-radius:0}.list-group-flush>.list-group-item{border-width:0 0 var(--bs-list-group-border-width)}.list-group-flush>.list-group-item:last-child{border-bottom-width:0}.list-group-item-default{--bs-list-group-color: var(--bs-default-text-emphasis);--bs-list-group-bg: var(--bs-default-bg-subtle);--bs-list-group-border-color: var(--bs-default-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-default-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-default-border-subtle);--bs-list-group-active-color: var(--bs-default-bg-subtle);--bs-list-group-active-bg: var(--bs-default-text-emphasis);--bs-list-group-active-border-color: var(--bs-default-text-emphasis)}.list-group-item-primary{--bs-list-group-color: var(--bs-primary-text-emphasis);--bs-list-group-bg: var(--bs-primary-bg-subtle);--bs-list-group-border-color: var(--bs-primary-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-primary-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-primary-border-subtle);--bs-list-group-active-color: var(--bs-primary-bg-subtle);--bs-list-group-active-bg: var(--bs-primary-text-emphasis);--bs-list-group-active-border-color: var(--bs-primary-text-emphasis)}.list-group-item-secondary{--bs-list-group-color: var(--bs-secondary-text-emphasis);--bs-list-group-bg: var(--bs-secondary-bg-subtle);--bs-list-group-border-color: var(--bs-secondary-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-secondary-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-secondary-border-subtle);--bs-list-group-active-color: var(--bs-secondary-bg-subtle);--bs-list-group-active-bg: var(--bs-secondary-text-emphasis);--bs-list-group-active-border-color: var(--bs-secondary-text-emphasis)}.list-group-item-success{--bs-list-group-color: var(--bs-success-text-emphasis);--bs-list-group-bg: var(--bs-success-bg-subtle);--bs-list-group-border-color: var(--bs-success-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-success-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-success-border-subtle);--bs-list-group-active-color: var(--bs-success-bg-subtle);--bs-list-group-active-bg: var(--bs-success-text-emphasis);--bs-list-group-active-border-color: var(--bs-success-text-emphasis)}.list-group-item-info{--bs-list-group-color: var(--bs-info-text-emphasis);--bs-list-group-bg: var(--bs-info-bg-subtle);--bs-list-group-border-color: var(--bs-info-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-info-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-info-border-subtle);--bs-list-group-active-color: var(--bs-info-bg-subtle);--bs-list-group-active-bg: var(--bs-info-text-emphasis);--bs-list-group-active-border-color: var(--bs-info-text-emphasis)}.list-group-item-warning{--bs-list-group-color: var(--bs-warning-text-emphasis);--bs-list-group-bg: var(--bs-warning-bg-subtle);--bs-list-group-border-color: var(--bs-warning-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-warning-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-warning-border-subtle);--bs-list-group-active-color: var(--bs-warning-bg-subtle);--bs-list-group-active-bg: var(--bs-warning-text-emphasis);--bs-list-group-active-border-color: var(--bs-warning-text-emphasis)}.list-group-item-danger{--bs-list-group-color: var(--bs-danger-text-emphasis);--bs-list-group-bg: var(--bs-danger-bg-subtle);--bs-list-group-border-color: var(--bs-danger-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-danger-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-danger-border-subtle);--bs-list-group-active-color: var(--bs-danger-bg-subtle);--bs-list-group-active-bg: var(--bs-danger-text-emphasis);--bs-list-group-active-border-color: var(--bs-danger-text-emphasis)}.list-group-item-light{--bs-list-group-color: var(--bs-light-text-emphasis);--bs-list-group-bg: var(--bs-light-bg-subtle);--bs-list-group-border-color: var(--bs-light-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-light-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-light-border-subtle);--bs-list-group-active-color: var(--bs-light-bg-subtle);--bs-list-group-active-bg: var(--bs-light-text-emphasis);--bs-list-group-active-border-color: var(--bs-light-text-emphasis)}.list-group-item-dark{--bs-list-group-color: var(--bs-dark-text-emphasis);--bs-list-group-bg: var(--bs-dark-bg-subtle);--bs-list-group-border-color: var(--bs-dark-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-dark-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-dark-border-subtle);--bs-list-group-active-color: var(--bs-dark-bg-subtle);--bs-list-group-active-bg: var(--bs-dark-text-emphasis);--bs-list-group-active-border-color: var(--bs-dark-text-emphasis)}.btn-close{--bs-btn-close-color: #000;--bs-btn-close-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath d='M.293.293a1 1 0 0 1 1.414 0L8 6.586 14.293.293a1 1 0 1 1 1.414 1.414L9.414 8l6.293 6.293a1 1 0 0 1-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 0 1-1.414-1.414L6.586 8 .293 1.707a1 1 0 0 1 0-1.414z'/%3e%3c/svg%3e");--bs-btn-close-opacity: 0.5;--bs-btn-close-hover-opacity: 0.75;--bs-btn-close-focus-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);--bs-btn-close-focus-opacity: 1;--bs-btn-close-disabled-opacity: 0.25;--bs-btn-close-white-filter: invert(1) grayscale(100%) brightness(200%);box-sizing:content-box;width:1em;height:1em;padding:.25em .25em;color:var(--bs-btn-close-color);background:rgba(0,0,0,0) var(--bs-btn-close-bg) center/1em auto no-repeat;border:0;border-radius:.375rem;opacity:var(--bs-btn-close-opacity)}.btn-close:hover{color:var(--bs-btn-close-color);text-decoration:none;opacity:var(--bs-btn-close-hover-opacity)}.btn-close:focus{outline:0;box-shadow:var(--bs-btn-close-focus-shadow);opacity:var(--bs-btn-close-focus-opacity)}.btn-close:disabled,.btn-close.disabled{pointer-events:none;user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;opacity:var(--bs-btn-close-disabled-opacity)}.btn-close-white{filter:var(--bs-btn-close-white-filter)}[data-bs-theme=dark] .btn-close{filter:var(--bs-btn-close-white-filter)}.toast{--bs-toast-zindex: 1090;--bs-toast-padding-x: 0.75rem;--bs-toast-padding-y: 0.5rem;--bs-toast-spacing: 1.5rem;--bs-toast-max-width: 350px;--bs-toast-font-size:0.875rem;--bs-toast-color: ;--bs-toast-bg: rgba(255, 255, 255, 0.85);--bs-toast-border-width: 1px;--bs-toast-border-color: rgba(0, 0, 0, 0.175);--bs-toast-border-radius: 0.375rem;--bs-toast-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);--bs-toast-header-color: rgba(33, 37, 41, 0.75);--bs-toast-header-bg: rgba(255, 255, 255, 0.85);--bs-toast-header-border-color: rgba(0, 0, 0, 0.175);width:var(--bs-toast-max-width);max-width:100%;font-size:var(--bs-toast-font-size);color:var(--bs-toast-color);pointer-events:auto;background-color:var(--bs-toast-bg);background-clip:padding-box;border:var(--bs-toast-border-width) solid var(--bs-toast-border-color);box-shadow:var(--bs-toast-box-shadow);border-radius:var(--bs-toast-border-radius)}.toast.showing{opacity:0}.toast:not(.show){display:none}.toast-container{--bs-toast-zindex: 1090;position:absolute;z-index:var(--bs-toast-zindex);width:max-content;width:-webkit-max-content;width:-moz-max-content;width:-ms-max-content;width:-o-max-content;max-width:100%;pointer-events:none}.toast-container>:not(:last-child){margin-bottom:var(--bs-toast-spacing)}.toast-header{display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;padding:var(--bs-toast-padding-y) var(--bs-toast-padding-x);color:var(--bs-toast-header-color);background-color:var(--bs-toast-header-bg);background-clip:padding-box;border-bottom:var(--bs-toast-border-width) solid var(--bs-toast-header-border-color);border-top-left-radius:calc(var(--bs-toast-border-radius) - var(--bs-toast-border-width));border-top-right-radius:calc(var(--bs-toast-border-radius) - var(--bs-toast-border-width))}.toast-header .btn-close{margin-right:calc(-0.5*var(--bs-toast-padding-x));margin-left:var(--bs-toast-padding-x)}.toast-body{padding:var(--bs-toast-padding-x);word-wrap:break-word}.modal{--bs-modal-zindex: 1055;--bs-modal-width: 500px;--bs-modal-padding: 1rem;--bs-modal-margin: 0.5rem;--bs-modal-color: ;--bs-modal-bg: #ffffff;--bs-modal-border-color: rgba(0, 0, 0, 0.175);--bs-modal-border-width: 1px;--bs-modal-border-radius: 0.5rem;--bs-modal-box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);--bs-modal-inner-border-radius: calc(0.5rem - 1px);--bs-modal-header-padding-x: 1rem;--bs-modal-header-padding-y: 1rem;--bs-modal-header-padding: 1rem 1rem;--bs-modal-header-border-color: #dee2e6;--bs-modal-header-border-width: 1px;--bs-modal-title-line-height: 1.5;--bs-modal-footer-gap: 0.5rem;--bs-modal-footer-bg: ;--bs-modal-footer-border-color: #dee2e6;--bs-modal-footer-border-width: 1px;position:fixed;top:0;left:0;z-index:var(--bs-modal-zindex);display:none;width:100%;height:100%;overflow-x:hidden;overflow-y:auto;outline:0}.modal-dialog{position:relative;width:auto;margin:var(--bs-modal-margin);pointer-events:none}.modal.fade .modal-dialog{transition:transform .3s ease-out;transform:translate(0, -50px)}@media(prefers-reduced-motion: reduce){.modal.fade .modal-dialog{transition:none}}.modal.show .modal-dialog{transform:none}.modal.modal-static .modal-dialog{transform:scale(1.02)}.modal-dialog-scrollable{height:calc(100% - var(--bs-modal-margin)*2)}.modal-dialog-scrollable .modal-content{max-height:100%;overflow:hidden}.modal-dialog-scrollable .modal-body{overflow-y:auto}.modal-dialog-centered{display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;min-height:calc(100% - var(--bs-modal-margin)*2)}.modal-content{position:relative;display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;width:100%;color:var(--bs-modal-color);pointer-events:auto;background-color:var(--bs-modal-bg);background-clip:padding-box;border:var(--bs-modal-border-width) solid var(--bs-modal-border-color);border-radius:var(--bs-modal-border-radius);outline:0}.modal-backdrop{--bs-backdrop-zindex: 1050;--bs-backdrop-bg: #000;--bs-backdrop-opacity: 0.5;position:fixed;top:0;left:0;z-index:var(--bs-backdrop-zindex);width:100vw;height:100vh;background-color:var(--bs-backdrop-bg)}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:var(--bs-backdrop-opacity)}.modal-header{display:flex;display:-webkit-flex;flex-shrink:0;-webkit-flex-shrink:0;align-items:center;-webkit-align-items:center;justify-content:space-between;-webkit-justify-content:space-between;padding:var(--bs-modal-header-padding);border-bottom:var(--bs-modal-header-border-width) solid var(--bs-modal-header-border-color);border-top-left-radius:var(--bs-modal-inner-border-radius);border-top-right-radius:var(--bs-modal-inner-border-radius)}.modal-header .btn-close{padding:calc(var(--bs-modal-header-padding-y)*.5) calc(var(--bs-modal-header-padding-x)*.5);margin:calc(-0.5*var(--bs-modal-header-padding-y)) calc(-0.5*var(--bs-modal-header-padding-x)) calc(-0.5*var(--bs-modal-header-padding-y)) auto}.modal-title{margin-bottom:0;line-height:var(--bs-modal-title-line-height)}.modal-body{position:relative;flex:1 1 auto;-webkit-flex:1 1 auto;padding:var(--bs-modal-padding)}.modal-footer{display:flex;display:-webkit-flex;flex-shrink:0;-webkit-flex-shrink:0;flex-wrap:wrap;-webkit-flex-wrap:wrap;align-items:center;-webkit-align-items:center;justify-content:flex-end;-webkit-justify-content:flex-end;padding:calc(var(--bs-modal-padding) - var(--bs-modal-footer-gap)*.5);background-color:var(--bs-modal-footer-bg);border-top:var(--bs-modal-footer-border-width) solid var(--bs-modal-footer-border-color);border-bottom-right-radius:var(--bs-modal-inner-border-radius);border-bottom-left-radius:var(--bs-modal-inner-border-radius)}.modal-footer>*{margin:calc(var(--bs-modal-footer-gap)*.5)}@media(min-width: 576px){.modal{--bs-modal-margin: 1.75rem;--bs-modal-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15)}.modal-dialog{max-width:var(--bs-modal-width);margin-right:auto;margin-left:auto}.modal-sm{--bs-modal-width: 300px}}@media(min-width: 992px){.modal-lg,.modal-xl{--bs-modal-width: 800px}}@media(min-width: 1200px){.modal-xl{--bs-modal-width: 1140px}}.modal-fullscreen{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen .modal-header,.modal-fullscreen .modal-footer{border-radius:0}.modal-fullscreen .modal-body{overflow-y:auto}@media(max-width: 575.98px){.modal-fullscreen-sm-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-sm-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-sm-down .modal-header,.modal-fullscreen-sm-down .modal-footer{border-radius:0}.modal-fullscreen-sm-down .modal-body{overflow-y:auto}}@media(max-width: 767.98px){.modal-fullscreen-md-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-md-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-md-down .modal-header,.modal-fullscreen-md-down .modal-footer{border-radius:0}.modal-fullscreen-md-down .modal-body{overflow-y:auto}}@media(max-width: 991.98px){.modal-fullscreen-lg-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-lg-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-lg-down .modal-header,.modal-fullscreen-lg-down .modal-footer{border-radius:0}.modal-fullscreen-lg-down .modal-body{overflow-y:auto}}@media(max-width: 1199.98px){.modal-fullscreen-xl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xl-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-xl-down .modal-header,.modal-fullscreen-xl-down .modal-footer{border-radius:0}.modal-fullscreen-xl-down .modal-body{overflow-y:auto}}@media(max-width: 1399.98px){.modal-fullscreen-xxl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xxl-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-xxl-down .modal-header,.modal-fullscreen-xxl-down .modal-footer{border-radius:0}.modal-fullscreen-xxl-down .modal-body{overflow-y:auto}}.tooltip{--bs-tooltip-zindex: 1080;--bs-tooltip-max-width: 200px;--bs-tooltip-padding-x: 0.5rem;--bs-tooltip-padding-y: 0.25rem;--bs-tooltip-margin: ;--bs-tooltip-font-size:0.875rem;--bs-tooltip-color: #ffffff;--bs-tooltip-bg: #000;--bs-tooltip-border-radius: 0.375rem;--bs-tooltip-opacity: 0.9;--bs-tooltip-arrow-width: 0.8rem;--bs-tooltip-arrow-height: 0.4rem;z-index:var(--bs-tooltip-zindex);display:block;margin:var(--bs-tooltip-margin);font-family:system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue","Noto Sans","Liberation Sans",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;white-space:normal;word-spacing:normal;line-break:auto;font-size:var(--bs-tooltip-font-size);word-wrap:break-word;opacity:0}.tooltip.show{opacity:var(--bs-tooltip-opacity)}.tooltip .tooltip-arrow{display:block;width:var(--bs-tooltip-arrow-width);height:var(--bs-tooltip-arrow-height)}.tooltip .tooltip-arrow::before{position:absolute;content:"";border-color:rgba(0,0,0,0);border-style:solid}.bs-tooltip-top .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow{bottom:calc(-1*var(--bs-tooltip-arrow-height))}.bs-tooltip-top .tooltip-arrow::before,.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow::before{top:-1px;border-width:var(--bs-tooltip-arrow-height) calc(var(--bs-tooltip-arrow-width)*.5) 0;border-top-color:var(--bs-tooltip-bg)}.bs-tooltip-end .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow{left:calc(-1*var(--bs-tooltip-arrow-height));width:var(--bs-tooltip-arrow-height);height:var(--bs-tooltip-arrow-width)}.bs-tooltip-end .tooltip-arrow::before,.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow::before{right:-1px;border-width:calc(var(--bs-tooltip-arrow-width)*.5) var(--bs-tooltip-arrow-height) calc(var(--bs-tooltip-arrow-width)*.5) 0;border-right-color:var(--bs-tooltip-bg)}.bs-tooltip-bottom .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow{top:calc(-1*var(--bs-tooltip-arrow-height))}.bs-tooltip-bottom .tooltip-arrow::before,.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow::before{bottom:-1px;border-width:0 calc(var(--bs-tooltip-arrow-width)*.5) var(--bs-tooltip-arrow-height);border-bottom-color:var(--bs-tooltip-bg)}.bs-tooltip-start .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow{right:calc(-1*var(--bs-tooltip-arrow-height));width:var(--bs-tooltip-arrow-height);height:var(--bs-tooltip-arrow-width)}.bs-tooltip-start .tooltip-arrow::before,.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow::before{left:-1px;border-width:calc(var(--bs-tooltip-arrow-width)*.5) 0 calc(var(--bs-tooltip-arrow-width)*.5) var(--bs-tooltip-arrow-height);border-left-color:var(--bs-tooltip-bg)}.tooltip-inner{max-width:var(--bs-tooltip-max-width);padding:var(--bs-tooltip-padding-y) var(--bs-tooltip-padding-x);color:var(--bs-tooltip-color);text-align:center;background-color:var(--bs-tooltip-bg);border-radius:var(--bs-tooltip-border-radius)}.popover{--bs-popover-zindex: 1070;--bs-popover-max-width: 276px;--bs-popover-font-size:0.875rem;--bs-popover-bg: #ffffff;--bs-popover-border-width: 1px;--bs-popover-border-color: rgba(0, 0, 0, 0.175);--bs-popover-border-radius: 0.5rem;--bs-popover-inner-border-radius: calc(0.5rem - 1px);--bs-popover-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);--bs-popover-header-padding-x: 1rem;--bs-popover-header-padding-y: 0.5rem;--bs-popover-header-font-size:1rem;--bs-popover-header-color: inherit;--bs-popover-header-bg: #e9ecef;--bs-popover-body-padding-x: 1rem;--bs-popover-body-padding-y: 1rem;--bs-popover-body-color: #212529;--bs-popover-arrow-width: 1rem;--bs-popover-arrow-height: 0.5rem;--bs-popover-arrow-border: var(--bs-popover-border-color);z-index:var(--bs-popover-zindex);display:block;max-width:var(--bs-popover-max-width);font-family:system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue","Noto Sans","Liberation Sans",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;white-space:normal;word-spacing:normal;line-break:auto;font-size:var(--bs-popover-font-size);word-wrap:break-word;background-color:var(--bs-popover-bg);background-clip:padding-box;border:var(--bs-popover-border-width) solid var(--bs-popover-border-color);border-radius:var(--bs-popover-border-radius)}.popover .popover-arrow{display:block;width:var(--bs-popover-arrow-width);height:var(--bs-popover-arrow-height)}.popover .popover-arrow::before,.popover .popover-arrow::after{position:absolute;display:block;content:"";border-color:rgba(0,0,0,0);border-style:solid;border-width:0}.bs-popover-top>.popover-arrow,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow{bottom:calc(-1*(var(--bs-popover-arrow-height)) - var(--bs-popover-border-width))}.bs-popover-top>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::before,.bs-popover-top>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::after{border-width:var(--bs-popover-arrow-height) calc(var(--bs-popover-arrow-width)*.5) 0}.bs-popover-top>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::before{bottom:0;border-top-color:var(--bs-popover-arrow-border)}.bs-popover-top>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::after{bottom:var(--bs-popover-border-width);border-top-color:var(--bs-popover-bg)}.bs-popover-end>.popover-arrow,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow{left:calc(-1*(var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));width:var(--bs-popover-arrow-height);height:var(--bs-popover-arrow-width)}.bs-popover-end>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::before,.bs-popover-end>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::after{border-width:calc(var(--bs-popover-arrow-width)*.5) var(--bs-popover-arrow-height) calc(var(--bs-popover-arrow-width)*.5) 0}.bs-popover-end>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::before{left:0;border-right-color:var(--bs-popover-arrow-border)}.bs-popover-end>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::after{left:var(--bs-popover-border-width);border-right-color:var(--bs-popover-bg)}.bs-popover-bottom>.popover-arrow,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow{top:calc(-1*(var(--bs-popover-arrow-height)) - var(--bs-popover-border-width))}.bs-popover-bottom>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::before,.bs-popover-bottom>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::after{border-width:0 calc(var(--bs-popover-arrow-width)*.5) var(--bs-popover-arrow-height)}.bs-popover-bottom>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::before{top:0;border-bottom-color:var(--bs-popover-arrow-border)}.bs-popover-bottom>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::after{top:var(--bs-popover-border-width);border-bottom-color:var(--bs-popover-bg)}.bs-popover-bottom .popover-header::before,.bs-popover-auto[data-popper-placement^=bottom] .popover-header::before{position:absolute;top:0;left:50%;display:block;width:var(--bs-popover-arrow-width);margin-left:calc(-0.5*var(--bs-popover-arrow-width));content:"";border-bottom:var(--bs-popover-border-width) solid var(--bs-popover-header-bg)}.bs-popover-start>.popover-arrow,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow{right:calc(-1*(var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));width:var(--bs-popover-arrow-height);height:var(--bs-popover-arrow-width)}.bs-popover-start>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::before,.bs-popover-start>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::after{border-width:calc(var(--bs-popover-arrow-width)*.5) 0 calc(var(--bs-popover-arrow-width)*.5) var(--bs-popover-arrow-height)}.bs-popover-start>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::before{right:0;border-left-color:var(--bs-popover-arrow-border)}.bs-popover-start>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::after{right:var(--bs-popover-border-width);border-left-color:var(--bs-popover-bg)}.popover-header{padding:var(--bs-popover-header-padding-y) var(--bs-popover-header-padding-x);margin-bottom:0;font-size:var(--bs-popover-header-font-size);color:var(--bs-popover-header-color);background-color:var(--bs-popover-header-bg);border-bottom:var(--bs-popover-border-width) solid var(--bs-popover-border-color);border-top-left-radius:var(--bs-popover-inner-border-radius);border-top-right-radius:var(--bs-popover-inner-border-radius)}.popover-header:empty{display:none}.popover-body{padding:var(--bs-popover-body-padding-y) var(--bs-popover-body-padding-x);color:var(--bs-popover-body-color)}.carousel{position:relative}.carousel.pointer-event{touch-action:pan-y;-webkit-touch-action:pan-y;-moz-touch-action:pan-y;-ms-touch-action:pan-y;-o-touch-action:pan-y}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner::after{display:block;clear:both;content:""}.carousel-item{position:relative;display:none;float:left;width:100%;margin-right:-100%;backface-visibility:hidden;-webkit-backface-visibility:hidden;-moz-backface-visibility:hidden;-ms-backface-visibility:hidden;-o-backface-visibility:hidden;transition:transform .6s ease-in-out}@media(prefers-reduced-motion: reduce){.carousel-item{transition:none}}.carousel-item.active,.carousel-item-next,.carousel-item-prev{display:block}.carousel-item-next:not(.carousel-item-start),.active.carousel-item-end{transform:translateX(100%)}.carousel-item-prev:not(.carousel-item-end),.active.carousel-item-start{transform:translateX(-100%)}.carousel-fade .carousel-item{opacity:0;transition-property:opacity;transform:none}.carousel-fade .carousel-item.active,.carousel-fade .carousel-item-next.carousel-item-start,.carousel-fade .carousel-item-prev.carousel-item-end{z-index:1;opacity:1}.carousel-fade .active.carousel-item-start,.carousel-fade .active.carousel-item-end{z-index:0;opacity:0;transition:opacity 0s .6s}@media(prefers-reduced-motion: reduce){.carousel-fade .active.carousel-item-start,.carousel-fade .active.carousel-item-end{transition:none}}.carousel-control-prev,.carousel-control-next{position:absolute;top:0;bottom:0;z-index:1;display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;justify-content:center;-webkit-justify-content:center;width:15%;padding:0;color:#fff;text-align:center;background:none;border:0;opacity:.5;transition:opacity .15s ease}@media(prefers-reduced-motion: reduce){.carousel-control-prev,.carousel-control-next{transition:none}}.carousel-control-prev:hover,.carousel-control-prev:focus,.carousel-control-next:hover,.carousel-control-next:focus{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-prev-icon,.carousel-control-next-icon{display:inline-block;width:2rem;height:2rem;background-repeat:no-repeat;background-position:50%;background-size:100% 100%}.carousel-control-prev-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23ffffff'%3e%3cpath d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z'/%3e%3c/svg%3e")}.carousel-control-next-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23ffffff'%3e%3cpath d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e")}.carousel-indicators{position:absolute;right:0;bottom:0;left:0;z-index:2;display:flex;display:-webkit-flex;justify-content:center;-webkit-justify-content:center;padding:0;margin-right:15%;margin-bottom:1rem;margin-left:15%}.carousel-indicators [data-bs-target]{box-sizing:content-box;flex:0 1 auto;-webkit-flex:0 1 auto;width:30px;height:3px;padding:0;margin-right:3px;margin-left:3px;text-indent:-999px;cursor:pointer;background-color:#fff;background-clip:padding-box;border:0;border-top:10px solid rgba(0,0,0,0);border-bottom:10px solid rgba(0,0,0,0);opacity:.5;transition:opacity .6s ease}@media(prefers-reduced-motion: reduce){.carousel-indicators [data-bs-target]{transition:none}}.carousel-indicators .active{opacity:1}.carousel-caption{position:absolute;right:15%;bottom:1.25rem;left:15%;padding-top:1.25rem;padding-bottom:1.25rem;color:#fff;text-align:center}.carousel-dark .carousel-control-prev-icon,.carousel-dark .carousel-control-next-icon{filter:invert(1) grayscale(100)}.carousel-dark .carousel-indicators [data-bs-target]{background-color:#000}.carousel-dark .carousel-caption{color:#000}[data-bs-theme=dark] .carousel .carousel-control-prev-icon,[data-bs-theme=dark] .carousel .carousel-control-next-icon,[data-bs-theme=dark].carousel .carousel-control-prev-icon,[data-bs-theme=dark].carousel .carousel-control-next-icon{filter:invert(1) grayscale(100)}[data-bs-theme=dark] .carousel .carousel-indicators [data-bs-target],[data-bs-theme=dark].carousel .carousel-indicators [data-bs-target]{background-color:#000}[data-bs-theme=dark] .carousel .carousel-caption,[data-bs-theme=dark].carousel .carousel-caption{color:#000}.spinner-grow,.spinner-border{display:inline-block;width:var(--bs-spinner-width);height:var(--bs-spinner-height);vertical-align:var(--bs-spinner-vertical-align);border-radius:50%;animation:var(--bs-spinner-animation-speed) linear infinite var(--bs-spinner-animation-name)}@keyframes spinner-border{to{transform:rotate(360deg) /* rtl:ignore */}}.spinner-border{--bs-spinner-width: 2rem;--bs-spinner-height: 2rem;--bs-spinner-vertical-align: -0.125em;--bs-spinner-border-width: 0.25em;--bs-spinner-animation-speed: 0.75s;--bs-spinner-animation-name: spinner-border;border:var(--bs-spinner-border-width) solid currentcolor;border-right-color:rgba(0,0,0,0)}.spinner-border-sm{--bs-spinner-width: 1rem;--bs-spinner-height: 1rem;--bs-spinner-border-width: 0.2em}@keyframes spinner-grow{0%{transform:scale(0)}50%{opacity:1;transform:none}}.spinner-grow{--bs-spinner-width: 2rem;--bs-spinner-height: 2rem;--bs-spinner-vertical-align: -0.125em;--bs-spinner-animation-speed: 0.75s;--bs-spinner-animation-name: spinner-grow;background-color:currentcolor;opacity:0}.spinner-grow-sm{--bs-spinner-width: 1rem;--bs-spinner-height: 1rem}@media(prefers-reduced-motion: reduce){.spinner-border,.spinner-grow{--bs-spinner-animation-speed: 1.5s}}.offcanvas,.offcanvas-xxl,.offcanvas-xl,.offcanvas-lg,.offcanvas-md,.offcanvas-sm{--bs-offcanvas-zindex: 1045;--bs-offcanvas-width: 400px;--bs-offcanvas-height: 30vh;--bs-offcanvas-padding-x: 1rem;--bs-offcanvas-padding-y: 1rem;--bs-offcanvas-color: #212529;--bs-offcanvas-bg: #ffffff;--bs-offcanvas-border-width: 1px;--bs-offcanvas-border-color: rgba(0, 0, 0, 0.175);--bs-offcanvas-box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);--bs-offcanvas-transition: transform 0.3s ease-in-out;--bs-offcanvas-title-line-height: 1.5}@media(max-width: 575.98px){.offcanvas-sm{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media(max-width: 575.98px)and (prefers-reduced-motion: reduce){.offcanvas-sm{transition:none}}@media(max-width: 575.98px){.offcanvas-sm.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-sm.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-sm.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-sm.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-sm.showing,.offcanvas-sm.show:not(.hiding){transform:none}.offcanvas-sm.showing,.offcanvas-sm.hiding,.offcanvas-sm.show{visibility:visible}}@media(min-width: 576px){.offcanvas-sm{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:rgba(0,0,0,0) !important}.offcanvas-sm .offcanvas-header{display:none}.offcanvas-sm .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible;background-color:rgba(0,0,0,0) !important}}@media(max-width: 767.98px){.offcanvas-md{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media(max-width: 767.98px)and (prefers-reduced-motion: reduce){.offcanvas-md{transition:none}}@media(max-width: 767.98px){.offcanvas-md.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-md.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-md.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-md.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-md.showing,.offcanvas-md.show:not(.hiding){transform:none}.offcanvas-md.showing,.offcanvas-md.hiding,.offcanvas-md.show{visibility:visible}}@media(min-width: 768px){.offcanvas-md{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:rgba(0,0,0,0) !important}.offcanvas-md .offcanvas-header{display:none}.offcanvas-md .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible;background-color:rgba(0,0,0,0) !important}}@media(max-width: 991.98px){.offcanvas-lg{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media(max-width: 991.98px)and (prefers-reduced-motion: reduce){.offcanvas-lg{transition:none}}@media(max-width: 991.98px){.offcanvas-lg.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-lg.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-lg.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-lg.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-lg.showing,.offcanvas-lg.show:not(.hiding){transform:none}.offcanvas-lg.showing,.offcanvas-lg.hiding,.offcanvas-lg.show{visibility:visible}}@media(min-width: 992px){.offcanvas-lg{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:rgba(0,0,0,0) !important}.offcanvas-lg .offcanvas-header{display:none}.offcanvas-lg .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible;background-color:rgba(0,0,0,0) !important}}@media(max-width: 1199.98px){.offcanvas-xl{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media(max-width: 1199.98px)and (prefers-reduced-motion: reduce){.offcanvas-xl{transition:none}}@media(max-width: 1199.98px){.offcanvas-xl.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-xl.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-xl.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-xl.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-xl.showing,.offcanvas-xl.show:not(.hiding){transform:none}.offcanvas-xl.showing,.offcanvas-xl.hiding,.offcanvas-xl.show{visibility:visible}}@media(min-width: 1200px){.offcanvas-xl{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:rgba(0,0,0,0) !important}.offcanvas-xl .offcanvas-header{display:none}.offcanvas-xl .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible;background-color:rgba(0,0,0,0) !important}}@media(max-width: 1399.98px){.offcanvas-xxl{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media(max-width: 1399.98px)and (prefers-reduced-motion: reduce){.offcanvas-xxl{transition:none}}@media(max-width: 1399.98px){.offcanvas-xxl.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-xxl.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-xxl.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-xxl.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-xxl.showing,.offcanvas-xxl.show:not(.hiding){transform:none}.offcanvas-xxl.showing,.offcanvas-xxl.hiding,.offcanvas-xxl.show{visibility:visible}}@media(min-width: 1400px){.offcanvas-xxl{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:rgba(0,0,0,0) !important}.offcanvas-xxl .offcanvas-header{display:none}.offcanvas-xxl .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible;background-color:rgba(0,0,0,0) !important}}.offcanvas{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}@media(prefers-reduced-motion: reduce){.offcanvas{transition:none}}.offcanvas.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas.showing,.offcanvas.show:not(.hiding){transform:none}.offcanvas.showing,.offcanvas.hiding,.offcanvas.show{visibility:visible}.offcanvas-backdrop{position:fixed;top:0;left:0;z-index:1040;width:100vw;height:100vh;background-color:#000}.offcanvas-backdrop.fade{opacity:0}.offcanvas-backdrop.show{opacity:.5}.offcanvas-header{display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;justify-content:space-between;-webkit-justify-content:space-between;padding:var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x)}.offcanvas-header .btn-close{padding:calc(var(--bs-offcanvas-padding-y)*.5) calc(var(--bs-offcanvas-padding-x)*.5);margin-top:calc(-0.5*var(--bs-offcanvas-padding-y));margin-right:calc(-0.5*var(--bs-offcanvas-padding-x));margin-bottom:calc(-0.5*var(--bs-offcanvas-padding-y))}.offcanvas-title{margin-bottom:0;line-height:var(--bs-offcanvas-title-line-height)}.offcanvas-body{flex-grow:1;-webkit-flex-grow:1;padding:var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x);overflow-y:auto}.placeholder{display:inline-block;min-height:1em;vertical-align:middle;cursor:wait;background-color:currentcolor;opacity:.5}.placeholder.btn::before{display:inline-block;content:""}.placeholder-xs{min-height:.6em}.placeholder-sm{min-height:.8em}.placeholder-lg{min-height:1.2em}.placeholder-glow .placeholder{animation:placeholder-glow 2s ease-in-out infinite}@keyframes placeholder-glow{50%{opacity:.2}}.placeholder-wave{mask-image:linear-gradient(130deg, #000 55%, rgba(0, 0, 0, 0.8) 75%, #000 95%);-webkit-mask-image:linear-gradient(130deg, #000 55%, rgba(0, 0, 0, 0.8) 75%, #000 95%);mask-size:200% 100%;-webkit-mask-size:200% 100%;animation:placeholder-wave 2s linear infinite}@keyframes placeholder-wave{100%{mask-position:-200% 0%;-webkit-mask-position:-200% 0%}}.clearfix::after{display:block;clear:both;content:""}.text-bg-default{color:#000 !important;background-color:RGBA(var(--bs-default-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-primary{color:#fff !important;background-color:RGBA(var(--bs-primary-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-secondary{color:#fff !important;background-color:RGBA(var(--bs-secondary-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-success{color:#fff !important;background-color:RGBA(var(--bs-success-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-info{color:#000 !important;background-color:RGBA(var(--bs-info-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-warning{color:#000 !important;background-color:RGBA(var(--bs-warning-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-danger{color:#fff !important;background-color:RGBA(var(--bs-danger-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-light{color:#000 !important;background-color:RGBA(var(--bs-light-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-dark{color:#fff !important;background-color:RGBA(var(--bs-dark-rgb), var(--bs-bg-opacity, 1)) !important}.link-default{color:RGBA(var(--bs-default-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-default-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-default:hover,.link-default:focus{color:RGBA(229, 232, 235, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(229, 232, 235, var(--bs-link-underline-opacity, 1)) !important}.link-primary{color:RGBA(var(--bs-primary-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-primary-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-primary:hover,.link-primary:focus{color:RGBA(10, 88, 202, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(10, 88, 202, var(--bs-link-underline-opacity, 1)) !important}.link-secondary{color:RGBA(var(--bs-secondary-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-secondary-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-secondary:hover,.link-secondary:focus{color:RGBA(86, 94, 100, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(86, 94, 100, var(--bs-link-underline-opacity, 1)) !important}.link-success{color:RGBA(var(--bs-success-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-success-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-success:hover,.link-success:focus{color:RGBA(20, 108, 67, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(20, 108, 67, var(--bs-link-underline-opacity, 1)) !important}.link-info{color:RGBA(var(--bs-info-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-info-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-info:hover,.link-info:focus{color:RGBA(61, 213, 243, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(61, 213, 243, var(--bs-link-underline-opacity, 1)) !important}.link-warning{color:RGBA(var(--bs-warning-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-warning-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-warning:hover,.link-warning:focus{color:RGBA(255, 205, 57, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(255, 205, 57, var(--bs-link-underline-opacity, 1)) !important}.link-danger{color:RGBA(var(--bs-danger-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-danger-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-danger:hover,.link-danger:focus{color:RGBA(176, 42, 55, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(176, 42, 55, var(--bs-link-underline-opacity, 1)) !important}.link-light{color:RGBA(var(--bs-light-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-light-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-light:hover,.link-light:focus{color:RGBA(249, 250, 251, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(249, 250, 251, var(--bs-link-underline-opacity, 1)) !important}.link-dark{color:RGBA(var(--bs-dark-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-dark-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-dark:hover,.link-dark:focus{color:RGBA(26, 30, 33, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(26, 30, 33, var(--bs-link-underline-opacity, 1)) !important}.link-body-emphasis{color:RGBA(var(--bs-emphasis-color-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-emphasis-color-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-body-emphasis:hover,.link-body-emphasis:focus{color:RGBA(var(--bs-emphasis-color-rgb), var(--bs-link-opacity, 0.75)) !important;text-decoration-color:RGBA(var(--bs-emphasis-color-rgb), var(--bs-link-underline-opacity, 0.75)) !important}.focus-ring:focus{outline:0;box-shadow:var(--bs-focus-ring-x, 0) var(--bs-focus-ring-y, 0) var(--bs-focus-ring-blur, 0) var(--bs-focus-ring-width) var(--bs-focus-ring-color)}.icon-link{display:inline-flex;gap:.375rem;align-items:center;-webkit-align-items:center;text-decoration-color:rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 0.5));text-underline-offset:.25em;backface-visibility:hidden;-webkit-backface-visibility:hidden;-moz-backface-visibility:hidden;-ms-backface-visibility:hidden;-o-backface-visibility:hidden}.icon-link>.bi{flex-shrink:0;-webkit-flex-shrink:0;width:1em;height:1em;fill:currentcolor;transition:.2s ease-in-out transform}@media(prefers-reduced-motion: reduce){.icon-link>.bi{transition:none}}.icon-link-hover:hover>.bi,.icon-link-hover:focus-visible>.bi{transform:var(--bs-icon-link-transform, translate3d(0.25em, 0, 0))}.ratio{position:relative;width:100%}.ratio::before{display:block;padding-top:var(--bs-aspect-ratio);content:""}.ratio>*{position:absolute;top:0;left:0;width:100%;height:100%}.ratio-1x1{--bs-aspect-ratio: 100%}.ratio-4x3{--bs-aspect-ratio: 75%}.ratio-16x9{--bs-aspect-ratio: 56.25%}.ratio-21x9{--bs-aspect-ratio: 42.8571428571%}.fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030}.fixed-bottom{position:fixed;right:0;bottom:0;left:0;z-index:1030}.sticky-top{position:sticky;top:0;z-index:1020}.sticky-bottom{position:sticky;bottom:0;z-index:1020}@media(min-width: 576px){.sticky-sm-top{position:sticky;top:0;z-index:1020}.sticky-sm-bottom{position:sticky;bottom:0;z-index:1020}}@media(min-width: 768px){.sticky-md-top{position:sticky;top:0;z-index:1020}.sticky-md-bottom{position:sticky;bottom:0;z-index:1020}}@media(min-width: 992px){.sticky-lg-top{position:sticky;top:0;z-index:1020}.sticky-lg-bottom{position:sticky;bottom:0;z-index:1020}}@media(min-width: 1200px){.sticky-xl-top{position:sticky;top:0;z-index:1020}.sticky-xl-bottom{position:sticky;bottom:0;z-index:1020}}@media(min-width: 1400px){.sticky-xxl-top{position:sticky;top:0;z-index:1020}.sticky-xxl-bottom{position:sticky;bottom:0;z-index:1020}}.hstack{display:flex;display:-webkit-flex;flex-direction:row;-webkit-flex-direction:row;align-items:center;-webkit-align-items:center;align-self:stretch;-webkit-align-self:stretch}.vstack{display:flex;display:-webkit-flex;flex:1 1 auto;-webkit-flex:1 1 auto;flex-direction:column;-webkit-flex-direction:column;align-self:stretch;-webkit-align-self:stretch}.visually-hidden,.visually-hidden-focusable:not(:focus):not(:focus-within){width:1px !important;height:1px !important;padding:0 !important;margin:-1px !important;overflow:hidden !important;clip:rect(0, 0, 0, 0) !important;white-space:nowrap !important;border:0 !important}.visually-hidden:not(caption),.visually-hidden-focusable:not(:focus):not(:focus-within):not(caption){position:absolute !important}.stretched-link::after{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;content:""}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vr{display:inline-block;align-self:stretch;-webkit-align-self:stretch;width:1px;min-height:1em;background-color:currentcolor;opacity:.25}.align-baseline{vertical-align:baseline !important}.align-top{vertical-align:top !important}.align-middle{vertical-align:middle !important}.align-bottom{vertical-align:bottom !important}.align-text-bottom{vertical-align:text-bottom !important}.align-text-top{vertical-align:text-top !important}.float-start{float:left !important}.float-end{float:right !important}.float-none{float:none !important}.object-fit-contain{object-fit:contain !important}.object-fit-cover{object-fit:cover !important}.object-fit-fill{object-fit:fill !important}.object-fit-scale{object-fit:scale-down !important}.object-fit-none{object-fit:none !important}.opacity-0{opacity:0 !important}.opacity-25{opacity:.25 !important}.opacity-50{opacity:.5 !important}.opacity-75{opacity:.75 !important}.opacity-100{opacity:1 !important}.overflow-auto{overflow:auto !important}.overflow-hidden{overflow:hidden !important}.overflow-visible{overflow:visible !important}.overflow-scroll{overflow:scroll !important}.overflow-x-auto{overflow-x:auto !important}.overflow-x-hidden{overflow-x:hidden !important}.overflow-x-visible{overflow-x:visible !important}.overflow-x-scroll{overflow-x:scroll !important}.overflow-y-auto{overflow-y:auto !important}.overflow-y-hidden{overflow-y:hidden !important}.overflow-y-visible{overflow-y:visible !important}.overflow-y-scroll{overflow-y:scroll !important}.d-inline{display:inline !important}.d-inline-block{display:inline-block !important}.d-block{display:block !important}.d-grid{display:grid !important}.d-inline-grid{display:inline-grid !important}.d-table{display:table !important}.d-table-row{display:table-row !important}.d-table-cell{display:table-cell !important}.d-flex{display:flex !important}.d-inline-flex{display:inline-flex !important}.d-none{display:none !important}.shadow{box-shadow:0 .5rem 1rem rgba(0,0,0,.15) !important}.shadow-sm{box-shadow:0 .125rem .25rem rgba(0,0,0,.075) !important}.shadow-lg{box-shadow:0 1rem 3rem rgba(0,0,0,.175) !important}.shadow-none{box-shadow:none !important}.focus-ring-default{--bs-focus-ring-color: rgba(var(--bs-default-rgb), var(--bs-focus-ring-opacity))}.focus-ring-primary{--bs-focus-ring-color: rgba(var(--bs-primary-rgb), var(--bs-focus-ring-opacity))}.focus-ring-secondary{--bs-focus-ring-color: rgba(var(--bs-secondary-rgb), var(--bs-focus-ring-opacity))}.focus-ring-success{--bs-focus-ring-color: rgba(var(--bs-success-rgb), var(--bs-focus-ring-opacity))}.focus-ring-info{--bs-focus-ring-color: rgba(var(--bs-info-rgb), var(--bs-focus-ring-opacity))}.focus-ring-warning{--bs-focus-ring-color: rgba(var(--bs-warning-rgb), var(--bs-focus-ring-opacity))}.focus-ring-danger{--bs-focus-ring-color: rgba(var(--bs-danger-rgb), var(--bs-focus-ring-opacity))}.focus-ring-light{--bs-focus-ring-color: rgba(var(--bs-light-rgb), var(--bs-focus-ring-opacity))}.focus-ring-dark{--bs-focus-ring-color: rgba(var(--bs-dark-rgb), var(--bs-focus-ring-opacity))}.position-static{position:static !important}.position-relative{position:relative !important}.position-absolute{position:absolute !important}.position-fixed{position:fixed !important}.position-sticky{position:sticky !important}.top-0{top:0 !important}.top-50{top:50% !important}.top-100{top:100% !important}.bottom-0{bottom:0 !important}.bottom-50{bottom:50% !important}.bottom-100{bottom:100% !important}.start-0{left:0 !important}.start-50{left:50% !important}.start-100{left:100% !important}.end-0{right:0 !important}.end-50{right:50% !important}.end-100{right:100% !important}.translate-middle{transform:translate(-50%, -50%) !important}.translate-middle-x{transform:translateX(-50%) !important}.translate-middle-y{transform:translateY(-50%) !important}.border{border:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important}.border-0{border:0 !important}.border-top{border-top:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important}.border-top-0{border-top:0 !important}.border-end{border-right:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important}.border-end-0{border-right:0 !important}.border-bottom{border-bottom:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important}.border-bottom-0{border-bottom:0 !important}.border-start{border-left:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important}.border-start-0{border-left:0 !important}.border-default{--bs-border-opacity: 1;border-color:rgba(var(--bs-default-rgb), var(--bs-border-opacity)) !important}.border-primary{--bs-border-opacity: 1;border-color:rgba(var(--bs-primary-rgb), var(--bs-border-opacity)) !important}.border-secondary{--bs-border-opacity: 1;border-color:rgba(var(--bs-secondary-rgb), var(--bs-border-opacity)) !important}.border-success{--bs-border-opacity: 1;border-color:rgba(var(--bs-success-rgb), var(--bs-border-opacity)) !important}.border-info{--bs-border-opacity: 1;border-color:rgba(var(--bs-info-rgb), var(--bs-border-opacity)) !important}.border-warning{--bs-border-opacity: 1;border-color:rgba(var(--bs-warning-rgb), var(--bs-border-opacity)) !important}.border-danger{--bs-border-opacity: 1;border-color:rgba(var(--bs-danger-rgb), var(--bs-border-opacity)) !important}.border-light{--bs-border-opacity: 1;border-color:rgba(var(--bs-light-rgb), var(--bs-border-opacity)) !important}.border-dark{--bs-border-opacity: 1;border-color:rgba(var(--bs-dark-rgb), var(--bs-border-opacity)) !important}.border-black{--bs-border-opacity: 1;border-color:rgba(var(--bs-black-rgb), var(--bs-border-opacity)) !important}.border-white{--bs-border-opacity: 1;border-color:rgba(var(--bs-white-rgb), var(--bs-border-opacity)) !important}.border-primary-subtle{border-color:var(--bs-primary-border-subtle) !important}.border-secondary-subtle{border-color:var(--bs-secondary-border-subtle) !important}.border-success-subtle{border-color:var(--bs-success-border-subtle) !important}.border-info-subtle{border-color:var(--bs-info-border-subtle) !important}.border-warning-subtle{border-color:var(--bs-warning-border-subtle) !important}.border-danger-subtle{border-color:var(--bs-danger-border-subtle) !important}.border-light-subtle{border-color:var(--bs-light-border-subtle) !important}.border-dark-subtle{border-color:var(--bs-dark-border-subtle) !important}.border-1{border-width:1px !important}.border-2{border-width:2px !important}.border-3{border-width:3px !important}.border-4{border-width:4px !important}.border-5{border-width:5px !important}.border-opacity-10{--bs-border-opacity: 0.1}.border-opacity-25{--bs-border-opacity: 0.25}.border-opacity-50{--bs-border-opacity: 0.5}.border-opacity-75{--bs-border-opacity: 0.75}.border-opacity-100{--bs-border-opacity: 1}.w-25{width:25% !important}.w-50{width:50% !important}.w-75{width:75% !important}.w-100{width:100% !important}.w-auto{width:auto !important}.mw-100{max-width:100% !important}.vw-100{width:100vw !important}.min-vw-100{min-width:100vw !important}.h-25{height:25% !important}.h-50{height:50% !important}.h-75{height:75% !important}.h-100{height:100% !important}.h-auto{height:auto !important}.mh-100{max-height:100% !important}.vh-100{height:100vh !important}.min-vh-100{min-height:100vh !important}.flex-fill{flex:1 1 auto !important}.flex-row{flex-direction:row !important}.flex-column{flex-direction:column !important}.flex-row-reverse{flex-direction:row-reverse !important}.flex-column-reverse{flex-direction:column-reverse !important}.flex-grow-0{flex-grow:0 !important}.flex-grow-1{flex-grow:1 !important}.flex-shrink-0{flex-shrink:0 !important}.flex-shrink-1{flex-shrink:1 !important}.flex-wrap{flex-wrap:wrap !important}.flex-nowrap{flex-wrap:nowrap !important}.flex-wrap-reverse{flex-wrap:wrap-reverse !important}.justify-content-start{justify-content:flex-start !important}.justify-content-end{justify-content:flex-end !important}.justify-content-center{justify-content:center !important}.justify-content-between{justify-content:space-between !important}.justify-content-around{justify-content:space-around !important}.justify-content-evenly{justify-content:space-evenly !important}.align-items-start{align-items:flex-start !important}.align-items-end{align-items:flex-end !important}.align-items-center{align-items:center !important}.align-items-baseline{align-items:baseline !important}.align-items-stretch{align-items:stretch !important}.align-content-start{align-content:flex-start !important}.align-content-end{align-content:flex-end !important}.align-content-center{align-content:center !important}.align-content-between{align-content:space-between !important}.align-content-around{align-content:space-around !important}.align-content-stretch{align-content:stretch !important}.align-self-auto{align-self:auto !important}.align-self-start{align-self:flex-start !important}.align-self-end{align-self:flex-end !important}.align-self-center{align-self:center !important}.align-self-baseline{align-self:baseline !important}.align-self-stretch{align-self:stretch !important}.order-first{order:-1 !important}.order-0{order:0 !important}.order-1{order:1 !important}.order-2{order:2 !important}.order-3{order:3 !important}.order-4{order:4 !important}.order-5{order:5 !important}.order-last{order:6 !important}.m-0{margin:0 !important}.m-1{margin:.25rem !important}.m-2{margin:.5rem !important}.m-3{margin:1rem !important}.m-4{margin:1.5rem !important}.m-5{margin:3rem !important}.m-auto{margin:auto !important}.mx-0{margin-right:0 !important;margin-left:0 !important}.mx-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-3{margin-right:1rem !important;margin-left:1rem !important}.mx-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-5{margin-right:3rem !important;margin-left:3rem !important}.mx-auto{margin-right:auto !important;margin-left:auto !important}.my-0{margin-top:0 !important;margin-bottom:0 !important}.my-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-0{margin-top:0 !important}.mt-1{margin-top:.25rem !important}.mt-2{margin-top:.5rem !important}.mt-3{margin-top:1rem !important}.mt-4{margin-top:1.5rem !important}.mt-5{margin-top:3rem !important}.mt-auto{margin-top:auto !important}.me-0{margin-right:0 !important}.me-1{margin-right:.25rem !important}.me-2{margin-right:.5rem !important}.me-3{margin-right:1rem !important}.me-4{margin-right:1.5rem !important}.me-5{margin-right:3rem !important}.me-auto{margin-right:auto !important}.mb-0{margin-bottom:0 !important}.mb-1{margin-bottom:.25rem !important}.mb-2{margin-bottom:.5rem !important}.mb-3{margin-bottom:1rem !important}.mb-4{margin-bottom:1.5rem !important}.mb-5{margin-bottom:3rem !important}.mb-auto{margin-bottom:auto !important}.ms-0{margin-left:0 !important}.ms-1{margin-left:.25rem !important}.ms-2{margin-left:.5rem !important}.ms-3{margin-left:1rem !important}.ms-4{margin-left:1.5rem !important}.ms-5{margin-left:3rem !important}.ms-auto{margin-left:auto !important}.p-0{padding:0 !important}.p-1{padding:.25rem !important}.p-2{padding:.5rem !important}.p-3{padding:1rem !important}.p-4{padding:1.5rem !important}.p-5{padding:3rem !important}.px-0{padding-right:0 !important;padding-left:0 !important}.px-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-3{padding-right:1rem !important;padding-left:1rem !important}.px-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-5{padding-right:3rem !important;padding-left:3rem !important}.py-0{padding-top:0 !important;padding-bottom:0 !important}.py-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-0{padding-top:0 !important}.pt-1{padding-top:.25rem !important}.pt-2{padding-top:.5rem !important}.pt-3{padding-top:1rem !important}.pt-4{padding-top:1.5rem !important}.pt-5{padding-top:3rem !important}.pe-0{padding-right:0 !important}.pe-1{padding-right:.25rem !important}.pe-2{padding-right:.5rem !important}.pe-3{padding-right:1rem !important}.pe-4{padding-right:1.5rem !important}.pe-5{padding-right:3rem !important}.pb-0{padding-bottom:0 !important}.pb-1{padding-bottom:.25rem !important}.pb-2{padding-bottom:.5rem !important}.pb-3{padding-bottom:1rem !important}.pb-4{padding-bottom:1.5rem !important}.pb-5{padding-bottom:3rem !important}.ps-0{padding-left:0 !important}.ps-1{padding-left:.25rem !important}.ps-2{padding-left:.5rem !important}.ps-3{padding-left:1rem !important}.ps-4{padding-left:1.5rem !important}.ps-5{padding-left:3rem !important}.gap-0{gap:0 !important}.gap-1{gap:.25rem !important}.gap-2{gap:.5rem !important}.gap-3{gap:1rem !important}.gap-4{gap:1.5rem !important}.gap-5{gap:3rem !important}.row-gap-0{row-gap:0 !important}.row-gap-1{row-gap:.25rem !important}.row-gap-2{row-gap:.5rem !important}.row-gap-3{row-gap:1rem !important}.row-gap-4{row-gap:1.5rem !important}.row-gap-5{row-gap:3rem !important}.column-gap-0{column-gap:0 !important}.column-gap-1{column-gap:.25rem !important}.column-gap-2{column-gap:.5rem !important}.column-gap-3{column-gap:1rem !important}.column-gap-4{column-gap:1.5rem !important}.column-gap-5{column-gap:3rem !important}.font-monospace{font-family:var(--bs-font-monospace) !important}.fs-1{font-size:calc(1.325rem + 0.9vw) !important}.fs-2{font-size:calc(1.29rem + 0.48vw) !important}.fs-3{font-size:calc(1.27rem + 0.24vw) !important}.fs-4{font-size:1.25rem !important}.fs-5{font-size:1.1rem !important}.fs-6{font-size:1rem !important}.fst-italic{font-style:italic !important}.fst-normal{font-style:normal !important}.fw-lighter{font-weight:lighter !important}.fw-light{font-weight:300 !important}.fw-normal{font-weight:400 !important}.fw-medium{font-weight:500 !important}.fw-semibold{font-weight:600 !important}.fw-bold{font-weight:700 !important}.fw-bolder{font-weight:bolder !important}.lh-1{line-height:1 !important}.lh-sm{line-height:1.25 !important}.lh-base{line-height:1.5 !important}.lh-lg{line-height:2 !important}.text-start{text-align:left !important}.text-end{text-align:right !important}.text-center{text-align:center !important}.text-decoration-none{text-decoration:none !important}.text-decoration-underline{text-decoration:underline !important}.text-decoration-line-through{text-decoration:line-through !important}.text-lowercase{text-transform:lowercase !important}.text-uppercase{text-transform:uppercase !important}.text-capitalize{text-transform:capitalize !important}.text-wrap{white-space:normal !important}.text-nowrap{white-space:nowrap !important}.text-break{word-wrap:break-word !important;word-break:break-word !important}.text-default{--bs-text-opacity: 1;color:rgba(var(--bs-default-rgb), var(--bs-text-opacity)) !important}.text-primary{--bs-text-opacity: 1;color:rgba(var(--bs-primary-rgb), var(--bs-text-opacity)) !important}.text-secondary{--bs-text-opacity: 1;color:rgba(var(--bs-secondary-rgb), var(--bs-text-opacity)) !important}.text-success{--bs-text-opacity: 1;color:rgba(var(--bs-success-rgb), var(--bs-text-opacity)) !important}.text-info{--bs-text-opacity: 1;color:rgba(var(--bs-info-rgb), var(--bs-text-opacity)) !important}.text-warning{--bs-text-opacity: 1;color:rgba(var(--bs-warning-rgb), var(--bs-text-opacity)) !important}.text-danger{--bs-text-opacity: 1;color:rgba(var(--bs-danger-rgb), var(--bs-text-opacity)) !important}.text-light{--bs-text-opacity: 1;color:rgba(var(--bs-light-rgb), var(--bs-text-opacity)) !important}.text-dark{--bs-text-opacity: 1;color:rgba(var(--bs-dark-rgb), var(--bs-text-opacity)) !important}.text-black{--bs-text-opacity: 1;color:rgba(var(--bs-black-rgb), var(--bs-text-opacity)) !important}.text-white{--bs-text-opacity: 1;color:rgba(var(--bs-white-rgb), var(--bs-text-opacity)) !important}.text-body{--bs-text-opacity: 1;color:rgba(var(--bs-body-color-rgb), var(--bs-text-opacity)) !important}.text-muted{--bs-text-opacity: 1;color:var(--bs-secondary-color) !important}.text-black-50{--bs-text-opacity: 1;color:rgba(0,0,0,.5) !important}.text-white-50{--bs-text-opacity: 1;color:rgba(255,255,255,.5) !important}.text-body-secondary{--bs-text-opacity: 1;color:var(--bs-secondary-color) !important}.text-body-tertiary{--bs-text-opacity: 1;color:var(--bs-tertiary-color) !important}.text-body-emphasis{--bs-text-opacity: 1;color:var(--bs-emphasis-color) !important}.text-reset{--bs-text-opacity: 1;color:inherit !important}.text-opacity-25{--bs-text-opacity: 0.25}.text-opacity-50{--bs-text-opacity: 0.5}.text-opacity-75{--bs-text-opacity: 0.75}.text-opacity-100{--bs-text-opacity: 1}.text-primary-emphasis{color:var(--bs-primary-text-emphasis) !important}.text-secondary-emphasis{color:var(--bs-secondary-text-emphasis) !important}.text-success-emphasis{color:var(--bs-success-text-emphasis) !important}.text-info-emphasis{color:var(--bs-info-text-emphasis) !important}.text-warning-emphasis{color:var(--bs-warning-text-emphasis) !important}.text-danger-emphasis{color:var(--bs-danger-text-emphasis) !important}.text-light-emphasis{color:var(--bs-light-text-emphasis) !important}.text-dark-emphasis{color:var(--bs-dark-text-emphasis) !important}.link-opacity-10{--bs-link-opacity: 0.1}.link-opacity-10-hover:hover{--bs-link-opacity: 0.1}.link-opacity-25{--bs-link-opacity: 0.25}.link-opacity-25-hover:hover{--bs-link-opacity: 0.25}.link-opacity-50{--bs-link-opacity: 0.5}.link-opacity-50-hover:hover{--bs-link-opacity: 0.5}.link-opacity-75{--bs-link-opacity: 0.75}.link-opacity-75-hover:hover{--bs-link-opacity: 0.75}.link-opacity-100{--bs-link-opacity: 1}.link-opacity-100-hover:hover{--bs-link-opacity: 1}.link-offset-1{text-underline-offset:.125em !important}.link-offset-1-hover:hover{text-underline-offset:.125em !important}.link-offset-2{text-underline-offset:.25em !important}.link-offset-2-hover:hover{text-underline-offset:.25em !important}.link-offset-3{text-underline-offset:.375em !important}.link-offset-3-hover:hover{text-underline-offset:.375em !important}.link-underline-default{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-default-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-primary{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-primary-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-secondary{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-secondary-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-success{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-success-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-info{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-info-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-warning{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-warning-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-danger{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-danger-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-light{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-light-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-dark{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-dark-rgb), var(--bs-link-underline-opacity)) !important}.link-underline{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-link-color-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-underline-opacity-0{--bs-link-underline-opacity: 0}.link-underline-opacity-0-hover:hover{--bs-link-underline-opacity: 0}.link-underline-opacity-10{--bs-link-underline-opacity: 0.1}.link-underline-opacity-10-hover:hover{--bs-link-underline-opacity: 0.1}.link-underline-opacity-25{--bs-link-underline-opacity: 0.25}.link-underline-opacity-25-hover:hover{--bs-link-underline-opacity: 0.25}.link-underline-opacity-50{--bs-link-underline-opacity: 0.5}.link-underline-opacity-50-hover:hover{--bs-link-underline-opacity: 0.5}.link-underline-opacity-75{--bs-link-underline-opacity: 0.75}.link-underline-opacity-75-hover:hover{--bs-link-underline-opacity: 0.75}.link-underline-opacity-100{--bs-link-underline-opacity: 1}.link-underline-opacity-100-hover:hover{--bs-link-underline-opacity: 1}.bg-default{--bs-bg-opacity: 1;background-color:rgba(var(--bs-default-rgb), var(--bs-bg-opacity)) !important}.bg-primary{--bs-bg-opacity: 1;background-color:rgba(var(--bs-primary-rgb), var(--bs-bg-opacity)) !important}.bg-secondary{--bs-bg-opacity: 1;background-color:rgba(var(--bs-secondary-rgb), var(--bs-bg-opacity)) !important}.bg-success{--bs-bg-opacity: 1;background-color:rgba(var(--bs-success-rgb), var(--bs-bg-opacity)) !important}.bg-info{--bs-bg-opacity: 1;background-color:rgba(var(--bs-info-rgb), var(--bs-bg-opacity)) !important}.bg-warning{--bs-bg-opacity: 1;background-color:rgba(var(--bs-warning-rgb), var(--bs-bg-opacity)) !important}.bg-danger{--bs-bg-opacity: 1;background-color:rgba(var(--bs-danger-rgb), var(--bs-bg-opacity)) !important}.bg-light{--bs-bg-opacity: 1;background-color:rgba(var(--bs-light-rgb), var(--bs-bg-opacity)) !important}.bg-dark{--bs-bg-opacity: 1;background-color:rgba(var(--bs-dark-rgb), var(--bs-bg-opacity)) !important}.bg-black{--bs-bg-opacity: 1;background-color:rgba(var(--bs-black-rgb), var(--bs-bg-opacity)) !important}.bg-white{--bs-bg-opacity: 1;background-color:rgba(var(--bs-white-rgb), var(--bs-bg-opacity)) !important}.bg-body{--bs-bg-opacity: 1;background-color:rgba(var(--bs-body-bg-rgb), var(--bs-bg-opacity)) !important}.bg-transparent{--bs-bg-opacity: 1;background-color:rgba(0,0,0,0) !important}.bg-body-secondary{--bs-bg-opacity: 1;background-color:rgba(var(--bs-secondary-bg-rgb), var(--bs-bg-opacity)) !important}.bg-body-tertiary{--bs-bg-opacity: 1;background-color:rgba(var(--bs-tertiary-bg-rgb), var(--bs-bg-opacity)) !important}.bg-opacity-10{--bs-bg-opacity: 0.1}.bg-opacity-25{--bs-bg-opacity: 0.25}.bg-opacity-50{--bs-bg-opacity: 0.5}.bg-opacity-75{--bs-bg-opacity: 0.75}.bg-opacity-100{--bs-bg-opacity: 1}.bg-primary-subtle{background-color:var(--bs-primary-bg-subtle) !important}.bg-secondary-subtle{background-color:var(--bs-secondary-bg-subtle) !important}.bg-success-subtle{background-color:var(--bs-success-bg-subtle) !important}.bg-info-subtle{background-color:var(--bs-info-bg-subtle) !important}.bg-warning-subtle{background-color:var(--bs-warning-bg-subtle) !important}.bg-danger-subtle{background-color:var(--bs-danger-bg-subtle) !important}.bg-light-subtle{background-color:var(--bs-light-bg-subtle) !important}.bg-dark-subtle{background-color:var(--bs-dark-bg-subtle) !important}.bg-gradient{background-image:var(--bs-gradient) !important}.user-select-all{user-select:all !important}.user-select-auto{user-select:auto !important}.user-select-none{user-select:none !important}.pe-none{pointer-events:none !important}.pe-auto{pointer-events:auto !important}.rounded{border-radius:var(--bs-border-radius) !important}.rounded-0{border-radius:0 !important}.rounded-1{border-radius:var(--bs-border-radius-sm) !important}.rounded-2{border-radius:var(--bs-border-radius) !important}.rounded-3{border-radius:var(--bs-border-radius-lg) !important}.rounded-4{border-radius:var(--bs-border-radius-xl) !important}.rounded-5{border-radius:var(--bs-border-radius-xxl) !important}.rounded-circle{border-radius:50% !important}.rounded-pill{border-radius:var(--bs-border-radius-pill) !important}.rounded-top{border-top-left-radius:var(--bs-border-radius) !important;border-top-right-radius:var(--bs-border-radius) !important}.rounded-top-0{border-top-left-radius:0 !important;border-top-right-radius:0 !important}.rounded-top-1{border-top-left-radius:var(--bs-border-radius-sm) !important;border-top-right-radius:var(--bs-border-radius-sm) !important}.rounded-top-2{border-top-left-radius:var(--bs-border-radius) !important;border-top-right-radius:var(--bs-border-radius) !important}.rounded-top-3{border-top-left-radius:var(--bs-border-radius-lg) !important;border-top-right-radius:var(--bs-border-radius-lg) !important}.rounded-top-4{border-top-left-radius:var(--bs-border-radius-xl) !important;border-top-right-radius:var(--bs-border-radius-xl) !important}.rounded-top-5{border-top-left-radius:var(--bs-border-radius-xxl) !important;border-top-right-radius:var(--bs-border-radius-xxl) !important}.rounded-top-circle{border-top-left-radius:50% !important;border-top-right-radius:50% !important}.rounded-top-pill{border-top-left-radius:var(--bs-border-radius-pill) !important;border-top-right-radius:var(--bs-border-radius-pill) !important}.rounded-end{border-top-right-radius:var(--bs-border-radius) !important;border-bottom-right-radius:var(--bs-border-radius) !important}.rounded-end-0{border-top-right-radius:0 !important;border-bottom-right-radius:0 !important}.rounded-end-1{border-top-right-radius:var(--bs-border-radius-sm) !important;border-bottom-right-radius:var(--bs-border-radius-sm) !important}.rounded-end-2{border-top-right-radius:var(--bs-border-radius) !important;border-bottom-right-radius:var(--bs-border-radius) !important}.rounded-end-3{border-top-right-radius:var(--bs-border-radius-lg) !important;border-bottom-right-radius:var(--bs-border-radius-lg) !important}.rounded-end-4{border-top-right-radius:var(--bs-border-radius-xl) !important;border-bottom-right-radius:var(--bs-border-radius-xl) !important}.rounded-end-5{border-top-right-radius:var(--bs-border-radius-xxl) !important;border-bottom-right-radius:var(--bs-border-radius-xxl) !important}.rounded-end-circle{border-top-right-radius:50% !important;border-bottom-right-radius:50% !important}.rounded-end-pill{border-top-right-radius:var(--bs-border-radius-pill) !important;border-bottom-right-radius:var(--bs-border-radius-pill) !important}.rounded-bottom{border-bottom-right-radius:var(--bs-border-radius) !important;border-bottom-left-radius:var(--bs-border-radius) !important}.rounded-bottom-0{border-bottom-right-radius:0 !important;border-bottom-left-radius:0 !important}.rounded-bottom-1{border-bottom-right-radius:var(--bs-border-radius-sm) !important;border-bottom-left-radius:var(--bs-border-radius-sm) !important}.rounded-bottom-2{border-bottom-right-radius:var(--bs-border-radius) !important;border-bottom-left-radius:var(--bs-border-radius) !important}.rounded-bottom-3{border-bottom-right-radius:var(--bs-border-radius-lg) !important;border-bottom-left-radius:var(--bs-border-radius-lg) !important}.rounded-bottom-4{border-bottom-right-radius:var(--bs-border-radius-xl) !important;border-bottom-left-radius:var(--bs-border-radius-xl) !important}.rounded-bottom-5{border-bottom-right-radius:var(--bs-border-radius-xxl) !important;border-bottom-left-radius:var(--bs-border-radius-xxl) !important}.rounded-bottom-circle{border-bottom-right-radius:50% !important;border-bottom-left-radius:50% !important}.rounded-bottom-pill{border-bottom-right-radius:var(--bs-border-radius-pill) !important;border-bottom-left-radius:var(--bs-border-radius-pill) !important}.rounded-start{border-bottom-left-radius:var(--bs-border-radius) !important;border-top-left-radius:var(--bs-border-radius) !important}.rounded-start-0{border-bottom-left-radius:0 !important;border-top-left-radius:0 !important}.rounded-start-1{border-bottom-left-radius:var(--bs-border-radius-sm) !important;border-top-left-radius:var(--bs-border-radius-sm) !important}.rounded-start-2{border-bottom-left-radius:var(--bs-border-radius) !important;border-top-left-radius:var(--bs-border-radius) !important}.rounded-start-3{border-bottom-left-radius:var(--bs-border-radius-lg) !important;border-top-left-radius:var(--bs-border-radius-lg) !important}.rounded-start-4{border-bottom-left-radius:var(--bs-border-radius-xl) !important;border-top-left-radius:var(--bs-border-radius-xl) !important}.rounded-start-5{border-bottom-left-radius:var(--bs-border-radius-xxl) !important;border-top-left-radius:var(--bs-border-radius-xxl) !important}.rounded-start-circle{border-bottom-left-radius:50% !important;border-top-left-radius:50% !important}.rounded-start-pill{border-bottom-left-radius:var(--bs-border-radius-pill) !important;border-top-left-radius:var(--bs-border-radius-pill) !important}.visible{visibility:visible !important}.invisible{visibility:hidden !important}.z-n1{z-index:-1 !important}.z-0{z-index:0 !important}.z-1{z-index:1 !important}.z-2{z-index:2 !important}.z-3{z-index:3 !important}@media(min-width: 576px){.float-sm-start{float:left !important}.float-sm-end{float:right !important}.float-sm-none{float:none !important}.object-fit-sm-contain{object-fit:contain !important}.object-fit-sm-cover{object-fit:cover !important}.object-fit-sm-fill{object-fit:fill !important}.object-fit-sm-scale{object-fit:scale-down !important}.object-fit-sm-none{object-fit:none !important}.d-sm-inline{display:inline !important}.d-sm-inline-block{display:inline-block !important}.d-sm-block{display:block !important}.d-sm-grid{display:grid !important}.d-sm-inline-grid{display:inline-grid !important}.d-sm-table{display:table !important}.d-sm-table-row{display:table-row !important}.d-sm-table-cell{display:table-cell !important}.d-sm-flex{display:flex !important}.d-sm-inline-flex{display:inline-flex !important}.d-sm-none{display:none !important}.flex-sm-fill{flex:1 1 auto !important}.flex-sm-row{flex-direction:row !important}.flex-sm-column{flex-direction:column !important}.flex-sm-row-reverse{flex-direction:row-reverse !important}.flex-sm-column-reverse{flex-direction:column-reverse !important}.flex-sm-grow-0{flex-grow:0 !important}.flex-sm-grow-1{flex-grow:1 !important}.flex-sm-shrink-0{flex-shrink:0 !important}.flex-sm-shrink-1{flex-shrink:1 !important}.flex-sm-wrap{flex-wrap:wrap !important}.flex-sm-nowrap{flex-wrap:nowrap !important}.flex-sm-wrap-reverse{flex-wrap:wrap-reverse !important}.justify-content-sm-start{justify-content:flex-start !important}.justify-content-sm-end{justify-content:flex-end !important}.justify-content-sm-center{justify-content:center !important}.justify-content-sm-between{justify-content:space-between !important}.justify-content-sm-around{justify-content:space-around !important}.justify-content-sm-evenly{justify-content:space-evenly !important}.align-items-sm-start{align-items:flex-start !important}.align-items-sm-end{align-items:flex-end !important}.align-items-sm-center{align-items:center !important}.align-items-sm-baseline{align-items:baseline !important}.align-items-sm-stretch{align-items:stretch !important}.align-content-sm-start{align-content:flex-start !important}.align-content-sm-end{align-content:flex-end !important}.align-content-sm-center{align-content:center !important}.align-content-sm-between{align-content:space-between !important}.align-content-sm-around{align-content:space-around !important}.align-content-sm-stretch{align-content:stretch !important}.align-self-sm-auto{align-self:auto !important}.align-self-sm-start{align-self:flex-start !important}.align-self-sm-end{align-self:flex-end !important}.align-self-sm-center{align-self:center !important}.align-self-sm-baseline{align-self:baseline !important}.align-self-sm-stretch{align-self:stretch !important}.order-sm-first{order:-1 !important}.order-sm-0{order:0 !important}.order-sm-1{order:1 !important}.order-sm-2{order:2 !important}.order-sm-3{order:3 !important}.order-sm-4{order:4 !important}.order-sm-5{order:5 !important}.order-sm-last{order:6 !important}.m-sm-0{margin:0 !important}.m-sm-1{margin:.25rem !important}.m-sm-2{margin:.5rem !important}.m-sm-3{margin:1rem !important}.m-sm-4{margin:1.5rem !important}.m-sm-5{margin:3rem !important}.m-sm-auto{margin:auto !important}.mx-sm-0{margin-right:0 !important;margin-left:0 !important}.mx-sm-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-sm-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-sm-3{margin-right:1rem !important;margin-left:1rem !important}.mx-sm-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-sm-5{margin-right:3rem !important;margin-left:3rem !important}.mx-sm-auto{margin-right:auto !important;margin-left:auto !important}.my-sm-0{margin-top:0 !important;margin-bottom:0 !important}.my-sm-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-sm-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-sm-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-sm-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-sm-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-sm-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-sm-0{margin-top:0 !important}.mt-sm-1{margin-top:.25rem !important}.mt-sm-2{margin-top:.5rem !important}.mt-sm-3{margin-top:1rem !important}.mt-sm-4{margin-top:1.5rem !important}.mt-sm-5{margin-top:3rem !important}.mt-sm-auto{margin-top:auto !important}.me-sm-0{margin-right:0 !important}.me-sm-1{margin-right:.25rem !important}.me-sm-2{margin-right:.5rem !important}.me-sm-3{margin-right:1rem !important}.me-sm-4{margin-right:1.5rem !important}.me-sm-5{margin-right:3rem !important}.me-sm-auto{margin-right:auto !important}.mb-sm-0{margin-bottom:0 !important}.mb-sm-1{margin-bottom:.25rem !important}.mb-sm-2{margin-bottom:.5rem !important}.mb-sm-3{margin-bottom:1rem !important}.mb-sm-4{margin-bottom:1.5rem !important}.mb-sm-5{margin-bottom:3rem !important}.mb-sm-auto{margin-bottom:auto !important}.ms-sm-0{margin-left:0 !important}.ms-sm-1{margin-left:.25rem !important}.ms-sm-2{margin-left:.5rem !important}.ms-sm-3{margin-left:1rem !important}.ms-sm-4{margin-left:1.5rem !important}.ms-sm-5{margin-left:3rem !important}.ms-sm-auto{margin-left:auto !important}.p-sm-0{padding:0 !important}.p-sm-1{padding:.25rem !important}.p-sm-2{padding:.5rem !important}.p-sm-3{padding:1rem !important}.p-sm-4{padding:1.5rem !important}.p-sm-5{padding:3rem !important}.px-sm-0{padding-right:0 !important;padding-left:0 !important}.px-sm-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-sm-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-sm-3{padding-right:1rem !important;padding-left:1rem !important}.px-sm-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-sm-5{padding-right:3rem !important;padding-left:3rem !important}.py-sm-0{padding-top:0 !important;padding-bottom:0 !important}.py-sm-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-sm-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-sm-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-sm-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-sm-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-sm-0{padding-top:0 !important}.pt-sm-1{padding-top:.25rem !important}.pt-sm-2{padding-top:.5rem !important}.pt-sm-3{padding-top:1rem !important}.pt-sm-4{padding-top:1.5rem !important}.pt-sm-5{padding-top:3rem !important}.pe-sm-0{padding-right:0 !important}.pe-sm-1{padding-right:.25rem !important}.pe-sm-2{padding-right:.5rem !important}.pe-sm-3{padding-right:1rem !important}.pe-sm-4{padding-right:1.5rem !important}.pe-sm-5{padding-right:3rem !important}.pb-sm-0{padding-bottom:0 !important}.pb-sm-1{padding-bottom:.25rem !important}.pb-sm-2{padding-bottom:.5rem !important}.pb-sm-3{padding-bottom:1rem !important}.pb-sm-4{padding-bottom:1.5rem !important}.pb-sm-5{padding-bottom:3rem !important}.ps-sm-0{padding-left:0 !important}.ps-sm-1{padding-left:.25rem !important}.ps-sm-2{padding-left:.5rem !important}.ps-sm-3{padding-left:1rem !important}.ps-sm-4{padding-left:1.5rem !important}.ps-sm-5{padding-left:3rem !important}.gap-sm-0{gap:0 !important}.gap-sm-1{gap:.25rem !important}.gap-sm-2{gap:.5rem !important}.gap-sm-3{gap:1rem !important}.gap-sm-4{gap:1.5rem !important}.gap-sm-5{gap:3rem !important}.row-gap-sm-0{row-gap:0 !important}.row-gap-sm-1{row-gap:.25rem !important}.row-gap-sm-2{row-gap:.5rem !important}.row-gap-sm-3{row-gap:1rem !important}.row-gap-sm-4{row-gap:1.5rem !important}.row-gap-sm-5{row-gap:3rem !important}.column-gap-sm-0{column-gap:0 !important}.column-gap-sm-1{column-gap:.25rem !important}.column-gap-sm-2{column-gap:.5rem !important}.column-gap-sm-3{column-gap:1rem !important}.column-gap-sm-4{column-gap:1.5rem !important}.column-gap-sm-5{column-gap:3rem !important}.text-sm-start{text-align:left !important}.text-sm-end{text-align:right !important}.text-sm-center{text-align:center !important}}@media(min-width: 768px){.float-md-start{float:left !important}.float-md-end{float:right !important}.float-md-none{float:none !important}.object-fit-md-contain{object-fit:contain !important}.object-fit-md-cover{object-fit:cover !important}.object-fit-md-fill{object-fit:fill !important}.object-fit-md-scale{object-fit:scale-down !important}.object-fit-md-none{object-fit:none !important}.d-md-inline{display:inline !important}.d-md-inline-block{display:inline-block !important}.d-md-block{display:block !important}.d-md-grid{display:grid !important}.d-md-inline-grid{display:inline-grid !important}.d-md-table{display:table !important}.d-md-table-row{display:table-row !important}.d-md-table-cell{display:table-cell !important}.d-md-flex{display:flex !important}.d-md-inline-flex{display:inline-flex !important}.d-md-none{display:none !important}.flex-md-fill{flex:1 1 auto !important}.flex-md-row{flex-direction:row !important}.flex-md-column{flex-direction:column !important}.flex-md-row-reverse{flex-direction:row-reverse !important}.flex-md-column-reverse{flex-direction:column-reverse !important}.flex-md-grow-0{flex-grow:0 !important}.flex-md-grow-1{flex-grow:1 !important}.flex-md-shrink-0{flex-shrink:0 !important}.flex-md-shrink-1{flex-shrink:1 !important}.flex-md-wrap{flex-wrap:wrap !important}.flex-md-nowrap{flex-wrap:nowrap !important}.flex-md-wrap-reverse{flex-wrap:wrap-reverse !important}.justify-content-md-start{justify-content:flex-start !important}.justify-content-md-end{justify-content:flex-end !important}.justify-content-md-center{justify-content:center !important}.justify-content-md-between{justify-content:space-between !important}.justify-content-md-around{justify-content:space-around !important}.justify-content-md-evenly{justify-content:space-evenly !important}.align-items-md-start{align-items:flex-start !important}.align-items-md-end{align-items:flex-end !important}.align-items-md-center{align-items:center !important}.align-items-md-baseline{align-items:baseline !important}.align-items-md-stretch{align-items:stretch !important}.align-content-md-start{align-content:flex-start !important}.align-content-md-end{align-content:flex-end !important}.align-content-md-center{align-content:center !important}.align-content-md-between{align-content:space-between !important}.align-content-md-around{align-content:space-around !important}.align-content-md-stretch{align-content:stretch !important}.align-self-md-auto{align-self:auto !important}.align-self-md-start{align-self:flex-start !important}.align-self-md-end{align-self:flex-end !important}.align-self-md-center{align-self:center !important}.align-self-md-baseline{align-self:baseline !important}.align-self-md-stretch{align-self:stretch !important}.order-md-first{order:-1 !important}.order-md-0{order:0 !important}.order-md-1{order:1 !important}.order-md-2{order:2 !important}.order-md-3{order:3 !important}.order-md-4{order:4 !important}.order-md-5{order:5 !important}.order-md-last{order:6 !important}.m-md-0{margin:0 !important}.m-md-1{margin:.25rem !important}.m-md-2{margin:.5rem !important}.m-md-3{margin:1rem !important}.m-md-4{margin:1.5rem !important}.m-md-5{margin:3rem !important}.m-md-auto{margin:auto !important}.mx-md-0{margin-right:0 !important;margin-left:0 !important}.mx-md-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-md-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-md-3{margin-right:1rem !important;margin-left:1rem !important}.mx-md-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-md-5{margin-right:3rem !important;margin-left:3rem !important}.mx-md-auto{margin-right:auto !important;margin-left:auto !important}.my-md-0{margin-top:0 !important;margin-bottom:0 !important}.my-md-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-md-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-md-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-md-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-md-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-md-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-md-0{margin-top:0 !important}.mt-md-1{margin-top:.25rem !important}.mt-md-2{margin-top:.5rem !important}.mt-md-3{margin-top:1rem !important}.mt-md-4{margin-top:1.5rem !important}.mt-md-5{margin-top:3rem !important}.mt-md-auto{margin-top:auto !important}.me-md-0{margin-right:0 !important}.me-md-1{margin-right:.25rem !important}.me-md-2{margin-right:.5rem !important}.me-md-3{margin-right:1rem !important}.me-md-4{margin-right:1.5rem !important}.me-md-5{margin-right:3rem !important}.me-md-auto{margin-right:auto !important}.mb-md-0{margin-bottom:0 !important}.mb-md-1{margin-bottom:.25rem !important}.mb-md-2{margin-bottom:.5rem !important}.mb-md-3{margin-bottom:1rem !important}.mb-md-4{margin-bottom:1.5rem !important}.mb-md-5{margin-bottom:3rem !important}.mb-md-auto{margin-bottom:auto !important}.ms-md-0{margin-left:0 !important}.ms-md-1{margin-left:.25rem !important}.ms-md-2{margin-left:.5rem !important}.ms-md-3{margin-left:1rem !important}.ms-md-4{margin-left:1.5rem !important}.ms-md-5{margin-left:3rem !important}.ms-md-auto{margin-left:auto !important}.p-md-0{padding:0 !important}.p-md-1{padding:.25rem !important}.p-md-2{padding:.5rem !important}.p-md-3{padding:1rem !important}.p-md-4{padding:1.5rem !important}.p-md-5{padding:3rem !important}.px-md-0{padding-right:0 !important;padding-left:0 !important}.px-md-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-md-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-md-3{padding-right:1rem !important;padding-left:1rem !important}.px-md-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-md-5{padding-right:3rem !important;padding-left:3rem !important}.py-md-0{padding-top:0 !important;padding-bottom:0 !important}.py-md-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-md-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-md-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-md-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-md-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-md-0{padding-top:0 !important}.pt-md-1{padding-top:.25rem !important}.pt-md-2{padding-top:.5rem !important}.pt-md-3{padding-top:1rem !important}.pt-md-4{padding-top:1.5rem !important}.pt-md-5{padding-top:3rem !important}.pe-md-0{padding-right:0 !important}.pe-md-1{padding-right:.25rem !important}.pe-md-2{padding-right:.5rem !important}.pe-md-3{padding-right:1rem !important}.pe-md-4{padding-right:1.5rem !important}.pe-md-5{padding-right:3rem !important}.pb-md-0{padding-bottom:0 !important}.pb-md-1{padding-bottom:.25rem !important}.pb-md-2{padding-bottom:.5rem !important}.pb-md-3{padding-bottom:1rem !important}.pb-md-4{padding-bottom:1.5rem !important}.pb-md-5{padding-bottom:3rem !important}.ps-md-0{padding-left:0 !important}.ps-md-1{padding-left:.25rem !important}.ps-md-2{padding-left:.5rem !important}.ps-md-3{padding-left:1rem !important}.ps-md-4{padding-left:1.5rem !important}.ps-md-5{padding-left:3rem !important}.gap-md-0{gap:0 !important}.gap-md-1{gap:.25rem !important}.gap-md-2{gap:.5rem !important}.gap-md-3{gap:1rem !important}.gap-md-4{gap:1.5rem !important}.gap-md-5{gap:3rem !important}.row-gap-md-0{row-gap:0 !important}.row-gap-md-1{row-gap:.25rem !important}.row-gap-md-2{row-gap:.5rem !important}.row-gap-md-3{row-gap:1rem !important}.row-gap-md-4{row-gap:1.5rem !important}.row-gap-md-5{row-gap:3rem !important}.column-gap-md-0{column-gap:0 !important}.column-gap-md-1{column-gap:.25rem !important}.column-gap-md-2{column-gap:.5rem !important}.column-gap-md-3{column-gap:1rem !important}.column-gap-md-4{column-gap:1.5rem !important}.column-gap-md-5{column-gap:3rem !important}.text-md-start{text-align:left !important}.text-md-end{text-align:right !important}.text-md-center{text-align:center !important}}@media(min-width: 992px){.float-lg-start{float:left !important}.float-lg-end{float:right !important}.float-lg-none{float:none !important}.object-fit-lg-contain{object-fit:contain !important}.object-fit-lg-cover{object-fit:cover !important}.object-fit-lg-fill{object-fit:fill !important}.object-fit-lg-scale{object-fit:scale-down !important}.object-fit-lg-none{object-fit:none !important}.d-lg-inline{display:inline !important}.d-lg-inline-block{display:inline-block !important}.d-lg-block{display:block !important}.d-lg-grid{display:grid !important}.d-lg-inline-grid{display:inline-grid !important}.d-lg-table{display:table !important}.d-lg-table-row{display:table-row !important}.d-lg-table-cell{display:table-cell !important}.d-lg-flex{display:flex !important}.d-lg-inline-flex{display:inline-flex !important}.d-lg-none{display:none !important}.flex-lg-fill{flex:1 1 auto !important}.flex-lg-row{flex-direction:row !important}.flex-lg-column{flex-direction:column !important}.flex-lg-row-reverse{flex-direction:row-reverse !important}.flex-lg-column-reverse{flex-direction:column-reverse !important}.flex-lg-grow-0{flex-grow:0 !important}.flex-lg-grow-1{flex-grow:1 !important}.flex-lg-shrink-0{flex-shrink:0 !important}.flex-lg-shrink-1{flex-shrink:1 !important}.flex-lg-wrap{flex-wrap:wrap !important}.flex-lg-nowrap{flex-wrap:nowrap !important}.flex-lg-wrap-reverse{flex-wrap:wrap-reverse !important}.justify-content-lg-start{justify-content:flex-start !important}.justify-content-lg-end{justify-content:flex-end !important}.justify-content-lg-center{justify-content:center !important}.justify-content-lg-between{justify-content:space-between !important}.justify-content-lg-around{justify-content:space-around !important}.justify-content-lg-evenly{justify-content:space-evenly !important}.align-items-lg-start{align-items:flex-start !important}.align-items-lg-end{align-items:flex-end !important}.align-items-lg-center{align-items:center !important}.align-items-lg-baseline{align-items:baseline !important}.align-items-lg-stretch{align-items:stretch !important}.align-content-lg-start{align-content:flex-start !important}.align-content-lg-end{align-content:flex-end !important}.align-content-lg-center{align-content:center !important}.align-content-lg-between{align-content:space-between !important}.align-content-lg-around{align-content:space-around !important}.align-content-lg-stretch{align-content:stretch !important}.align-self-lg-auto{align-self:auto !important}.align-self-lg-start{align-self:flex-start !important}.align-self-lg-end{align-self:flex-end !important}.align-self-lg-center{align-self:center !important}.align-self-lg-baseline{align-self:baseline !important}.align-self-lg-stretch{align-self:stretch !important}.order-lg-first{order:-1 !important}.order-lg-0{order:0 !important}.order-lg-1{order:1 !important}.order-lg-2{order:2 !important}.order-lg-3{order:3 !important}.order-lg-4{order:4 !important}.order-lg-5{order:5 !important}.order-lg-last{order:6 !important}.m-lg-0{margin:0 !important}.m-lg-1{margin:.25rem !important}.m-lg-2{margin:.5rem !important}.m-lg-3{margin:1rem !important}.m-lg-4{margin:1.5rem !important}.m-lg-5{margin:3rem !important}.m-lg-auto{margin:auto !important}.mx-lg-0{margin-right:0 !important;margin-left:0 !important}.mx-lg-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-lg-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-lg-3{margin-right:1rem !important;margin-left:1rem !important}.mx-lg-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-lg-5{margin-right:3rem !important;margin-left:3rem !important}.mx-lg-auto{margin-right:auto !important;margin-left:auto !important}.my-lg-0{margin-top:0 !important;margin-bottom:0 !important}.my-lg-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-lg-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-lg-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-lg-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-lg-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-lg-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-lg-0{margin-top:0 !important}.mt-lg-1{margin-top:.25rem !important}.mt-lg-2{margin-top:.5rem !important}.mt-lg-3{margin-top:1rem !important}.mt-lg-4{margin-top:1.5rem !important}.mt-lg-5{margin-top:3rem !important}.mt-lg-auto{margin-top:auto !important}.me-lg-0{margin-right:0 !important}.me-lg-1{margin-right:.25rem !important}.me-lg-2{margin-right:.5rem !important}.me-lg-3{margin-right:1rem !important}.me-lg-4{margin-right:1.5rem !important}.me-lg-5{margin-right:3rem !important}.me-lg-auto{margin-right:auto !important}.mb-lg-0{margin-bottom:0 !important}.mb-lg-1{margin-bottom:.25rem !important}.mb-lg-2{margin-bottom:.5rem !important}.mb-lg-3{margin-bottom:1rem !important}.mb-lg-4{margin-bottom:1.5rem !important}.mb-lg-5{margin-bottom:3rem !important}.mb-lg-auto{margin-bottom:auto !important}.ms-lg-0{margin-left:0 !important}.ms-lg-1{margin-left:.25rem !important}.ms-lg-2{margin-left:.5rem !important}.ms-lg-3{margin-left:1rem !important}.ms-lg-4{margin-left:1.5rem !important}.ms-lg-5{margin-left:3rem !important}.ms-lg-auto{margin-left:auto !important}.p-lg-0{padding:0 !important}.p-lg-1{padding:.25rem !important}.p-lg-2{padding:.5rem !important}.p-lg-3{padding:1rem !important}.p-lg-4{padding:1.5rem !important}.p-lg-5{padding:3rem !important}.px-lg-0{padding-right:0 !important;padding-left:0 !important}.px-lg-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-lg-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-lg-3{padding-right:1rem !important;padding-left:1rem !important}.px-lg-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-lg-5{padding-right:3rem !important;padding-left:3rem !important}.py-lg-0{padding-top:0 !important;padding-bottom:0 !important}.py-lg-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-lg-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-lg-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-lg-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-lg-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-lg-0{padding-top:0 !important}.pt-lg-1{padding-top:.25rem !important}.pt-lg-2{padding-top:.5rem !important}.pt-lg-3{padding-top:1rem !important}.pt-lg-4{padding-top:1.5rem !important}.pt-lg-5{padding-top:3rem !important}.pe-lg-0{padding-right:0 !important}.pe-lg-1{padding-right:.25rem !important}.pe-lg-2{padding-right:.5rem !important}.pe-lg-3{padding-right:1rem !important}.pe-lg-4{padding-right:1.5rem !important}.pe-lg-5{padding-right:3rem !important}.pb-lg-0{padding-bottom:0 !important}.pb-lg-1{padding-bottom:.25rem !important}.pb-lg-2{padding-bottom:.5rem !important}.pb-lg-3{padding-bottom:1rem !important}.pb-lg-4{padding-bottom:1.5rem !important}.pb-lg-5{padding-bottom:3rem !important}.ps-lg-0{padding-left:0 !important}.ps-lg-1{padding-left:.25rem !important}.ps-lg-2{padding-left:.5rem !important}.ps-lg-3{padding-left:1rem !important}.ps-lg-4{padding-left:1.5rem !important}.ps-lg-5{padding-left:3rem !important}.gap-lg-0{gap:0 !important}.gap-lg-1{gap:.25rem !important}.gap-lg-2{gap:.5rem !important}.gap-lg-3{gap:1rem !important}.gap-lg-4{gap:1.5rem !important}.gap-lg-5{gap:3rem !important}.row-gap-lg-0{row-gap:0 !important}.row-gap-lg-1{row-gap:.25rem !important}.row-gap-lg-2{row-gap:.5rem !important}.row-gap-lg-3{row-gap:1rem !important}.row-gap-lg-4{row-gap:1.5rem !important}.row-gap-lg-5{row-gap:3rem !important}.column-gap-lg-0{column-gap:0 !important}.column-gap-lg-1{column-gap:.25rem !important}.column-gap-lg-2{column-gap:.5rem !important}.column-gap-lg-3{column-gap:1rem !important}.column-gap-lg-4{column-gap:1.5rem !important}.column-gap-lg-5{column-gap:3rem !important}.text-lg-start{text-align:left !important}.text-lg-end{text-align:right !important}.text-lg-center{text-align:center !important}}@media(min-width: 1200px){.float-xl-start{float:left !important}.float-xl-end{float:right !important}.float-xl-none{float:none !important}.object-fit-xl-contain{object-fit:contain !important}.object-fit-xl-cover{object-fit:cover !important}.object-fit-xl-fill{object-fit:fill !important}.object-fit-xl-scale{object-fit:scale-down !important}.object-fit-xl-none{object-fit:none !important}.d-xl-inline{display:inline !important}.d-xl-inline-block{display:inline-block !important}.d-xl-block{display:block !important}.d-xl-grid{display:grid !important}.d-xl-inline-grid{display:inline-grid !important}.d-xl-table{display:table !important}.d-xl-table-row{display:table-row !important}.d-xl-table-cell{display:table-cell !important}.d-xl-flex{display:flex !important}.d-xl-inline-flex{display:inline-flex !important}.d-xl-none{display:none !important}.flex-xl-fill{flex:1 1 auto !important}.flex-xl-row{flex-direction:row !important}.flex-xl-column{flex-direction:column !important}.flex-xl-row-reverse{flex-direction:row-reverse !important}.flex-xl-column-reverse{flex-direction:column-reverse !important}.flex-xl-grow-0{flex-grow:0 !important}.flex-xl-grow-1{flex-grow:1 !important}.flex-xl-shrink-0{flex-shrink:0 !important}.flex-xl-shrink-1{flex-shrink:1 !important}.flex-xl-wrap{flex-wrap:wrap !important}.flex-xl-nowrap{flex-wrap:nowrap !important}.flex-xl-wrap-reverse{flex-wrap:wrap-reverse !important}.justify-content-xl-start{justify-content:flex-start !important}.justify-content-xl-end{justify-content:flex-end !important}.justify-content-xl-center{justify-content:center !important}.justify-content-xl-between{justify-content:space-between !important}.justify-content-xl-around{justify-content:space-around !important}.justify-content-xl-evenly{justify-content:space-evenly !important}.align-items-xl-start{align-items:flex-start !important}.align-items-xl-end{align-items:flex-end !important}.align-items-xl-center{align-items:center !important}.align-items-xl-baseline{align-items:baseline !important}.align-items-xl-stretch{align-items:stretch !important}.align-content-xl-start{align-content:flex-start !important}.align-content-xl-end{align-content:flex-end !important}.align-content-xl-center{align-content:center !important}.align-content-xl-between{align-content:space-between !important}.align-content-xl-around{align-content:space-around !important}.align-content-xl-stretch{align-content:stretch !important}.align-self-xl-auto{align-self:auto !important}.align-self-xl-start{align-self:flex-start !important}.align-self-xl-end{align-self:flex-end !important}.align-self-xl-center{align-self:center !important}.align-self-xl-baseline{align-self:baseline !important}.align-self-xl-stretch{align-self:stretch !important}.order-xl-first{order:-1 !important}.order-xl-0{order:0 !important}.order-xl-1{order:1 !important}.order-xl-2{order:2 !important}.order-xl-3{order:3 !important}.order-xl-4{order:4 !important}.order-xl-5{order:5 !important}.order-xl-last{order:6 !important}.m-xl-0{margin:0 !important}.m-xl-1{margin:.25rem !important}.m-xl-2{margin:.5rem !important}.m-xl-3{margin:1rem !important}.m-xl-4{margin:1.5rem !important}.m-xl-5{margin:3rem !important}.m-xl-auto{margin:auto !important}.mx-xl-0{margin-right:0 !important;margin-left:0 !important}.mx-xl-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-xl-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-xl-3{margin-right:1rem !important;margin-left:1rem !important}.mx-xl-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-xl-5{margin-right:3rem !important;margin-left:3rem !important}.mx-xl-auto{margin-right:auto !important;margin-left:auto !important}.my-xl-0{margin-top:0 !important;margin-bottom:0 !important}.my-xl-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-xl-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-xl-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-xl-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-xl-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-xl-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-xl-0{margin-top:0 !important}.mt-xl-1{margin-top:.25rem !important}.mt-xl-2{margin-top:.5rem !important}.mt-xl-3{margin-top:1rem !important}.mt-xl-4{margin-top:1.5rem !important}.mt-xl-5{margin-top:3rem !important}.mt-xl-auto{margin-top:auto !important}.me-xl-0{margin-right:0 !important}.me-xl-1{margin-right:.25rem !important}.me-xl-2{margin-right:.5rem !important}.me-xl-3{margin-right:1rem !important}.me-xl-4{margin-right:1.5rem !important}.me-xl-5{margin-right:3rem !important}.me-xl-auto{margin-right:auto !important}.mb-xl-0{margin-bottom:0 !important}.mb-xl-1{margin-bottom:.25rem !important}.mb-xl-2{margin-bottom:.5rem !important}.mb-xl-3{margin-bottom:1rem !important}.mb-xl-4{margin-bottom:1.5rem !important}.mb-xl-5{margin-bottom:3rem !important}.mb-xl-auto{margin-bottom:auto !important}.ms-xl-0{margin-left:0 !important}.ms-xl-1{margin-left:.25rem !important}.ms-xl-2{margin-left:.5rem !important}.ms-xl-3{margin-left:1rem !important}.ms-xl-4{margin-left:1.5rem !important}.ms-xl-5{margin-left:3rem !important}.ms-xl-auto{margin-left:auto !important}.p-xl-0{padding:0 !important}.p-xl-1{padding:.25rem !important}.p-xl-2{padding:.5rem !important}.p-xl-3{padding:1rem !important}.p-xl-4{padding:1.5rem !important}.p-xl-5{padding:3rem !important}.px-xl-0{padding-right:0 !important;padding-left:0 !important}.px-xl-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-xl-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-xl-3{padding-right:1rem !important;padding-left:1rem !important}.px-xl-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-xl-5{padding-right:3rem !important;padding-left:3rem !important}.py-xl-0{padding-top:0 !important;padding-bottom:0 !important}.py-xl-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-xl-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-xl-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-xl-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-xl-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-xl-0{padding-top:0 !important}.pt-xl-1{padding-top:.25rem !important}.pt-xl-2{padding-top:.5rem !important}.pt-xl-3{padding-top:1rem !important}.pt-xl-4{padding-top:1.5rem !important}.pt-xl-5{padding-top:3rem !important}.pe-xl-0{padding-right:0 !important}.pe-xl-1{padding-right:.25rem !important}.pe-xl-2{padding-right:.5rem !important}.pe-xl-3{padding-right:1rem !important}.pe-xl-4{padding-right:1.5rem !important}.pe-xl-5{padding-right:3rem !important}.pb-xl-0{padding-bottom:0 !important}.pb-xl-1{padding-bottom:.25rem !important}.pb-xl-2{padding-bottom:.5rem !important}.pb-xl-3{padding-bottom:1rem !important}.pb-xl-4{padding-bottom:1.5rem !important}.pb-xl-5{padding-bottom:3rem !important}.ps-xl-0{padding-left:0 !important}.ps-xl-1{padding-left:.25rem !important}.ps-xl-2{padding-left:.5rem !important}.ps-xl-3{padding-left:1rem !important}.ps-xl-4{padding-left:1.5rem !important}.ps-xl-5{padding-left:3rem !important}.gap-xl-0{gap:0 !important}.gap-xl-1{gap:.25rem !important}.gap-xl-2{gap:.5rem !important}.gap-xl-3{gap:1rem !important}.gap-xl-4{gap:1.5rem !important}.gap-xl-5{gap:3rem !important}.row-gap-xl-0{row-gap:0 !important}.row-gap-xl-1{row-gap:.25rem !important}.row-gap-xl-2{row-gap:.5rem !important}.row-gap-xl-3{row-gap:1rem !important}.row-gap-xl-4{row-gap:1.5rem !important}.row-gap-xl-5{row-gap:3rem !important}.column-gap-xl-0{column-gap:0 !important}.column-gap-xl-1{column-gap:.25rem !important}.column-gap-xl-2{column-gap:.5rem !important}.column-gap-xl-3{column-gap:1rem !important}.column-gap-xl-4{column-gap:1.5rem !important}.column-gap-xl-5{column-gap:3rem !important}.text-xl-start{text-align:left !important}.text-xl-end{text-align:right !important}.text-xl-center{text-align:center !important}}@media(min-width: 1400px){.float-xxl-start{float:left !important}.float-xxl-end{float:right !important}.float-xxl-none{float:none !important}.object-fit-xxl-contain{object-fit:contain !important}.object-fit-xxl-cover{object-fit:cover !important}.object-fit-xxl-fill{object-fit:fill !important}.object-fit-xxl-scale{object-fit:scale-down !important}.object-fit-xxl-none{object-fit:none !important}.d-xxl-inline{display:inline !important}.d-xxl-inline-block{display:inline-block !important}.d-xxl-block{display:block !important}.d-xxl-grid{display:grid !important}.d-xxl-inline-grid{display:inline-grid !important}.d-xxl-table{display:table !important}.d-xxl-table-row{display:table-row !important}.d-xxl-table-cell{display:table-cell !important}.d-xxl-flex{display:flex !important}.d-xxl-inline-flex{display:inline-flex !important}.d-xxl-none{display:none !important}.flex-xxl-fill{flex:1 1 auto !important}.flex-xxl-row{flex-direction:row !important}.flex-xxl-column{flex-direction:column !important}.flex-xxl-row-reverse{flex-direction:row-reverse !important}.flex-xxl-column-reverse{flex-direction:column-reverse !important}.flex-xxl-grow-0{flex-grow:0 !important}.flex-xxl-grow-1{flex-grow:1 !important}.flex-xxl-shrink-0{flex-shrink:0 !important}.flex-xxl-shrink-1{flex-shrink:1 !important}.flex-xxl-wrap{flex-wrap:wrap !important}.flex-xxl-nowrap{flex-wrap:nowrap !important}.flex-xxl-wrap-reverse{flex-wrap:wrap-reverse !important}.justify-content-xxl-start{justify-content:flex-start !important}.justify-content-xxl-end{justify-content:flex-end !important}.justify-content-xxl-center{justify-content:center !important}.justify-content-xxl-between{justify-content:space-between !important}.justify-content-xxl-around{justify-content:space-around !important}.justify-content-xxl-evenly{justify-content:space-evenly !important}.align-items-xxl-start{align-items:flex-start !important}.align-items-xxl-end{align-items:flex-end !important}.align-items-xxl-center{align-items:center !important}.align-items-xxl-baseline{align-items:baseline !important}.align-items-xxl-stretch{align-items:stretch !important}.align-content-xxl-start{align-content:flex-start !important}.align-content-xxl-end{align-content:flex-end !important}.align-content-xxl-center{align-content:center !important}.align-content-xxl-between{align-content:space-between !important}.align-content-xxl-around{align-content:space-around !important}.align-content-xxl-stretch{align-content:stretch !important}.align-self-xxl-auto{align-self:auto !important}.align-self-xxl-start{align-self:flex-start !important}.align-self-xxl-end{align-self:flex-end !important}.align-self-xxl-center{align-self:center !important}.align-self-xxl-baseline{align-self:baseline !important}.align-self-xxl-stretch{align-self:stretch !important}.order-xxl-first{order:-1 !important}.order-xxl-0{order:0 !important}.order-xxl-1{order:1 !important}.order-xxl-2{order:2 !important}.order-xxl-3{order:3 !important}.order-xxl-4{order:4 !important}.order-xxl-5{order:5 !important}.order-xxl-last{order:6 !important}.m-xxl-0{margin:0 !important}.m-xxl-1{margin:.25rem !important}.m-xxl-2{margin:.5rem !important}.m-xxl-3{margin:1rem !important}.m-xxl-4{margin:1.5rem !important}.m-xxl-5{margin:3rem !important}.m-xxl-auto{margin:auto !important}.mx-xxl-0{margin-right:0 !important;margin-left:0 !important}.mx-xxl-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-xxl-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-xxl-3{margin-right:1rem !important;margin-left:1rem !important}.mx-xxl-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-xxl-5{margin-right:3rem !important;margin-left:3rem !important}.mx-xxl-auto{margin-right:auto !important;margin-left:auto !important}.my-xxl-0{margin-top:0 !important;margin-bottom:0 !important}.my-xxl-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-xxl-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-xxl-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-xxl-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-xxl-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-xxl-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-xxl-0{margin-top:0 !important}.mt-xxl-1{margin-top:.25rem !important}.mt-xxl-2{margin-top:.5rem !important}.mt-xxl-3{margin-top:1rem !important}.mt-xxl-4{margin-top:1.5rem !important}.mt-xxl-5{margin-top:3rem !important}.mt-xxl-auto{margin-top:auto !important}.me-xxl-0{margin-right:0 !important}.me-xxl-1{margin-right:.25rem !important}.me-xxl-2{margin-right:.5rem !important}.me-xxl-3{margin-right:1rem !important}.me-xxl-4{margin-right:1.5rem !important}.me-xxl-5{margin-right:3rem !important}.me-xxl-auto{margin-right:auto !important}.mb-xxl-0{margin-bottom:0 !important}.mb-xxl-1{margin-bottom:.25rem !important}.mb-xxl-2{margin-bottom:.5rem !important}.mb-xxl-3{margin-bottom:1rem !important}.mb-xxl-4{margin-bottom:1.5rem !important}.mb-xxl-5{margin-bottom:3rem !important}.mb-xxl-auto{margin-bottom:auto !important}.ms-xxl-0{margin-left:0 !important}.ms-xxl-1{margin-left:.25rem !important}.ms-xxl-2{margin-left:.5rem !important}.ms-xxl-3{margin-left:1rem !important}.ms-xxl-4{margin-left:1.5rem !important}.ms-xxl-5{margin-left:3rem !important}.ms-xxl-auto{margin-left:auto !important}.p-xxl-0{padding:0 !important}.p-xxl-1{padding:.25rem !important}.p-xxl-2{padding:.5rem !important}.p-xxl-3{padding:1rem !important}.p-xxl-4{padding:1.5rem !important}.p-xxl-5{padding:3rem !important}.px-xxl-0{padding-right:0 !important;padding-left:0 !important}.px-xxl-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-xxl-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-xxl-3{padding-right:1rem !important;padding-left:1rem !important}.px-xxl-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-xxl-5{padding-right:3rem !important;padding-left:3rem !important}.py-xxl-0{padding-top:0 !important;padding-bottom:0 !important}.py-xxl-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-xxl-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-xxl-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-xxl-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-xxl-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-xxl-0{padding-top:0 !important}.pt-xxl-1{padding-top:.25rem !important}.pt-xxl-2{padding-top:.5rem !important}.pt-xxl-3{padding-top:1rem !important}.pt-xxl-4{padding-top:1.5rem !important}.pt-xxl-5{padding-top:3rem !important}.pe-xxl-0{padding-right:0 !important}.pe-xxl-1{padding-right:.25rem !important}.pe-xxl-2{padding-right:.5rem !important}.pe-xxl-3{padding-right:1rem !important}.pe-xxl-4{padding-right:1.5rem !important}.pe-xxl-5{padding-right:3rem !important}.pb-xxl-0{padding-bottom:0 !important}.pb-xxl-1{padding-bottom:.25rem !important}.pb-xxl-2{padding-bottom:.5rem !important}.pb-xxl-3{padding-bottom:1rem !important}.pb-xxl-4{padding-bottom:1.5rem !important}.pb-xxl-5{padding-bottom:3rem !important}.ps-xxl-0{padding-left:0 !important}.ps-xxl-1{padding-left:.25rem !important}.ps-xxl-2{padding-left:.5rem !important}.ps-xxl-3{padding-left:1rem !important}.ps-xxl-4{padding-left:1.5rem !important}.ps-xxl-5{padding-left:3rem !important}.gap-xxl-0{gap:0 !important}.gap-xxl-1{gap:.25rem !important}.gap-xxl-2{gap:.5rem !important}.gap-xxl-3{gap:1rem !important}.gap-xxl-4{gap:1.5rem !important}.gap-xxl-5{gap:3rem !important}.row-gap-xxl-0{row-gap:0 !important}.row-gap-xxl-1{row-gap:.25rem !important}.row-gap-xxl-2{row-gap:.5rem !important}.row-gap-xxl-3{row-gap:1rem !important}.row-gap-xxl-4{row-gap:1.5rem !important}.row-gap-xxl-5{row-gap:3rem !important}.column-gap-xxl-0{column-gap:0 !important}.column-gap-xxl-1{column-gap:.25rem !important}.column-gap-xxl-2{column-gap:.5rem !important}.column-gap-xxl-3{column-gap:1rem !important}.column-gap-xxl-4{column-gap:1.5rem !important}.column-gap-xxl-5{column-gap:3rem !important}.text-xxl-start{text-align:left !important}.text-xxl-end{text-align:right !important}.text-xxl-center{text-align:center !important}}.bg-default{color:#000}.bg-primary{color:#fff}.bg-secondary{color:#fff}.bg-success{color:#fff}.bg-info{color:#000}.bg-warning{color:#000}.bg-danger{color:#fff}.bg-light{color:#000}.bg-dark{color:#fff}@media(min-width: 1200px){.fs-1{font-size:2rem !important}.fs-2{font-size:1.65rem !important}.fs-3{font-size:1.45rem !important}}@media print{.d-print-inline{display:inline !important}.d-print-inline-block{display:inline-block !important}.d-print-block{display:block !important}.d-print-grid{display:grid !important}.d-print-inline-grid{display:inline-grid !important}.d-print-table{display:table !important}.d-print-table-row{display:table-row !important}.d-print-table-cell{display:table-cell !important}.d-print-flex{display:flex !important}.d-print-inline-flex{display:inline-flex !important}.d-print-none{display:none !important}}.tab-content>.tab-pane.html-fill-container{display:none}.tab-content>.active.html-fill-container{display:flex}.tab-content.html-fill-container{padding:0}:root{--bslib-spacer: 1rem;--bslib-mb-spacer: var(--bslib-spacer, 1rem)}.bslib-mb-spacing{margin-bottom:var(--bslib-mb-spacer)}.bslib-gap-spacing{gap:var(--bslib-mb-spacer)}.bslib-gap-spacing>.bslib-mb-spacing,.bslib-gap-spacing>.form-group,.bslib-gap-spacing>p,.bslib-gap-spacing>pre{margin-bottom:0}.html-fill-container>.html-fill-item.bslib-mb-spacing{margin-bottom:0}.tab-content>.tab-pane.html-fill-container{display:none}.tab-content>.active.html-fill-container{display:flex}.tab-content.html-fill-container{padding:0}.bg-blue{--bslib-color-bg: #0d6efd;--bslib-color-fg: #ffffff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-blue{--bslib-color-fg: #0d6efd;color:var(--bslib-color-fg)}.bg-indigo{--bslib-color-bg: #6610f2;--bslib-color-fg: #ffffff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-indigo{--bslib-color-fg: #6610f2;color:var(--bslib-color-fg)}.bg-purple{--bslib-color-bg: #6f42c1;--bslib-color-fg: #ffffff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-purple{--bslib-color-fg: #6f42c1;color:var(--bslib-color-fg)}.bg-pink{--bslib-color-bg: #d63384;--bslib-color-fg: #ffffff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-pink{--bslib-color-fg: #d63384;color:var(--bslib-color-fg)}.bg-red{--bslib-color-bg: #dc3545;--bslib-color-fg: #ffffff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-red{--bslib-color-fg: #dc3545;color:var(--bslib-color-fg)}.bg-orange{--bslib-color-bg: #fd7e14;--bslib-color-fg: #000;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-orange{--bslib-color-fg: #fd7e14;color:var(--bslib-color-fg)}.bg-yellow{--bslib-color-bg: #ffc107;--bslib-color-fg: #000;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-yellow{--bslib-color-fg: #ffc107;color:var(--bslib-color-fg)}.bg-green{--bslib-color-bg: #198754;--bslib-color-fg: #ffffff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-green{--bslib-color-fg: #198754;color:var(--bslib-color-fg)}.bg-teal{--bslib-color-bg: #20c997;--bslib-color-fg: #000;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-teal{--bslib-color-fg: #20c997;color:var(--bslib-color-fg)}.bg-cyan{--bslib-color-bg: #0dcaf0;--bslib-color-fg: #000;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-cyan{--bslib-color-fg: #0dcaf0;color:var(--bslib-color-fg)}.text-default{--bslib-color-fg: #dee2e6}.bg-default{--bslib-color-bg: #dee2e6;--bslib-color-fg: #000}.text-primary{--bslib-color-fg: #0d6efd}.bg-primary{--bslib-color-bg: #0d6efd;--bslib-color-fg: #ffffff}.text-secondary{--bslib-color-fg: #6c757d}.bg-secondary{--bslib-color-bg: #6c757d;--bslib-color-fg: #ffffff}.text-success{--bslib-color-fg: #198754}.bg-success{--bslib-color-bg: #198754;--bslib-color-fg: #ffffff}.text-info{--bslib-color-fg: #0dcaf0}.bg-info{--bslib-color-bg: #0dcaf0;--bslib-color-fg: #000}.text-warning{--bslib-color-fg: #ffc107}.bg-warning{--bslib-color-bg: #ffc107;--bslib-color-fg: #000}.text-danger{--bslib-color-fg: #dc3545}.bg-danger{--bslib-color-bg: #dc3545;--bslib-color-fg: #ffffff}.text-light{--bslib-color-fg: #f8f9fa}.bg-light{--bslib-color-bg: #f8f9fa;--bslib-color-fg: #000}.text-dark{--bslib-color-fg: #212529}.bg-dark{--bslib-color-bg: #212529;--bslib-color-fg: #ffffff}.bg-gradient-blue-indigo{--bslib-color-fg: #ffffff;--bslib-color-bg: #3148f9;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #3148f9;color:#fff}.bg-gradient-blue-purple{--bslib-color-fg: #ffffff;--bslib-color-bg: #345ce5;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #345ce5;color:#fff}.bg-gradient-blue-pink{--bslib-color-fg: #ffffff;--bslib-color-bg: #5d56cd;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #5d56cd;color:#fff}.bg-gradient-blue-red{--bslib-color-fg: #ffffff;--bslib-color-bg: #6057b3;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #6057b3;color:#fff}.bg-gradient-blue-orange{--bslib-color-fg: #ffffff;--bslib-color-bg: #6d74a0;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #6d74a0;color:#fff}.bg-gradient-blue-yellow{--bslib-color-fg: #000;--bslib-color-bg: #6e8f9b;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #6e8f9b;color:#000}.bg-gradient-blue-green{--bslib-color-fg: #ffffff;--bslib-color-bg: #1278b9;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #1278b9;color:#fff}.bg-gradient-blue-teal{--bslib-color-fg: #000;--bslib-color-bg: #1592d4;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #1592d4;color:#000}.bg-gradient-blue-cyan{--bslib-color-fg: #000;--bslib-color-bg: #0d93f8;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #0d93f8;color:#000}.bg-gradient-indigo-blue{--bslib-color-fg: #ffffff;--bslib-color-bg: #4236f6;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #4236f6;color:#fff}.bg-gradient-indigo-purple{--bslib-color-fg: #ffffff;--bslib-color-bg: #6a24de;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #6a24de;color:#fff}.bg-gradient-indigo-pink{--bslib-color-fg: #ffffff;--bslib-color-bg: #931ec6;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #931ec6;color:#fff}.bg-gradient-indigo-red{--bslib-color-fg: #ffffff;--bslib-color-bg: #951fad;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #951fad;color:#fff}.bg-gradient-indigo-orange{--bslib-color-fg: #ffffff;--bslib-color-bg: #a23c99;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #a23c99;color:#fff}.bg-gradient-indigo-yellow{--bslib-color-fg: #ffffff;--bslib-color-bg: #a35794;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #a35794;color:#fff}.bg-gradient-indigo-green{--bslib-color-fg: #ffffff;--bslib-color-bg: #4740b3;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #4740b3;color:#fff}.bg-gradient-indigo-teal{--bslib-color-fg: #ffffff;--bslib-color-bg: #4a5ace;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #4a5ace;color:#fff}.bg-gradient-indigo-cyan{--bslib-color-fg: #ffffff;--bslib-color-bg: #425af1;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #425af1;color:#fff}.bg-gradient-purple-blue{--bslib-color-fg: #ffffff;--bslib-color-bg: #4854d9;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #4854d9;color:#fff}.bg-gradient-purple-indigo{--bslib-color-fg: #ffffff;--bslib-color-bg: #6b2ed5;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #6b2ed5;color:#fff}.bg-gradient-purple-pink{--bslib-color-fg: #ffffff;--bslib-color-bg: #983ca9;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #983ca9;color:#fff}.bg-gradient-purple-red{--bslib-color-fg: #ffffff;--bslib-color-bg: #9b3d8f;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #9b3d8f;color:#fff}.bg-gradient-purple-orange{--bslib-color-fg: #ffffff;--bslib-color-bg: #a85a7c;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #a85a7c;color:#fff}.bg-gradient-purple-yellow{--bslib-color-fg: #000;--bslib-color-bg: #a97577;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #a97577;color:#000}.bg-gradient-purple-green{--bslib-color-fg: #ffffff;--bslib-color-bg: #4d5e95;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #4d5e95;color:#fff}.bg-gradient-purple-teal{--bslib-color-fg: #ffffff;--bslib-color-bg: #4f78b0;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #4f78b0;color:#fff}.bg-gradient-purple-cyan{--bslib-color-fg: #000;--bslib-color-bg: #4878d4;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #4878d4;color:#000}.bg-gradient-pink-blue{--bslib-color-fg: #ffffff;--bslib-color-bg: #864bb4;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #864bb4;color:#fff}.bg-gradient-pink-indigo{--bslib-color-fg: #ffffff;--bslib-color-bg: #a925b0;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #a925b0;color:#fff}.bg-gradient-pink-purple{--bslib-color-fg: #ffffff;--bslib-color-bg: #ad399c;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #ad399c;color:#fff}.bg-gradient-pink-red{--bslib-color-fg: #ffffff;--bslib-color-bg: #d8346b;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #d8346b;color:#fff}.bg-gradient-pink-orange{--bslib-color-fg: #000;--bslib-color-bg: #e65157;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #e65157;color:#000}.bg-gradient-pink-yellow{--bslib-color-fg: #000;--bslib-color-bg: #e66c52;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #e66c52;color:#000}.bg-gradient-pink-green{--bslib-color-fg: #ffffff;--bslib-color-bg: #8a5571;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #8a5571;color:#fff}.bg-gradient-pink-teal{--bslib-color-fg: #000;--bslib-color-bg: #8d6f8c;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #8d6f8c;color:#000}.bg-gradient-pink-cyan{--bslib-color-fg: #000;--bslib-color-bg: #866faf;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #866faf;color:#000}.bg-gradient-red-blue{--bslib-color-fg: #ffffff;--bslib-color-bg: #894c8f;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #894c8f;color:#fff}.bg-gradient-red-indigo{--bslib-color-fg: #ffffff;--bslib-color-bg: #ad268a;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #ad268a;color:#fff}.bg-gradient-red-purple{--bslib-color-fg: #ffffff;--bslib-color-bg: #b03a77;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #b03a77;color:#fff}.bg-gradient-red-pink{--bslib-color-fg: #ffffff;--bslib-color-bg: #da345e;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #da345e;color:#fff}.bg-gradient-red-orange{--bslib-color-fg: #000;--bslib-color-bg: #e95231;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #e95231;color:#000}.bg-gradient-red-yellow{--bslib-color-fg: #000;--bslib-color-bg: #ea6d2c;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #ea6d2c;color:#000}.bg-gradient-red-green{--bslib-color-fg: #ffffff;--bslib-color-bg: #8e564b;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #8e564b;color:#fff}.bg-gradient-red-teal{--bslib-color-fg: #000;--bslib-color-bg: #917066;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #917066;color:#000}.bg-gradient-red-cyan{--bslib-color-fg: #000;--bslib-color-bg: #897189;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #897189;color:#000}.bg-gradient-orange-blue{--bslib-color-fg: #000;--bslib-color-bg: #9d7871;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #9d7871;color:#000}.bg-gradient-orange-indigo{--bslib-color-fg: #000;--bslib-color-bg: #c1526d;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #c1526d;color:#000}.bg-gradient-orange-purple{--bslib-color-fg: #000;--bslib-color-bg: #c46659;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #c46659;color:#000}.bg-gradient-orange-pink{--bslib-color-fg: #000;--bslib-color-bg: #ed6041;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #ed6041;color:#000}.bg-gradient-orange-red{--bslib-color-fg: #000;--bslib-color-bg: #f06128;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #f06128;color:#000}.bg-gradient-orange-yellow{--bslib-color-fg: #000;--bslib-color-bg: #fe990f;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #fe990f;color:#000}.bg-gradient-orange-green{--bslib-color-fg: #000;--bslib-color-bg: #a2822e;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #a2822e;color:#000}.bg-gradient-orange-teal{--bslib-color-fg: #000;--bslib-color-bg: #a59c48;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #a59c48;color:#000}.bg-gradient-orange-cyan{--bslib-color-fg: #000;--bslib-color-bg: #9d9c6c;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #9d9c6c;color:#000}.bg-gradient-yellow-blue{--bslib-color-fg: #000;--bslib-color-bg: #9ea069;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #9ea069;color:#000}.bg-gradient-yellow-indigo{--bslib-color-fg: #000;--bslib-color-bg: #c27a65;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #c27a65;color:#000}.bg-gradient-yellow-purple{--bslib-color-fg: #000;--bslib-color-bg: #c58e51;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #c58e51;color:#000}.bg-gradient-yellow-pink{--bslib-color-fg: #000;--bslib-color-bg: #ef8839;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #ef8839;color:#000}.bg-gradient-yellow-red{--bslib-color-fg: #000;--bslib-color-bg: #f18920;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #f18920;color:#000}.bg-gradient-yellow-orange{--bslib-color-fg: #000;--bslib-color-bg: #fea60c;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #fea60c;color:#000}.bg-gradient-yellow-green{--bslib-color-fg: #000;--bslib-color-bg: #a3aa26;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #a3aa26;color:#000}.bg-gradient-yellow-teal{--bslib-color-fg: #000;--bslib-color-bg: #a6c441;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #a6c441;color:#000}.bg-gradient-yellow-cyan{--bslib-color-fg: #000;--bslib-color-bg: #9ec564;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #9ec564;color:#000}.bg-gradient-green-blue{--bslib-color-fg: #ffffff;--bslib-color-bg: #147d98;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #147d98;color:#fff}.bg-gradient-green-indigo{--bslib-color-fg: #ffffff;--bslib-color-bg: #385793;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #385793;color:#fff}.bg-gradient-green-purple{--bslib-color-fg: #ffffff;--bslib-color-bg: #3b6b80;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #3b6b80;color:#fff}.bg-gradient-green-pink{--bslib-color-fg: #ffffff;--bslib-color-bg: #656567;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #656567;color:#fff}.bg-gradient-green-red{--bslib-color-fg: #ffffff;--bslib-color-bg: #67664e;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #67664e;color:#fff}.bg-gradient-green-orange{--bslib-color-fg: #000;--bslib-color-bg: #74833a;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #74833a;color:#000}.bg-gradient-green-yellow{--bslib-color-fg: #000;--bslib-color-bg: #759e35;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #759e35;color:#000}.bg-gradient-green-teal{--bslib-color-fg: #000;--bslib-color-bg: #1ca16f;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #1ca16f;color:#000}.bg-gradient-green-cyan{--bslib-color-fg: #000;--bslib-color-bg: #14a292;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #14a292;color:#000}.bg-gradient-teal-blue{--bslib-color-fg: #000;--bslib-color-bg: #18a5c0;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #18a5c0;color:#000}.bg-gradient-teal-indigo{--bslib-color-fg: #000;--bslib-color-bg: #3c7fbb;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #3c7fbb;color:#000}.bg-gradient-teal-purple{--bslib-color-fg: #000;--bslib-color-bg: #4093a8;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #4093a8;color:#000}.bg-gradient-teal-pink{--bslib-color-fg: #000;--bslib-color-bg: #698d8f;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #698d8f;color:#000}.bg-gradient-teal-red{--bslib-color-fg: #000;--bslib-color-bg: #6b8e76;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #6b8e76;color:#000}.bg-gradient-teal-orange{--bslib-color-fg: #000;--bslib-color-bg: #78ab63;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #78ab63;color:#000}.bg-gradient-teal-yellow{--bslib-color-fg: #000;--bslib-color-bg: #79c65d;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #79c65d;color:#000}.bg-gradient-teal-green{--bslib-color-fg: #000;--bslib-color-bg: #1daf7c;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #1daf7c;color:#000}.bg-gradient-teal-cyan{--bslib-color-fg: #000;--bslib-color-bg: #18c9bb;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #18c9bb;color:#000}.bg-gradient-cyan-blue{--bslib-color-fg: #000;--bslib-color-bg: #0da5f5;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #0da5f5;color:#000}.bg-gradient-cyan-indigo{--bslib-color-fg: #000;--bslib-color-bg: #3180f1;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #3180f1;color:#000}.bg-gradient-cyan-purple{--bslib-color-fg: #000;--bslib-color-bg: #3494dd;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #3494dd;color:#000}.bg-gradient-cyan-pink{--bslib-color-fg: #000;--bslib-color-bg: #5d8ec5;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #5d8ec5;color:#000}.bg-gradient-cyan-red{--bslib-color-fg: #000;--bslib-color-bg: #608eac;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #608eac;color:#000}.bg-gradient-cyan-orange{--bslib-color-fg: #000;--bslib-color-bg: #6dac98;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #6dac98;color:#000}.bg-gradient-cyan-yellow{--bslib-color-fg: #000;--bslib-color-bg: #6ec693;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #6ec693;color:#000}.bg-gradient-cyan-green{--bslib-color-fg: #000;--bslib-color-bg: #12afb2;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #12afb2;color:#000}.bg-gradient-cyan-teal{--bslib-color-fg: #000;--bslib-color-bg: #15cacc;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #15cacc;color:#000}.bg-blue{--bslib-color-bg: #0d6efd;--bslib-color-fg: #ffffff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-blue{--bslib-color-fg: #0d6efd;color:var(--bslib-color-fg)}.bg-indigo{--bslib-color-bg: #6610f2;--bslib-color-fg: #ffffff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-indigo{--bslib-color-fg: #6610f2;color:var(--bslib-color-fg)}.bg-purple{--bslib-color-bg: #6f42c1;--bslib-color-fg: #ffffff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-purple{--bslib-color-fg: #6f42c1;color:var(--bslib-color-fg)}.bg-pink{--bslib-color-bg: #d63384;--bslib-color-fg: #ffffff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-pink{--bslib-color-fg: #d63384;color:var(--bslib-color-fg)}.bg-red{--bslib-color-bg: #dc3545;--bslib-color-fg: #ffffff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-red{--bslib-color-fg: #dc3545;color:var(--bslib-color-fg)}.bg-orange{--bslib-color-bg: #fd7e14;--bslib-color-fg: #000;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-orange{--bslib-color-fg: #fd7e14;color:var(--bslib-color-fg)}.bg-yellow{--bslib-color-bg: #ffc107;--bslib-color-fg: #000;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-yellow{--bslib-color-fg: #ffc107;color:var(--bslib-color-fg)}.bg-green{--bslib-color-bg: #198754;--bslib-color-fg: #ffffff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-green{--bslib-color-fg: #198754;color:var(--bslib-color-fg)}.bg-teal{--bslib-color-bg: #20c997;--bslib-color-fg: #000;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-teal{--bslib-color-fg: #20c997;color:var(--bslib-color-fg)}.bg-cyan{--bslib-color-bg: #0dcaf0;--bslib-color-fg: #000;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-cyan{--bslib-color-fg: #0dcaf0;color:var(--bslib-color-fg)}.text-default{--bslib-color-fg: #dee2e6}.bg-default{--bslib-color-bg: #dee2e6;--bslib-color-fg: #000}.text-primary{--bslib-color-fg: #0d6efd}.bg-primary{--bslib-color-bg: #0d6efd;--bslib-color-fg: #ffffff}.text-secondary{--bslib-color-fg: #6c757d}.bg-secondary{--bslib-color-bg: #6c757d;--bslib-color-fg: #ffffff}.text-success{--bslib-color-fg: #198754}.bg-success{--bslib-color-bg: #198754;--bslib-color-fg: #ffffff}.text-info{--bslib-color-fg: #0dcaf0}.bg-info{--bslib-color-bg: #0dcaf0;--bslib-color-fg: #000}.text-warning{--bslib-color-fg: #ffc107}.bg-warning{--bslib-color-bg: #ffc107;--bslib-color-fg: #000}.text-danger{--bslib-color-fg: #dc3545}.bg-danger{--bslib-color-bg: #dc3545;--bslib-color-fg: #ffffff}.text-light{--bslib-color-fg: #f8f9fa}.bg-light{--bslib-color-bg: #f8f9fa;--bslib-color-fg: #000}.text-dark{--bslib-color-fg: #212529}.bg-dark{--bslib-color-bg: #212529;--bslib-color-fg: #ffffff}.bg-gradient-blue-indigo{--bslib-color-fg: #ffffff;--bslib-color-bg: #3148f9;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #3148f9;color:#fff}.bg-gradient-blue-purple{--bslib-color-fg: #ffffff;--bslib-color-bg: #345ce5;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #345ce5;color:#fff}.bg-gradient-blue-pink{--bslib-color-fg: #ffffff;--bslib-color-bg: #5d56cd;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #5d56cd;color:#fff}.bg-gradient-blue-red{--bslib-color-fg: #ffffff;--bslib-color-bg: #6057b3;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #6057b3;color:#fff}.bg-gradient-blue-orange{--bslib-color-fg: #ffffff;--bslib-color-bg: #6d74a0;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #6d74a0;color:#fff}.bg-gradient-blue-yellow{--bslib-color-fg: #000;--bslib-color-bg: #6e8f9b;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #6e8f9b;color:#000}.bg-gradient-blue-green{--bslib-color-fg: #ffffff;--bslib-color-bg: #1278b9;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #1278b9;color:#fff}.bg-gradient-blue-teal{--bslib-color-fg: #000;--bslib-color-bg: #1592d4;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #1592d4;color:#000}.bg-gradient-blue-cyan{--bslib-color-fg: #000;--bslib-color-bg: #0d93f8;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #0d93f8;color:#000}.bg-gradient-indigo-blue{--bslib-color-fg: #ffffff;--bslib-color-bg: #4236f6;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #4236f6;color:#fff}.bg-gradient-indigo-purple{--bslib-color-fg: #ffffff;--bslib-color-bg: #6a24de;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #6a24de;color:#fff}.bg-gradient-indigo-pink{--bslib-color-fg: #ffffff;--bslib-color-bg: #931ec6;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #931ec6;color:#fff}.bg-gradient-indigo-red{--bslib-color-fg: #ffffff;--bslib-color-bg: #951fad;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #951fad;color:#fff}.bg-gradient-indigo-orange{--bslib-color-fg: #ffffff;--bslib-color-bg: #a23c99;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #a23c99;color:#fff}.bg-gradient-indigo-yellow{--bslib-color-fg: #ffffff;--bslib-color-bg: #a35794;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #a35794;color:#fff}.bg-gradient-indigo-green{--bslib-color-fg: #ffffff;--bslib-color-bg: #4740b3;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #4740b3;color:#fff}.bg-gradient-indigo-teal{--bslib-color-fg: #ffffff;--bslib-color-bg: #4a5ace;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #4a5ace;color:#fff}.bg-gradient-indigo-cyan{--bslib-color-fg: #ffffff;--bslib-color-bg: #425af1;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #425af1;color:#fff}.bg-gradient-purple-blue{--bslib-color-fg: #ffffff;--bslib-color-bg: #4854d9;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #4854d9;color:#fff}.bg-gradient-purple-indigo{--bslib-color-fg: #ffffff;--bslib-color-bg: #6b2ed5;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #6b2ed5;color:#fff}.bg-gradient-purple-pink{--bslib-color-fg: #ffffff;--bslib-color-bg: #983ca9;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #983ca9;color:#fff}.bg-gradient-purple-red{--bslib-color-fg: #ffffff;--bslib-color-bg: #9b3d8f;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #9b3d8f;color:#fff}.bg-gradient-purple-orange{--bslib-color-fg: #ffffff;--bslib-color-bg: #a85a7c;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #a85a7c;color:#fff}.bg-gradient-purple-yellow{--bslib-color-fg: #000;--bslib-color-bg: #a97577;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #a97577;color:#000}.bg-gradient-purple-green{--bslib-color-fg: #ffffff;--bslib-color-bg: #4d5e95;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #4d5e95;color:#fff}.bg-gradient-purple-teal{--bslib-color-fg: #ffffff;--bslib-color-bg: #4f78b0;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #4f78b0;color:#fff}.bg-gradient-purple-cyan{--bslib-color-fg: #000;--bslib-color-bg: #4878d4;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #4878d4;color:#000}.bg-gradient-pink-blue{--bslib-color-fg: #ffffff;--bslib-color-bg: #864bb4;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #864bb4;color:#fff}.bg-gradient-pink-indigo{--bslib-color-fg: #ffffff;--bslib-color-bg: #a925b0;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #a925b0;color:#fff}.bg-gradient-pink-purple{--bslib-color-fg: #ffffff;--bslib-color-bg: #ad399c;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #ad399c;color:#fff}.bg-gradient-pink-red{--bslib-color-fg: #ffffff;--bslib-color-bg: #d8346b;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #d8346b;color:#fff}.bg-gradient-pink-orange{--bslib-color-fg: #000;--bslib-color-bg: #e65157;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #e65157;color:#000}.bg-gradient-pink-yellow{--bslib-color-fg: #000;--bslib-color-bg: #e66c52;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #e66c52;color:#000}.bg-gradient-pink-green{--bslib-color-fg: #ffffff;--bslib-color-bg: #8a5571;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #8a5571;color:#fff}.bg-gradient-pink-teal{--bslib-color-fg: #000;--bslib-color-bg: #8d6f8c;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #8d6f8c;color:#000}.bg-gradient-pink-cyan{--bslib-color-fg: #000;--bslib-color-bg: #866faf;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #866faf;color:#000}.bg-gradient-red-blue{--bslib-color-fg: #ffffff;--bslib-color-bg: #894c8f;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #894c8f;color:#fff}.bg-gradient-red-indigo{--bslib-color-fg: #ffffff;--bslib-color-bg: #ad268a;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #ad268a;color:#fff}.bg-gradient-red-purple{--bslib-color-fg: #ffffff;--bslib-color-bg: #b03a77;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #b03a77;color:#fff}.bg-gradient-red-pink{--bslib-color-fg: #ffffff;--bslib-color-bg: #da345e;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #da345e;color:#fff}.bg-gradient-red-orange{--bslib-color-fg: #000;--bslib-color-bg: #e95231;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #e95231;color:#000}.bg-gradient-red-yellow{--bslib-color-fg: #000;--bslib-color-bg: #ea6d2c;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #ea6d2c;color:#000}.bg-gradient-red-green{--bslib-color-fg: #ffffff;--bslib-color-bg: #8e564b;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #8e564b;color:#fff}.bg-gradient-red-teal{--bslib-color-fg: #000;--bslib-color-bg: #917066;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #917066;color:#000}.bg-gradient-red-cyan{--bslib-color-fg: #000;--bslib-color-bg: #897189;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #897189;color:#000}.bg-gradient-orange-blue{--bslib-color-fg: #000;--bslib-color-bg: #9d7871;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #9d7871;color:#000}.bg-gradient-orange-indigo{--bslib-color-fg: #000;--bslib-color-bg: #c1526d;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #c1526d;color:#000}.bg-gradient-orange-purple{--bslib-color-fg: #000;--bslib-color-bg: #c46659;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #c46659;color:#000}.bg-gradient-orange-pink{--bslib-color-fg: #000;--bslib-color-bg: #ed6041;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #ed6041;color:#000}.bg-gradient-orange-red{--bslib-color-fg: #000;--bslib-color-bg: #f06128;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #f06128;color:#000}.bg-gradient-orange-yellow{--bslib-color-fg: #000;--bslib-color-bg: #fe990f;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #fe990f;color:#000}.bg-gradient-orange-green{--bslib-color-fg: #000;--bslib-color-bg: #a2822e;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #a2822e;color:#000}.bg-gradient-orange-teal{--bslib-color-fg: #000;--bslib-color-bg: #a59c48;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #a59c48;color:#000}.bg-gradient-orange-cyan{--bslib-color-fg: #000;--bslib-color-bg: #9d9c6c;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #9d9c6c;color:#000}.bg-gradient-yellow-blue{--bslib-color-fg: #000;--bslib-color-bg: #9ea069;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #9ea069;color:#000}.bg-gradient-yellow-indigo{--bslib-color-fg: #000;--bslib-color-bg: #c27a65;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #c27a65;color:#000}.bg-gradient-yellow-purple{--bslib-color-fg: #000;--bslib-color-bg: #c58e51;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #c58e51;color:#000}.bg-gradient-yellow-pink{--bslib-color-fg: #000;--bslib-color-bg: #ef8839;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #ef8839;color:#000}.bg-gradient-yellow-red{--bslib-color-fg: #000;--bslib-color-bg: #f18920;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #f18920;color:#000}.bg-gradient-yellow-orange{--bslib-color-fg: #000;--bslib-color-bg: #fea60c;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #fea60c;color:#000}.bg-gradient-yellow-green{--bslib-color-fg: #000;--bslib-color-bg: #a3aa26;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #a3aa26;color:#000}.bg-gradient-yellow-teal{--bslib-color-fg: #000;--bslib-color-bg: #a6c441;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #a6c441;color:#000}.bg-gradient-yellow-cyan{--bslib-color-fg: #000;--bslib-color-bg: #9ec564;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #9ec564;color:#000}.bg-gradient-green-blue{--bslib-color-fg: #ffffff;--bslib-color-bg: #147d98;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #147d98;color:#fff}.bg-gradient-green-indigo{--bslib-color-fg: #ffffff;--bslib-color-bg: #385793;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #385793;color:#fff}.bg-gradient-green-purple{--bslib-color-fg: #ffffff;--bslib-color-bg: #3b6b80;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #3b6b80;color:#fff}.bg-gradient-green-pink{--bslib-color-fg: #ffffff;--bslib-color-bg: #656567;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #656567;color:#fff}.bg-gradient-green-red{--bslib-color-fg: #ffffff;--bslib-color-bg: #67664e;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #67664e;color:#fff}.bg-gradient-green-orange{--bslib-color-fg: #000;--bslib-color-bg: #74833a;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #74833a;color:#000}.bg-gradient-green-yellow{--bslib-color-fg: #000;--bslib-color-bg: #759e35;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #759e35;color:#000}.bg-gradient-green-teal{--bslib-color-fg: #000;--bslib-color-bg: #1ca16f;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #1ca16f;color:#000}.bg-gradient-green-cyan{--bslib-color-fg: #000;--bslib-color-bg: #14a292;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #14a292;color:#000}.bg-gradient-teal-blue{--bslib-color-fg: #000;--bslib-color-bg: #18a5c0;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #18a5c0;color:#000}.bg-gradient-teal-indigo{--bslib-color-fg: #000;--bslib-color-bg: #3c7fbb;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #3c7fbb;color:#000}.bg-gradient-teal-purple{--bslib-color-fg: #000;--bslib-color-bg: #4093a8;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #4093a8;color:#000}.bg-gradient-teal-pink{--bslib-color-fg: #000;--bslib-color-bg: #698d8f;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #698d8f;color:#000}.bg-gradient-teal-red{--bslib-color-fg: #000;--bslib-color-bg: #6b8e76;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #6b8e76;color:#000}.bg-gradient-teal-orange{--bslib-color-fg: #000;--bslib-color-bg: #78ab63;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #78ab63;color:#000}.bg-gradient-teal-yellow{--bslib-color-fg: #000;--bslib-color-bg: #79c65d;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #79c65d;color:#000}.bg-gradient-teal-green{--bslib-color-fg: #000;--bslib-color-bg: #1daf7c;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #1daf7c;color:#000}.bg-gradient-teal-cyan{--bslib-color-fg: #000;--bslib-color-bg: #18c9bb;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #18c9bb;color:#000}.bg-gradient-cyan-blue{--bslib-color-fg: #000;--bslib-color-bg: #0da5f5;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #0da5f5;color:#000}.bg-gradient-cyan-indigo{--bslib-color-fg: #000;--bslib-color-bg: #3180f1;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #3180f1;color:#000}.bg-gradient-cyan-purple{--bslib-color-fg: #000;--bslib-color-bg: #3494dd;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #3494dd;color:#000}.bg-gradient-cyan-pink{--bslib-color-fg: #000;--bslib-color-bg: #5d8ec5;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #5d8ec5;color:#000}.bg-gradient-cyan-red{--bslib-color-fg: #000;--bslib-color-bg: #608eac;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #608eac;color:#000}.bg-gradient-cyan-orange{--bslib-color-fg: #000;--bslib-color-bg: #6dac98;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #6dac98;color:#000}.bg-gradient-cyan-yellow{--bslib-color-fg: #000;--bslib-color-bg: #6ec693;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #6ec693;color:#000}.bg-gradient-cyan-green{--bslib-color-fg: #000;--bslib-color-bg: #12afb2;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #12afb2;color:#000}.bg-gradient-cyan-teal{--bslib-color-fg: #000;--bslib-color-bg: #15cacc;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #15cacc;color:#000}:root{--bslib-spacer: 1rem;--bslib-mb-spacer: var(--bslib-spacer, 1rem)}.bslib-mb-spacing{margin-bottom:var(--bslib-mb-spacer)}.bslib-gap-spacing{gap:var(--bslib-mb-spacer)}.bslib-gap-spacing>.bslib-mb-spacing,.bslib-gap-spacing>.form-group,.bslib-gap-spacing>p,.bslib-gap-spacing>pre{margin-bottom:0}.html-fill-container>.html-fill-item.bslib-mb-spacing{margin-bottom:0}.bslib-grid{display:grid !important;gap:var(--bslib-spacer, 1rem);height:var(--bslib-grid-height)}.bslib-grid.grid{grid-template-columns:repeat(var(--bs-columns, 12), minmax(0, 1fr));grid-template-rows:unset;grid-auto-rows:var(--bslib-grid--row-heights);--bslib-grid--row-heights--xs: unset;--bslib-grid--row-heights--sm: unset;--bslib-grid--row-heights--md: unset;--bslib-grid--row-heights--lg: unset;--bslib-grid--row-heights--xl: unset;--bslib-grid--row-heights--xxl: unset}.bslib-grid.grid.bslib-grid--row-heights--xs{--bslib-grid--row-heights: var(--bslib-grid--row-heights--xs)}@media(min-width: 576px){.bslib-grid.grid.bslib-grid--row-heights--sm{--bslib-grid--row-heights: var(--bslib-grid--row-heights--sm)}}@media(min-width: 768px){.bslib-grid.grid.bslib-grid--row-heights--md{--bslib-grid--row-heights: var(--bslib-grid--row-heights--md)}}@media(min-width: 992px){.bslib-grid.grid.bslib-grid--row-heights--lg{--bslib-grid--row-heights: var(--bslib-grid--row-heights--lg)}}@media(min-width: 1200px){.bslib-grid.grid.bslib-grid--row-heights--xl{--bslib-grid--row-heights: var(--bslib-grid--row-heights--xl)}}@media(min-width: 1400px){.bslib-grid.grid.bslib-grid--row-heights--xxl{--bslib-grid--row-heights: var(--bslib-grid--row-heights--xxl)}}.bslib-grid>*>.shiny-input-container{width:100%}.bslib-grid-item{grid-column:auto/span 1}@media(max-width: 767.98px){.bslib-grid-item{grid-column:1/-1}}@media(max-width: 575.98px){.bslib-grid{grid-template-columns:1fr !important;height:var(--bslib-grid-height-mobile)}.bslib-grid.grid{height:unset !important;grid-auto-rows:var(--bslib-grid--row-heights--xs, auto)}}@media(min-width: 576px){.nav:not(.nav-hidden){display:flex !important;display:-webkit-flex !important}.nav:not(.nav-hidden):not(.nav-stacked):not(.flex-column){float:none !important}.nav:not(.nav-hidden):not(.nav-stacked):not(.flex-column)>.bslib-nav-spacer{margin-left:auto !important}.nav:not(.nav-hidden):not(.nav-stacked):not(.flex-column)>.form-inline{margin-top:auto;margin-bottom:auto}.nav:not(.nav-hidden).nav-stacked{flex-direction:column;-webkit-flex-direction:column;height:100%}.nav:not(.nav-hidden).nav-stacked>.bslib-nav-spacer{margin-top:auto !important}}.accordion .accordion-header{font-size:calc(1.29rem + 0.48vw);margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2;color:var(--bs-heading-color);margin-bottom:0}@media(min-width: 1200px){.accordion .accordion-header{font-size:1.65rem}}.accordion .accordion-icon:not(:empty){margin-right:.75rem;display:flex}.accordion .accordion-button:not(.collapsed){box-shadow:none}.accordion .accordion-button:not(.collapsed):focus{box-shadow:var(--bs-accordion-btn-focus-box-shadow)}html{height:100%}.bslib-page-fill{width:100%;height:100%;margin:0;padding:var(--bslib-spacer, 1rem);gap:var(--bslib-spacer, 1rem)}@media(max-width: 575.98px){.bslib-page-fill{height:var(--bslib-page-fill-mobile-height, auto)}}.bslib-sidebar-layout{--bslib-sidebar-transition-duration: 500ms;--bslib-sidebar-transition-easing-x: cubic-bezier(0.8, 0.78, 0.22, 1.07);--bslib-sidebar-border: var(--bs-card-border-width, 1px) solid var(--bs-card-border-color, rgba(0, 0, 0, 0.175));--bslib-sidebar-border-radius: var(--bs-border-radius);--bslib-sidebar-vert-border: var(--bs-card-border-width, 1px) solid var(--bs-card-border-color, rgba(0, 0, 0, 0.175));--bslib-sidebar-bg: rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.05);--bslib-sidebar-fg: var(--bs-emphasis-color, black);--bslib-sidebar-main-fg: var(--bs-card-color, var(--bs-body-color));--bslib-sidebar-main-bg: var(--bs-card-bg, var(--bs-body-bg));--bslib-sidebar-toggle-bg: rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.1);--bslib-sidebar-padding: calc(var(--bslib-spacer) * 1.5);--bslib-sidebar-icon-size: var(--bslib-spacer, 1rem);--bslib-sidebar-icon-button-size: calc(var(--bslib-sidebar-icon-size, 1rem) * 2);--bslib-sidebar-padding-icon: calc(var(--bslib-sidebar-icon-button-size, 2rem) * 1.5);--bslib-collapse-toggle-border-radius: var(--bs-border-radius, 0.375rem);--bslib-collapse-toggle-transform: 0deg;--bslib-sidebar-toggle-transition-easing: cubic-bezier(1, 0, 0, 1);--bslib-collapse-toggle-right-transform: 180deg;--bslib-sidebar-column-main: minmax(0, 1fr);display:grid !important;grid-template-columns:min(100% - var(--bslib-sidebar-icon-size),var(--bslib-sidebar-width, 250px)) var(--bslib-sidebar-column-main);position:relative;transition:grid-template-columns ease-in-out var(--bslib-sidebar-transition-duration);border:var(--bslib-sidebar-border);border-radius:var(--bslib-sidebar-border-radius)}@media(prefers-reduced-motion: reduce){.bslib-sidebar-layout{transition:none}}.bslib-sidebar-layout[data-bslib-sidebar-border=false]{border:none}.bslib-sidebar-layout[data-bslib-sidebar-border-radius=false]{border-radius:initial}.bslib-sidebar-layout>.main,.bslib-sidebar-layout>.sidebar{grid-row:1/2;border-radius:inherit;overflow:auto}.bslib-sidebar-layout>.main{grid-column:2/3;border-top-left-radius:0;border-bottom-left-radius:0;padding:var(--bslib-sidebar-padding);transition:padding var(--bslib-sidebar-transition-easing-x) var(--bslib-sidebar-transition-duration);color:var(--bslib-sidebar-main-fg);background-color:var(--bslib-sidebar-main-bg)}.bslib-sidebar-layout>.sidebar{grid-column:1/2;width:100%;height:100%;border-right:var(--bslib-sidebar-vert-border);border-top-right-radius:0;border-bottom-right-radius:0;color:var(--bslib-sidebar-fg);background-color:var(--bslib-sidebar-bg);backdrop-filter:blur(5px)}.bslib-sidebar-layout>.sidebar>.sidebar-content{display:flex;flex-direction:column;gap:var(--bslib-spacer, 1rem);padding:var(--bslib-sidebar-padding);padding-top:var(--bslib-sidebar-padding-icon)}.bslib-sidebar-layout>.sidebar>.sidebar-content>:last-child:not(.sidebar-title){margin-bottom:0}.bslib-sidebar-layout>.sidebar>.sidebar-content>.accordion{margin-left:calc(-1*var(--bslib-sidebar-padding));margin-right:calc(-1*var(--bslib-sidebar-padding))}.bslib-sidebar-layout>.sidebar>.sidebar-content>.accordion:last-child{margin-bottom:calc(-1*var(--bslib-sidebar-padding))}.bslib-sidebar-layout>.sidebar>.sidebar-content>.accordion:not(:last-child){margin-bottom:1rem}.bslib-sidebar-layout>.sidebar>.sidebar-content>.accordion .accordion-body{display:flex;flex-direction:column}.bslib-sidebar-layout>.sidebar>.sidebar-content>.accordion:not(:first-child) .accordion-item:first-child{border-top:var(--bs-accordion-border-width) solid var(--bs-accordion-border-color)}.bslib-sidebar-layout>.sidebar>.sidebar-content>.accordion:not(:last-child) .accordion-item:last-child{border-bottom:var(--bs-accordion-border-width) solid var(--bs-accordion-border-color)}.bslib-sidebar-layout>.sidebar>.sidebar-content.has-accordion>.sidebar-title{border-bottom:none;padding-bottom:0}.bslib-sidebar-layout>.sidebar .shiny-input-container{width:100%}.bslib-sidebar-layout[data-bslib-sidebar-open=always]>.sidebar>.sidebar-content{padding-top:var(--bslib-sidebar-padding)}.bslib-sidebar-layout>.collapse-toggle{grid-row:1/2;grid-column:1/2;display:inline-flex;align-items:center;position:absolute;right:calc(var(--bslib-sidebar-icon-size));top:calc(var(--bslib-sidebar-icon-size, 1rem)/2);border:none;border-radius:var(--bslib-collapse-toggle-border-radius);height:var(--bslib-sidebar-icon-button-size, 2rem);width:var(--bslib-sidebar-icon-button-size, 2rem);display:flex;align-items:center;justify-content:center;padding:0;color:var(--bslib-sidebar-fg);background-color:unset;transition:color var(--bslib-sidebar-transition-easing-x) var(--bslib-sidebar-transition-duration),top var(--bslib-sidebar-transition-easing-x) var(--bslib-sidebar-transition-duration),right var(--bslib-sidebar-transition-easing-x) var(--bslib-sidebar-transition-duration),left var(--bslib-sidebar-transition-easing-x) var(--bslib-sidebar-transition-duration)}.bslib-sidebar-layout>.collapse-toggle:hover{background-color:var(--bslib-sidebar-toggle-bg)}.bslib-sidebar-layout>.collapse-toggle>.collapse-icon{opacity:.8;width:var(--bslib-sidebar-icon-size);height:var(--bslib-sidebar-icon-size);transform:rotateY(var(--bslib-collapse-toggle-transform));transition:transform var(--bslib-sidebar-toggle-transition-easing) var(--bslib-sidebar-transition-duration)}.bslib-sidebar-layout>.collapse-toggle:hover>.collapse-icon{opacity:1}.bslib-sidebar-layout .sidebar-title{font-size:1.25rem;line-height:1.25;margin-top:0;margin-bottom:1rem;padding-bottom:1rem;border-bottom:var(--bslib-sidebar-border)}.bslib-sidebar-layout.sidebar-right{grid-template-columns:var(--bslib-sidebar-column-main) min(100% - var(--bslib-sidebar-icon-size),var(--bslib-sidebar-width, 250px))}.bslib-sidebar-layout.sidebar-right>.main{grid-column:1/2;border-top-right-radius:0;border-bottom-right-radius:0;border-top-left-radius:inherit;border-bottom-left-radius:inherit}.bslib-sidebar-layout.sidebar-right>.sidebar{grid-column:2/3;border-right:none;border-left:var(--bslib-sidebar-vert-border);border-top-left-radius:0;border-bottom-left-radius:0}.bslib-sidebar-layout.sidebar-right>.collapse-toggle{grid-column:2/3;left:var(--bslib-sidebar-icon-size);right:unset;border:var(--bslib-collapse-toggle-border)}.bslib-sidebar-layout.sidebar-right>.collapse-toggle>.collapse-icon{transform:rotateY(var(--bslib-collapse-toggle-right-transform))}.bslib-sidebar-layout.sidebar-collapsed{--bslib-collapse-toggle-transform: 180deg;--bslib-collapse-toggle-right-transform: 0deg;--bslib-sidebar-vert-border: none;grid-template-columns:0 minmax(0, 1fr)}.bslib-sidebar-layout.sidebar-collapsed.sidebar-right{grid-template-columns:minmax(0, 1fr) 0}.bslib-sidebar-layout.sidebar-collapsed:not(.transitioning)>.sidebar>*{display:none}.bslib-sidebar-layout.sidebar-collapsed>.main{border-radius:inherit}.bslib-sidebar-layout.sidebar-collapsed:not(.sidebar-right)>.main{padding-left:var(--bslib-sidebar-padding-icon)}.bslib-sidebar-layout.sidebar-collapsed.sidebar-right>.main{padding-right:var(--bslib-sidebar-padding-icon)}.bslib-sidebar-layout.sidebar-collapsed>.collapse-toggle{color:var(--bslib-sidebar-main-fg);top:calc(var(--bslib-sidebar-overlap-counter, 0)*(var(--bslib-sidebar-icon-size) + var(--bslib-sidebar-padding)) + var(--bslib-sidebar-icon-size, 1rem)/2);right:calc(-2.5*var(--bslib-sidebar-icon-size) - var(--bs-card-border-width, 1px))}.bslib-sidebar-layout.sidebar-collapsed.sidebar-right>.collapse-toggle{left:calc(-2.5*var(--bslib-sidebar-icon-size) - var(--bs-card-border-width, 1px));right:unset}@media(min-width: 576px){.bslib-sidebar-layout.transitioning>.sidebar>.sidebar-content{display:none}}@media(max-width: 575.98px){.bslib-sidebar-layout[data-bslib-sidebar-open=desktop]{--bslib-sidebar-js-init-collapsed: true}.bslib-sidebar-layout>.sidebar,.bslib-sidebar-layout.sidebar-right>.sidebar{border:none}.bslib-sidebar-layout>.main,.bslib-sidebar-layout.sidebar-right>.main{grid-column:1/3}.bslib-sidebar-layout[data-bslib-sidebar-open=always]{display:block !important}.bslib-sidebar-layout[data-bslib-sidebar-open=always]>.sidebar{max-height:var(--bslib-sidebar-max-height-mobile);overflow-y:auto;border-top:var(--bslib-sidebar-vert-border)}.bslib-sidebar-layout:not([data-bslib-sidebar-open=always]){grid-template-columns:100% 0}.bslib-sidebar-layout:not([data-bslib-sidebar-open=always]):not(.sidebar-collapsed)>.sidebar{z-index:1}.bslib-sidebar-layout:not([data-bslib-sidebar-open=always]):not(.sidebar-collapsed)>.collapse-toggle{z-index:1}.bslib-sidebar-layout:not([data-bslib-sidebar-open=always]).sidebar-right{grid-template-columns:0 100%}.bslib-sidebar-layout:not([data-bslib-sidebar-open=always]).sidebar-collapsed{grid-template-columns:0 100%}.bslib-sidebar-layout:not([data-bslib-sidebar-open=always]).sidebar-collapsed.sidebar-right{grid-template-columns:100% 0}.bslib-sidebar-layout:not([data-bslib-sidebar-open=always]):not(.sidebar-right)>.main{padding-left:var(--bslib-sidebar-padding-icon)}.bslib-sidebar-layout:not([data-bslib-sidebar-open=always]).sidebar-right>.main{padding-right:var(--bslib-sidebar-padding-icon)}.bslib-sidebar-layout:not([data-bslib-sidebar-open=always])>.main{opacity:0;transition:opacity var(--bslib-sidebar-transition-easing-x) var(--bslib-sidebar-transition-duration)}.bslib-sidebar-layout:not([data-bslib-sidebar-open=always]).sidebar-collapsed>.main{opacity:1}}:root{--bslib-value-box-shadow: none;--bslib-value-box-border-width-auto-yes: var(--bslib-value-box-border-width-baseline);--bslib-value-box-border-width-auto-no: 0;--bslib-value-box-border-width-baseline: 1px}.bslib-value-box{border-width:var(--bslib-value-box-border-width-auto-no, var(--bslib-value-box-border-width-baseline));container-name:bslib-value-box;container-type:inline-size}.bslib-value-box.card{box-shadow:var(--bslib-value-box-shadow)}.bslib-value-box.border-auto{border-width:var(--bslib-value-box-border-width-auto-yes, var(--bslib-value-box-border-width-baseline))}.bslib-value-box.default{--bslib-value-box-bg-default: var(--bs-card-bg, #ffffff);--bslib-value-box-border-color-default: var(--bs-card-border-color, rgba(0, 0, 0, 0.175));color:var(--bslib-value-box-color);background-color:var(--bslib-value-box-bg, var(--bslib-value-box-bg-default));border-color:var(--bslib-value-box-border-color, var(--bslib-value-box-border-color-default))}.bslib-value-box .value-box-grid{display:grid;grid-template-areas:"left right";align-items:center;overflow:hidden}.bslib-value-box .value-box-showcase{height:100%;max-height:var(---bslib-value-box-showcase-max-h, 100%)}.bslib-value-box .value-box-showcase,.bslib-value-box .value-box-showcase>.html-fill-item{width:100%}.bslib-value-box[data-full-screen=true] .value-box-showcase{max-height:var(---bslib-value-box-showcase-max-h-fs, 100%)}@media screen and (min-width: 575.98px){@container bslib-value-box (max-width: 300px){.bslib-value-box:not(.showcase-bottom) .value-box-grid{grid-template-columns:1fr !important;grid-template-rows:auto auto;grid-template-areas:"top" "bottom"}.bslib-value-box:not(.showcase-bottom) .value-box-grid .value-box-showcase{grid-area:top !important}.bslib-value-box:not(.showcase-bottom) .value-box-grid .value-box-area{grid-area:bottom !important;justify-content:end}}}.bslib-value-box .value-box-area{justify-content:center;padding:1.5rem 1rem;font-size:.9rem;font-weight:500}.bslib-value-box .value-box-area *{margin-bottom:0;margin-top:0}.bslib-value-box .value-box-title{font-size:1rem;margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2}.bslib-value-box .value-box-title:empty::after{content:" "}.bslib-value-box .value-box-value{font-size:calc(1.29rem + 0.48vw);margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2}@media(min-width: 1200px){.bslib-value-box .value-box-value{font-size:1.65rem}}.bslib-value-box .value-box-value:empty::after{content:" "}.bslib-value-box .value-box-showcase{align-items:center;justify-content:center;margin-top:auto;margin-bottom:auto;padding:1rem}.bslib-value-box .value-box-showcase .bi,.bslib-value-box .value-box-showcase .fa,.bslib-value-box .value-box-showcase .fab,.bslib-value-box .value-box-showcase .fas,.bslib-value-box .value-box-showcase .far{opacity:.85;min-width:50px;max-width:125%}.bslib-value-box .value-box-showcase .bi,.bslib-value-box .value-box-showcase .fa,.bslib-value-box .value-box-showcase .fab,.bslib-value-box .value-box-showcase .fas,.bslib-value-box .value-box-showcase .far{font-size:4rem}.bslib-value-box.showcase-top-right .value-box-grid{grid-template-columns:1fr var(---bslib-value-box-showcase-w, 50%)}.bslib-value-box.showcase-top-right .value-box-grid .value-box-showcase{grid-area:right;margin-left:auto;align-self:start;align-items:end;padding-left:0;padding-bottom:0}.bslib-value-box.showcase-top-right .value-box-grid .value-box-area{grid-area:left;align-self:end}.bslib-value-box.showcase-top-right[data-full-screen=true] .value-box-grid{grid-template-columns:auto var(---bslib-value-box-showcase-w-fs, 1fr)}.bslib-value-box.showcase-top-right[data-full-screen=true] .value-box-grid>div{align-self:center}.bslib-value-box.showcase-top-right:not([data-full-screen=true]) .value-box-showcase{margin-top:0}@container bslib-value-box (max-width: 300px){.bslib-value-box.showcase-top-right:not([data-full-screen=true]) .value-box-grid .value-box-showcase{padding-left:1rem}}.bslib-value-box.showcase-left-center .value-box-grid{grid-template-columns:var(---bslib-value-box-showcase-w, 30%) auto}.bslib-value-box.showcase-left-center[data-full-screen=true] .value-box-grid{grid-template-columns:var(---bslib-value-box-showcase-w-fs, 1fr) auto}.bslib-value-box.showcase-left-center:not([data-fill-screen=true]) .value-box-grid .value-box-showcase{grid-area:left}.bslib-value-box.showcase-left-center:not([data-fill-screen=true]) .value-box-grid .value-box-area{grid-area:right}.bslib-value-box.showcase-bottom .value-box-grid{grid-template-columns:1fr;grid-template-rows:1fr var(---bslib-value-box-showcase-h, auto);grid-template-areas:"top" "bottom";overflow:hidden}.bslib-value-box.showcase-bottom .value-box-grid .value-box-showcase{grid-area:bottom;padding:0;margin:0}.bslib-value-box.showcase-bottom .value-box-grid .value-box-area{grid-area:top}.bslib-value-box.showcase-bottom[data-full-screen=true] .value-box-grid{grid-template-rows:1fr var(---bslib-value-box-showcase-h-fs, 2fr)}.bslib-value-box.showcase-bottom[data-full-screen=true] .value-box-grid .value-box-showcase{padding:1rem}[data-bs-theme=dark] .bslib-value-box{--bslib-value-box-shadow: 0 0.5rem 1rem rgb(0 0 0 / 50%)}.bslib-card{overflow:auto}.bslib-card .card-body+.card-body{padding-top:0}.bslib-card .card-body{overflow:auto}.bslib-card .card-body p{margin-top:0}.bslib-card .card-body p:last-child{margin-bottom:0}.bslib-card .card-body{max-height:var(--bslib-card-body-max-height, none)}.bslib-card[data-full-screen=true]>.card-body{max-height:var(--bslib-card-body-max-height-full-screen, none)}.bslib-card .card-header .form-group{margin-bottom:0}.bslib-card .card-header .selectize-control{margin-bottom:0}.bslib-card .card-header .selectize-control .item{margin-right:1.15rem}.bslib-card .card-footer{margin-top:auto}.bslib-card .bslib-navs-card-title{display:flex;flex-wrap:wrap;justify-content:space-between;align-items:center}.bslib-card .bslib-navs-card-title .nav{margin-left:auto}.bslib-card .bslib-sidebar-layout:not([data-bslib-sidebar-border=true]){border:none}.bslib-card .bslib-sidebar-layout:not([data-bslib-sidebar-border-radius=true]){border-top-left-radius:0;border-top-right-radius:0}[data-full-screen=true]{position:fixed;inset:3.5rem 1rem 1rem;height:auto !important;max-height:none !important;width:auto !important;z-index:1070}.bslib-full-screen-enter{display:none;position:absolute;bottom:var(--bslib-full-screen-enter-bottom, 0.2rem);right:var(--bslib-full-screen-enter-right, 0);top:var(--bslib-full-screen-enter-top);left:var(--bslib-full-screen-enter-left);color:var(--bslib-color-fg, var(--bs-card-color));background-color:var(--bslib-color-bg, var(--bs-card-bg, var(--bs-body-bg)));border:var(--bs-card-border-width) solid var(--bslib-color-fg, var(--bs-card-border-color));box-shadow:0 2px 4px rgba(0,0,0,.15);margin:.2rem .4rem;padding:.55rem !important;font-size:.8rem;cursor:pointer;opacity:.7;z-index:1070}.bslib-full-screen-enter:hover{opacity:1}.card[data-full-screen=false]:hover>*>.bslib-full-screen-enter{display:block}.bslib-has-full-screen .card:hover>*>.bslib-full-screen-enter{display:none}@media(max-width: 575.98px){.bslib-full-screen-enter{display:none !important}}.bslib-full-screen-exit{position:relative;top:1.35rem;font-size:.9rem;cursor:pointer;text-decoration:none;display:flex;float:right;margin-right:2.15rem;align-items:center;color:rgba(var(--bs-body-bg-rgb), 0.8)}.bslib-full-screen-exit:hover{color:rgba(var(--bs-body-bg-rgb), 1)}.bslib-full-screen-exit svg{margin-left:.5rem;font-size:1.5rem}#bslib-full-screen-overlay{position:fixed;inset:0;background-color:rgba(var(--bs-body-color-rgb), 0.6);backdrop-filter:blur(2px);-webkit-backdrop-filter:blur(2px);z-index:1069;animation:bslib-full-screen-overlay-enter 400ms cubic-bezier(0.6, 0.02, 0.65, 1) forwards}@keyframes bslib-full-screen-overlay-enter{0%{opacity:0}100%{opacity:1}}.navbar+.container-fluid:has(>.tab-content>.tab-pane.active.html-fill-container),.navbar+.container-sm:has(>.tab-content>.tab-pane.active.html-fill-container),.navbar+.container-md:has(>.tab-content>.tab-pane.active.html-fill-container),.navbar+.container-lg:has(>.tab-content>.tab-pane.active.html-fill-container),.navbar+.container-xl:has(>.tab-content>.tab-pane.active.html-fill-container),.navbar+.container-xxl:has(>.tab-content>.tab-pane.active.html-fill-container){padding-left:0;padding-right:0}.navbar+.container-fluid>.tab-content>.tab-pane.active.html-fill-container,.navbar+.container-sm>.tab-content>.tab-pane.active.html-fill-container,.navbar+.container-md>.tab-content>.tab-pane.active.html-fill-container,.navbar+.container-lg>.tab-content>.tab-pane.active.html-fill-container,.navbar+.container-xl>.tab-content>.tab-pane.active.html-fill-container,.navbar+.container-xxl>.tab-content>.tab-pane.active.html-fill-container{padding:var(--bslib-spacer, 1rem);gap:var(--bslib-spacer, 1rem)}.navbar+.container-fluid>.tab-content>.tab-pane.active.html-fill-container:has(>.bslib-sidebar-layout:only-child),.navbar+.container-sm>.tab-content>.tab-pane.active.html-fill-container:has(>.bslib-sidebar-layout:only-child),.navbar+.container-md>.tab-content>.tab-pane.active.html-fill-container:has(>.bslib-sidebar-layout:only-child),.navbar+.container-lg>.tab-content>.tab-pane.active.html-fill-container:has(>.bslib-sidebar-layout:only-child),.navbar+.container-xl>.tab-content>.tab-pane.active.html-fill-container:has(>.bslib-sidebar-layout:only-child),.navbar+.container-xxl>.tab-content>.tab-pane.active.html-fill-container:has(>.bslib-sidebar-layout:only-child){padding:0}.navbar+.container-fluid>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border=true]),.navbar+.container-sm>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border=true]),.navbar+.container-md>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border=true]),.navbar+.container-lg>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border=true]),.navbar+.container-xl>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border=true]),.navbar+.container-xxl>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border=true]){border-left:none;border-right:none;border-bottom:none}.navbar+.container-fluid>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border-radius=true]),.navbar+.container-sm>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border-radius=true]),.navbar+.container-md>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border-radius=true]),.navbar+.container-lg>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border-radius=true]),.navbar+.container-xl>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border-radius=true]),.navbar+.container-xxl>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border-radius=true]){border-radius:0}.navbar+div>.bslib-sidebar-layout{border-top:var(--bslib-sidebar-border)}:root{--bslib-page-sidebar-title-bg: #517699;--bslib-page-sidebar-title-color: #ffffff}.bslib-page-title{background-color:var(--bslib-page-sidebar-title-bg);color:var(--bslib-page-sidebar-title-color);font-size:1.25rem;font-weight:300;padding:var(--bslib-spacer, 1rem);padding-left:1.5rem;margin-bottom:0;border-bottom:1px solid #dee2e6}.html-fill-container{display:flex;flex-direction:column;min-height:0;min-width:0}.html-fill-container>.html-fill-item{flex:1 1 auto;min-height:0;min-width:0}.html-fill-container>:not(.html-fill-item){flex:0 0 auto}.tippy-box[data-theme~=quarto]{background-color:#fff;border:solid 1px #dee2e6;border-radius:.375rem;color:#212529;font-size:.875rem}.tippy-box[data-theme~=quarto]>.tippy-backdrop{background-color:#fff}.tippy-box[data-theme~=quarto]>.tippy-arrow:after,.tippy-box[data-theme~=quarto]>.tippy-svg-arrow:after{content:"";position:absolute;z-index:-1}.tippy-box[data-theme~=quarto]>.tippy-arrow:after{border-color:rgba(0,0,0,0);border-style:solid}.tippy-box[data-placement^=top]>.tippy-arrow:before{bottom:-6px}.tippy-box[data-placement^=bottom]>.tippy-arrow:before{top:-6px}.tippy-box[data-placement^=right]>.tippy-arrow:before{left:-6px}.tippy-box[data-placement^=left]>.tippy-arrow:before{right:-6px}.tippy-box[data-theme~=quarto][data-placement^=top]>.tippy-arrow:before{border-top-color:#fff}.tippy-box[data-theme~=quarto][data-placement^=top]>.tippy-arrow:after{border-top-color:#dee2e6;border-width:7px 7px 0;top:17px;left:1px}.tippy-box[data-theme~=quarto][data-placement^=top]>.tippy-svg-arrow>svg{top:16px}.tippy-box[data-theme~=quarto][data-placement^=top]>.tippy-svg-arrow:after{top:17px}.tippy-box[data-theme~=quarto][data-placement^=bottom]>.tippy-arrow:before{border-bottom-color:#fff;bottom:16px}.tippy-box[data-theme~=quarto][data-placement^=bottom]>.tippy-arrow:after{border-bottom-color:#dee2e6;border-width:0 7px 7px;bottom:17px;left:1px}.tippy-box[data-theme~=quarto][data-placement^=bottom]>.tippy-svg-arrow>svg{bottom:15px}.tippy-box[data-theme~=quarto][data-placement^=bottom]>.tippy-svg-arrow:after{bottom:17px}.tippy-box[data-theme~=quarto][data-placement^=left]>.tippy-arrow:before{border-left-color:#fff}.tippy-box[data-theme~=quarto][data-placement^=left]>.tippy-arrow:after{border-left-color:#dee2e6;border-width:7px 0 7px 7px;left:17px;top:1px}.tippy-box[data-theme~=quarto][data-placement^=left]>.tippy-svg-arrow>svg{left:11px}.tippy-box[data-theme~=quarto][data-placement^=left]>.tippy-svg-arrow:after{left:12px}.tippy-box[data-theme~=quarto][data-placement^=right]>.tippy-arrow:before{border-right-color:#fff;right:16px}.tippy-box[data-theme~=quarto][data-placement^=right]>.tippy-arrow:after{border-width:7px 7px 7px 0;right:17px;top:1px;border-right-color:#dee2e6}.tippy-box[data-theme~=quarto][data-placement^=right]>.tippy-svg-arrow>svg{right:11px}.tippy-box[data-theme~=quarto][data-placement^=right]>.tippy-svg-arrow:after{right:12px}.tippy-box[data-theme~=quarto]>.tippy-svg-arrow{fill:#212529}.tippy-box[data-theme~=quarto]>.tippy-svg-arrow:after{background-image:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iNiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMCA2czEuNzk2LS4wMTMgNC42Ny0zLjYxNUM1Ljg1MS45IDYuOTMuMDA2IDggMGMxLjA3LS4wMDYgMi4xNDguODg3IDMuMzQzIDIuMzg1QzE0LjIzMyA2LjAwNSAxNiA2IDE2IDZIMHoiIGZpbGw9InJnYmEoMCwgOCwgMTYsIDAuMikiLz48L3N2Zz4=);background-size:16px 6px;width:16px;height:6px}.top-right{position:absolute;top:1em;right:1em}.visually-hidden{border:0;clip:rect(0 0 0 0);height:auto;margin:0;overflow:hidden;padding:0;position:absolute;width:1px;white-space:nowrap}.hidden{display:none !important}.zindex-bottom{z-index:-1 !important}figure.figure{display:block}.quarto-layout-panel{margin-bottom:1em}.quarto-layout-panel>figure{width:100%}.quarto-layout-panel>figure>figcaption,.quarto-layout-panel>.panel-caption{margin-top:10pt}.quarto-layout-panel>.table-caption{margin-top:0px}.table-caption p{margin-bottom:.5em}.quarto-layout-row{display:flex;flex-direction:row;align-items:flex-start}.quarto-layout-valign-top{align-items:flex-start}.quarto-layout-valign-bottom{align-items:flex-end}.quarto-layout-valign-center{align-items:center}.quarto-layout-cell{position:relative;margin-right:20px}.quarto-layout-cell:last-child{margin-right:0}.quarto-layout-cell figure,.quarto-layout-cell>p{margin:.2em}.quarto-layout-cell img{max-width:100%}.quarto-layout-cell .html-widget{width:100% !important}.quarto-layout-cell div figure p{margin:0}.quarto-layout-cell figure{display:block;margin-inline-start:0;margin-inline-end:0}.quarto-layout-cell table{display:inline-table}.quarto-layout-cell-subref figcaption,figure .quarto-layout-row figure figcaption{text-align:center;font-style:italic}.quarto-figure{position:relative;margin-bottom:1em}.quarto-figure>figure{width:100%;margin-bottom:0}.quarto-figure-left>figure>p,.quarto-figure-left>figure>div{text-align:left}.quarto-figure-center>figure>p,.quarto-figure-center>figure>div{text-align:center}.quarto-figure-right>figure>p,.quarto-figure-right>figure>div{text-align:right}.quarto-figure>figure>div.cell-annotation,.quarto-figure>figure>div code{text-align:left}figure>p:empty{display:none}figure>p:first-child{margin-top:0;margin-bottom:0}figure>figcaption.quarto-float-caption-bottom{margin-bottom:.5em}figure>figcaption.quarto-float-caption-top{margin-top:.5em}div[id^=tbl-]{position:relative}.quarto-figure>.anchorjs-link{position:absolute;top:.6em;right:.5em}div[id^=tbl-]>.anchorjs-link{position:absolute;top:.7em;right:.3em}.quarto-figure:hover>.anchorjs-link,div[id^=tbl-]:hover>.anchorjs-link,h2:hover>.anchorjs-link,.h2:hover>.anchorjs-link,h3:hover>.anchorjs-link,.h3:hover>.anchorjs-link,h4:hover>.anchorjs-link,.h4:hover>.anchorjs-link,h5:hover>.anchorjs-link,.h5:hover>.anchorjs-link,h6:hover>.anchorjs-link,.h6:hover>.anchorjs-link,.reveal-anchorjs-link>.anchorjs-link{opacity:1}#title-block-header{margin-block-end:1rem;position:relative;margin-top:-1px}#title-block-header .abstract{margin-block-start:1rem}#title-block-header .abstract .abstract-title{font-weight:600}#title-block-header a{text-decoration:none}#title-block-header .author,#title-block-header .date,#title-block-header .doi{margin-block-end:.2rem}#title-block-header .quarto-title-block>div{display:flex}#title-block-header .quarto-title-block>div>h1,#title-block-header .quarto-title-block>div>.h1{flex-grow:1}#title-block-header .quarto-title-block>div>button{flex-shrink:0;height:2.25rem;margin-top:0}@media(min-width: 992px){#title-block-header .quarto-title-block>div>button{margin-top:5px}}tr.header>th>p:last-of-type{margin-bottom:0px}table,table.table{margin-top:.5rem;margin-bottom:.5rem}caption,.table-caption{padding-top:.5rem;padding-bottom:.5rem;text-align:center}figure.quarto-float-tbl figcaption.quarto-float-caption-top{margin-top:.5rem;margin-bottom:.25rem;text-align:center}figure.quarto-float-tbl figcaption.quarto-float-caption-bottom{padding-top:.25rem;margin-bottom:.5rem;text-align:center}.utterances{max-width:none;margin-left:-8px}iframe{margin-bottom:1em}details{margin-bottom:1em}details[show]{margin-bottom:0}details>summary{color:rgba(33,37,41,.75)}details>summary>p:only-child{display:inline}pre.sourceCode,code.sourceCode{position:relative}dd code:not(.sourceCode),p code:not(.sourceCode){white-space:pre-wrap}code{white-space:pre}@media print{code{white-space:pre-wrap}}pre>code{display:block}pre>code.sourceCode{white-space:pre}pre>code.sourceCode>span>a:first-child::before{text-decoration:none}pre.code-overflow-wrap>code.sourceCode{white-space:pre-wrap}pre.code-overflow-scroll>code.sourceCode{white-space:pre}code a:any-link{color:inherit;text-decoration:none}code a:hover{color:inherit;text-decoration:underline}ul.task-list{padding-left:1em}[data-tippy-root]{display:inline-block}.tippy-content .footnote-back{display:none}.footnote-back{margin-left:.2em}.tippy-content{overflow-x:auto}.quarto-embedded-source-code{display:none}.quarto-unresolved-ref{font-weight:600}.quarto-cover-image{max-width:35%;float:right;margin-left:30px}.cell-output-display .widget-subarea{margin-bottom:1em}.cell-output-display:not(.no-overflow-x),.knitsql-table:not(.no-overflow-x){overflow-x:auto}.panel-input{margin-bottom:1em}.panel-input>div,.panel-input>div>div{display:inline-block;vertical-align:top;padding-right:12px}.panel-input>p:last-child{margin-bottom:0}.layout-sidebar{margin-bottom:1em}.layout-sidebar .tab-content{border:none}.tab-content>.page-columns.active{display:grid}div.sourceCode>iframe{width:100%;height:300px;margin-bottom:-0.5em}a{text-underline-offset:3px}div.ansi-escaped-output{font-family:monospace;display:block}/*! -* -* ansi colors from IPython notebook's -* -* we also add `bright-[color]-` synonyms for the `-[color]-intense` classes since -* that seems to be what ansi_up emits -* -*/.ansi-black-fg{color:#3e424d}.ansi-black-bg{background-color:#3e424d}.ansi-black-intense-black,.ansi-bright-black-fg{color:#282c36}.ansi-black-intense-black,.ansi-bright-black-bg{background-color:#282c36}.ansi-red-fg{color:#e75c58}.ansi-red-bg{background-color:#e75c58}.ansi-red-intense-red,.ansi-bright-red-fg{color:#b22b31}.ansi-red-intense-red,.ansi-bright-red-bg{background-color:#b22b31}.ansi-green-fg{color:#00a250}.ansi-green-bg{background-color:#00a250}.ansi-green-intense-green,.ansi-bright-green-fg{color:#007427}.ansi-green-intense-green,.ansi-bright-green-bg{background-color:#007427}.ansi-yellow-fg{color:#ddb62b}.ansi-yellow-bg{background-color:#ddb62b}.ansi-yellow-intense-yellow,.ansi-bright-yellow-fg{color:#b27d12}.ansi-yellow-intense-yellow,.ansi-bright-yellow-bg{background-color:#b27d12}.ansi-blue-fg{color:#208ffb}.ansi-blue-bg{background-color:#208ffb}.ansi-blue-intense-blue,.ansi-bright-blue-fg{color:#0065ca}.ansi-blue-intense-blue,.ansi-bright-blue-bg{background-color:#0065ca}.ansi-magenta-fg{color:#d160c4}.ansi-magenta-bg{background-color:#d160c4}.ansi-magenta-intense-magenta,.ansi-bright-magenta-fg{color:#a03196}.ansi-magenta-intense-magenta,.ansi-bright-magenta-bg{background-color:#a03196}.ansi-cyan-fg{color:#60c6c8}.ansi-cyan-bg{background-color:#60c6c8}.ansi-cyan-intense-cyan,.ansi-bright-cyan-fg{color:#258f8f}.ansi-cyan-intense-cyan,.ansi-bright-cyan-bg{background-color:#258f8f}.ansi-white-fg{color:#c5c1b4}.ansi-white-bg{background-color:#c5c1b4}.ansi-white-intense-white,.ansi-bright-white-fg{color:#a1a6b2}.ansi-white-intense-white,.ansi-bright-white-bg{background-color:#a1a6b2}.ansi-default-inverse-fg{color:#fff}.ansi-default-inverse-bg{background-color:#000}.ansi-bold{font-weight:bold}.ansi-underline{text-decoration:underline}:root{--quarto-body-bg: #ffffff;--quarto-body-color: #212529;--quarto-text-muted: rgba(33, 37, 41, 0.75);--quarto-border-color: #dee2e6;--quarto-border-width: 1px;--quarto-border-radius: 0.375rem}table.gt_table{color:var(--quarto-body-color);font-size:1em;width:100%;background-color:rgba(0,0,0,0);border-top-width:inherit;border-bottom-width:inherit;border-color:var(--quarto-border-color)}table.gt_table th.gt_column_spanner_outer{color:var(--quarto-body-color);background-color:rgba(0,0,0,0);border-top-width:inherit;border-bottom-width:inherit;border-color:var(--quarto-border-color)}table.gt_table th.gt_col_heading{color:var(--quarto-body-color);font-weight:bold;background-color:rgba(0,0,0,0)}table.gt_table thead.gt_col_headings{border-bottom:1px solid currentColor;border-top-width:inherit;border-top-color:var(--quarto-border-color)}table.gt_table thead.gt_col_headings:not(:first-child){border-top-width:1px;border-top-color:var(--quarto-border-color)}table.gt_table td.gt_row{border-bottom-width:1px;border-bottom-color:var(--quarto-border-color);border-top-width:0px}table.gt_table tbody.gt_table_body{border-top-width:1px;border-bottom-width:1px;border-bottom-color:var(--quarto-border-color);border-top-color:currentColor}div.columns{display:initial;gap:initial}div.column{display:inline-block;overflow-x:initial;vertical-align:top;width:50%}.code-annotation-tip-content{word-wrap:break-word}.code-annotation-container-hidden{display:none !important}dl.code-annotation-container-grid{display:grid;grid-template-columns:min-content auto}dl.code-annotation-container-grid dt{grid-column:1}dl.code-annotation-container-grid dd{grid-column:2}pre.sourceCode.code-annotation-code{padding-right:0}code.sourceCode .code-annotation-anchor{z-index:100;position:relative;float:right;background-color:rgba(0,0,0,0)}input[type=checkbox]{margin-right:.5ch}:root{--mermaid-bg-color: #ffffff;--mermaid-edge-color: #6c757d;--mermaid-node-fg-color: #212529;--mermaid-fg-color: #212529;--mermaid-fg-color--lighter: #383f45;--mermaid-fg-color--lightest: #4e5862;--mermaid-font-family: system-ui, -apple-system, Segoe UI, Roboto, Helvetica Neue, Noto Sans, Liberation Sans, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol, Noto Color Emoji;--mermaid-label-bg-color: #ffffff;--mermaid-label-fg-color: #0d6efd;--mermaid-node-bg-color: rgba(13, 110, 253, 0.1);--mermaid-node-fg-color: #212529}@media print{:root{font-size:11pt}#quarto-sidebar,#TOC,.nav-page{display:none}.page-columns .content{grid-column-start:page-start}.fixed-top{position:relative}.panel-caption,.figure-caption,figcaption{color:#666}}.code-copy-button{position:absolute;top:0;right:0;border:0;margin-top:5px;margin-right:5px;background-color:rgba(0,0,0,0);z-index:3}.code-copy-button:focus{outline:none}.code-copy-button-tooltip{font-size:.75em}pre.sourceCode:hover>.code-copy-button>.bi::before{display:inline-block;height:1rem;width:1rem;content:"";vertical-align:-0.125em;background-image:url('data:image/svg+xml,');background-repeat:no-repeat;background-size:1rem 1rem}pre.sourceCode:hover>.code-copy-button-checked>.bi::before{background-image:url('data:image/svg+xml,')}pre.sourceCode:hover>.code-copy-button:hover>.bi::before{background-image:url('data:image/svg+xml,')}pre.sourceCode:hover>.code-copy-button-checked:hover>.bi::before{background-image:url('data:image/svg+xml,')}main ol ol,main ul ul,main ol ul,main ul ol{margin-bottom:1em}ul>li:not(:has(>p))>ul,ol>li:not(:has(>p))>ul,ul>li:not(:has(>p))>ol,ol>li:not(:has(>p))>ol{margin-bottom:0}ul>li:not(:has(>p))>ul>li:has(>p),ol>li:not(:has(>p))>ul>li:has(>p),ul>li:not(:has(>p))>ol>li:has(>p),ol>li:not(:has(>p))>ol>li:has(>p){margin-top:1rem}body{margin:0}main.page-columns>header>h1.title,main.page-columns>header>.title.h1{margin-bottom:0}@media(min-width: 992px){body .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset] 35px [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(500px, calc(850px - 3em)) [body-content-end] 1.5em [body-end] 35px [body-end-outset] minmax(75px, 145px) [page-end-inset] 35px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.fullcontent:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset] 35px [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(500px, calc(850px - 3em)) [body-content-end] 1.5em [body-end] 35px [body-end-outset] 35px [page-end-inset page-end] 5fr [screen-end-inset] 1.5em}body.slimcontent:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset] 35px [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(500px, calc(850px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(0px, 200px) [page-end-inset] 35px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.listing:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start] minmax(50px, 100px) [page-start-inset] 50px [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(500px, calc(850px - 3em)) [body-content-end] 3em [body-end] 50px [body-end-outset] minmax(0px, 250px) [page-end-inset] minmax(50px, 100px) [page-end] 1fr [screen-end-inset] 1.5em [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] 35px [page-start-inset] minmax(0px, 175px) [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(450px, calc(800px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(0px, 200px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] 35px [page-start-inset] minmax(0px, 175px) [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(450px, calc(800px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(0px, 200px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] minmax(25px, 50px) [page-start-inset] minmax(50px, 150px) [body-start-outset] minmax(25px, 50px) [body-start] 1.5em [body-content-start] minmax(500px, calc(800px - 3em)) [body-content-end] 1.5em [body-end] minmax(25px, 50px) [body-end-outset] minmax(50px, 150px) [page-end-inset] minmax(25px, 50px) [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start] minmax(50px, 100px) [page-start-inset] 50px [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(500px, calc(1000px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(50px, 100px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked.fullcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start] minmax(50px, 100px) [page-start-inset] 50px [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(500px, calc(1000px - 3em)) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating.fullcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] 50px [page-start-inset] minmax(50px, 150px) [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(500px, calc(800px - 3em)) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked.slimcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start] minmax(50px, 100px) [page-start-inset] 50px [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(450px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(0px, 200px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked.listing .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start] minmax(50px, 100px) [page-start-inset] 50px [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(500px, calc(1000px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(0px, 200px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating.slimcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] 50px [page-start-inset] minmax(50px, 150px) [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(450px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(50px, 150px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating.listing .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] minmax(25px, 50px) [page-start-inset] minmax(50px, 150px) [body-start-outset] minmax(25px, 50px) [body-start] 1.5em [body-content-start] minmax(500px, calc(800px - 3em)) [body-content-end] 1.5em [body-end] minmax(25px, 50px) [body-end-outset] minmax(50px, 150px) [page-end-inset] minmax(25px, 50px) [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}}@media(max-width: 991.98px){body .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset] 5fr [body-start] 1.5em [body-content-start] minmax(500px, calc(800px - 3em)) [body-content-end] 1.5em [body-end] 35px [body-end-outset] minmax(75px, 145px) [page-end-inset] 35px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.fullcontent:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset] 5fr [body-start] 1.5em [body-content-start] minmax(500px, calc(800px - 3em)) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.slimcontent:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset] 5fr [body-start] 1.5em [body-content-start] minmax(500px, calc(800px - 3em)) [body-content-end] 1.5em [body-end] 35px [body-end-outset] minmax(75px, 145px) [page-end-inset] 35px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.listing:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset] 5fr [body-start] 1.5em [body-content-start] minmax(500px, calc(1250px - 3em)) [body-content-end body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] 35px [page-start-inset] minmax(0px, 145px) [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(450px, calc(800px - 3em)) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] 35px [page-start-inset] minmax(0px, 145px) [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(450px, calc(800px - 3em)) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset body-start-outset body-start] 1.5em [body-content-start] minmax(500px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(75px, 150px) [page-end-inset] 25px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(500px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(25px, 50px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked.fullcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(500px, calc(1000px - 3em)) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating.fullcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset body-start-outset body-start] 1em [body-content-start] minmax(500px, calc(800px - 3em)) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 4fr [screen-end-inset] 1.5em [screen-end]}body.docked.slimcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(500px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(25px, 50px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked.listing .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(500px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(25px, 50px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating.slimcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset body-start-outset body-start] 1em [body-content-start] minmax(500px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 35px [body-end-outset] minmax(75px, 145px) [page-end-inset] 35px [page-end] 4fr [screen-end-inset] 1.5em [screen-end]}body.floating.listing .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset body-start-outset body-start] 1em [body-content-start] minmax(500px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(75px, 150px) [page-end-inset] 25px [page-end] 4fr [screen-end-inset] 1.5em [screen-end]}}@media(max-width: 767.98px){body .page-columns,body.fullcontent:not(.floating):not(.docked) .page-columns,body.slimcontent:not(.floating):not(.docked) .page-columns,body.docked .page-columns,body.docked.slimcontent .page-columns,body.docked.fullcontent .page-columns,body.floating .page-columns,body.floating.slimcontent .page-columns,body.floating.fullcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(0px, 1fr) [body-content-end body-end body-end-outset page-end-inset page-end screen-end-inset] 1.5em [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(0px, 1fr) [body-content-end body-end body-end-outset page-end-inset page-end screen-end-inset] 1.5em [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(0px, 1fr) [body-content-end body-end body-end-outset page-end-inset page-end screen-end-inset] 1.5em [screen-end]}nav[role=doc-toc]{display:none}}body,.page-row-navigation{grid-template-rows:[page-top] max-content [contents-top] max-content [contents-bottom] max-content [page-bottom]}.page-rows-contents{grid-template-rows:[content-top] minmax(max-content, 1fr) [content-bottom] minmax(60px, max-content) [page-bottom]}.page-full{grid-column:screen-start/screen-end !important}.page-columns>*{grid-column:body-content-start/body-content-end}.page-columns.column-page>*{grid-column:page-start/page-end}.page-columns.column-page-left .page-columns.page-full>*,.page-columns.column-page-left>*{grid-column:page-start/body-content-end}.page-columns.column-page-right .page-columns.page-full>*,.page-columns.column-page-right>*{grid-column:body-content-start/page-end}.page-rows{grid-auto-rows:auto}.header{grid-column:screen-start/screen-end;grid-row:page-top/contents-top}#quarto-content{padding:0;grid-column:screen-start/screen-end;grid-row:contents-top/contents-bottom}body.floating .sidebar.sidebar-navigation{grid-column:page-start/body-start;grid-row:content-top/page-bottom}body.docked .sidebar.sidebar-navigation{grid-column:screen-start/body-start;grid-row:content-top/page-bottom}.sidebar.toc-left{grid-column:page-start/body-start;grid-row:content-top/page-bottom}.sidebar.margin-sidebar{grid-column:body-end/page-end;grid-row:content-top/page-bottom}.page-columns .content{grid-column:body-content-start/body-content-end;grid-row:content-top/content-bottom;align-content:flex-start}.page-columns .page-navigation{grid-column:body-content-start/body-content-end;grid-row:content-bottom/page-bottom}.page-columns .footer{grid-column:screen-start/screen-end;grid-row:contents-bottom/page-bottom}.page-columns .column-body{grid-column:body-content-start/body-content-end}.page-columns .column-body-fullbleed{grid-column:body-start/body-end}.page-columns .column-body-outset{grid-column:body-start-outset/body-end-outset;z-index:998;opacity:.999}.page-columns .column-body-outset table{background:#fff}.page-columns .column-body-outset-left{grid-column:body-start-outset/body-content-end;z-index:998;opacity:.999}.page-columns .column-body-outset-left table{background:#fff}.page-columns .column-body-outset-right{grid-column:body-content-start/body-end-outset;z-index:998;opacity:.999}.page-columns .column-body-outset-right table{background:#fff}.page-columns .column-page{grid-column:page-start/page-end;z-index:998;opacity:.999}.page-columns .column-page table{background:#fff}.page-columns .column-page-inset{grid-column:page-start-inset/page-end-inset;z-index:998;opacity:.999}.page-columns .column-page-inset table{background:#fff}.page-columns .column-page-inset-left{grid-column:page-start-inset/body-content-end;z-index:998;opacity:.999}.page-columns .column-page-inset-left table{background:#fff}.page-columns .column-page-inset-right{grid-column:body-content-start/page-end-inset;z-index:998;opacity:.999}.page-columns .column-page-inset-right figcaption table{background:#fff}.page-columns .column-page-left{grid-column:page-start/body-content-end;z-index:998;opacity:.999}.page-columns .column-page-left table{background:#fff}.page-columns .column-page-right{grid-column:body-content-start/page-end;z-index:998;opacity:.999}.page-columns .column-page-right figcaption table{background:#fff}#quarto-content.page-columns #quarto-margin-sidebar,#quarto-content.page-columns #quarto-sidebar{z-index:1}@media(max-width: 991.98px){#quarto-content.page-columns #quarto-margin-sidebar.collapse,#quarto-content.page-columns #quarto-sidebar.collapse,#quarto-content.page-columns #quarto-margin-sidebar.collapsing,#quarto-content.page-columns #quarto-sidebar.collapsing{z-index:1055}}#quarto-content.page-columns main.column-page,#quarto-content.page-columns main.column-page-right,#quarto-content.page-columns main.column-page-left{z-index:0}.page-columns .column-screen-inset{grid-column:screen-start-inset/screen-end-inset;z-index:998;opacity:.999}.page-columns .column-screen-inset table{background:#fff}.page-columns .column-screen-inset-left{grid-column:screen-start-inset/body-content-end;z-index:998;opacity:.999}.page-columns .column-screen-inset-left table{background:#fff}.page-columns .column-screen-inset-right{grid-column:body-content-start/screen-end-inset;z-index:998;opacity:.999}.page-columns .column-screen-inset-right table{background:#fff}.page-columns .column-screen{grid-column:screen-start/screen-end;z-index:998;opacity:.999}.page-columns .column-screen table{background:#fff}.page-columns .column-screen-left{grid-column:screen-start/body-content-end;z-index:998;opacity:.999}.page-columns .column-screen-left table{background:#fff}.page-columns .column-screen-right{grid-column:body-content-start/screen-end;z-index:998;opacity:.999}.page-columns .column-screen-right table{background:#fff}.page-columns .column-screen-inset-shaded{grid-column:screen-start/screen-end;padding:1em;background:#f8f9fa;z-index:998;opacity:.999;margin-bottom:1em}.zindex-content{z-index:998;opacity:.999}.zindex-modal{z-index:1055;opacity:.999}.zindex-over-content{z-index:999;opacity:.999}img.img-fluid.column-screen,img.img-fluid.column-screen-inset-shaded,img.img-fluid.column-screen-inset,img.img-fluid.column-screen-inset-left,img.img-fluid.column-screen-inset-right,img.img-fluid.column-screen-left,img.img-fluid.column-screen-right{width:100%}@media(min-width: 992px){.margin-caption,div.aside,aside:not(.footnotes):not(.sidebar),.column-margin{grid-column:body-end/page-end !important;z-index:998}.column-sidebar{grid-column:page-start/body-start !important;z-index:998}.column-leftmargin{grid-column:screen-start-inset/body-start !important;z-index:998}.no-row-height{height:1em;overflow:visible}}@media(max-width: 991.98px){.margin-caption,div.aside,aside:not(.footnotes):not(.sidebar),.column-margin{grid-column:body-end/page-end !important;z-index:998}.no-row-height{height:1em;overflow:visible}.page-columns.page-full{overflow:visible}.page-columns.toc-left .margin-caption,.page-columns.toc-left div.aside,.page-columns.toc-left aside:not(.footnotes):not(.sidebar),.page-columns.toc-left .column-margin{grid-column:body-content-start/body-content-end !important;z-index:998;opacity:.999}.page-columns.toc-left .no-row-height{height:initial;overflow:initial}}@media(max-width: 767.98px){.margin-caption,div.aside,aside:not(.footnotes):not(.sidebar),.column-margin{grid-column:body-content-start/body-content-end !important;z-index:998;opacity:.999}.no-row-height{height:initial;overflow:initial}#quarto-margin-sidebar{display:none}#quarto-sidebar-toc-left{display:none}.hidden-sm{display:none}}.panel-grid{display:grid;grid-template-rows:repeat(1, 1fr);grid-template-columns:repeat(24, 1fr);gap:1em}.panel-grid .g-col-1{grid-column:auto/span 1}.panel-grid .g-col-2{grid-column:auto/span 2}.panel-grid .g-col-3{grid-column:auto/span 3}.panel-grid .g-col-4{grid-column:auto/span 4}.panel-grid .g-col-5{grid-column:auto/span 5}.panel-grid .g-col-6{grid-column:auto/span 6}.panel-grid .g-col-7{grid-column:auto/span 7}.panel-grid .g-col-8{grid-column:auto/span 8}.panel-grid .g-col-9{grid-column:auto/span 9}.panel-grid .g-col-10{grid-column:auto/span 10}.panel-grid .g-col-11{grid-column:auto/span 11}.panel-grid .g-col-12{grid-column:auto/span 12}.panel-grid .g-col-13{grid-column:auto/span 13}.panel-grid .g-col-14{grid-column:auto/span 14}.panel-grid .g-col-15{grid-column:auto/span 15}.panel-grid .g-col-16{grid-column:auto/span 16}.panel-grid .g-col-17{grid-column:auto/span 17}.panel-grid .g-col-18{grid-column:auto/span 18}.panel-grid .g-col-19{grid-column:auto/span 19}.panel-grid .g-col-20{grid-column:auto/span 20}.panel-grid .g-col-21{grid-column:auto/span 21}.panel-grid .g-col-22{grid-column:auto/span 22}.panel-grid .g-col-23{grid-column:auto/span 23}.panel-grid .g-col-24{grid-column:auto/span 24}.panel-grid .g-start-1{grid-column-start:1}.panel-grid .g-start-2{grid-column-start:2}.panel-grid .g-start-3{grid-column-start:3}.panel-grid .g-start-4{grid-column-start:4}.panel-grid .g-start-5{grid-column-start:5}.panel-grid .g-start-6{grid-column-start:6}.panel-grid .g-start-7{grid-column-start:7}.panel-grid .g-start-8{grid-column-start:8}.panel-grid .g-start-9{grid-column-start:9}.panel-grid .g-start-10{grid-column-start:10}.panel-grid .g-start-11{grid-column-start:11}.panel-grid .g-start-12{grid-column-start:12}.panel-grid .g-start-13{grid-column-start:13}.panel-grid .g-start-14{grid-column-start:14}.panel-grid .g-start-15{grid-column-start:15}.panel-grid .g-start-16{grid-column-start:16}.panel-grid .g-start-17{grid-column-start:17}.panel-grid .g-start-18{grid-column-start:18}.panel-grid .g-start-19{grid-column-start:19}.panel-grid .g-start-20{grid-column-start:20}.panel-grid .g-start-21{grid-column-start:21}.panel-grid .g-start-22{grid-column-start:22}.panel-grid .g-start-23{grid-column-start:23}@media(min-width: 576px){.panel-grid .g-col-sm-1{grid-column:auto/span 1}.panel-grid .g-col-sm-2{grid-column:auto/span 2}.panel-grid .g-col-sm-3{grid-column:auto/span 3}.panel-grid .g-col-sm-4{grid-column:auto/span 4}.panel-grid .g-col-sm-5{grid-column:auto/span 5}.panel-grid .g-col-sm-6{grid-column:auto/span 6}.panel-grid .g-col-sm-7{grid-column:auto/span 7}.panel-grid .g-col-sm-8{grid-column:auto/span 8}.panel-grid .g-col-sm-9{grid-column:auto/span 9}.panel-grid .g-col-sm-10{grid-column:auto/span 10}.panel-grid .g-col-sm-11{grid-column:auto/span 11}.panel-grid .g-col-sm-12{grid-column:auto/span 12}.panel-grid .g-col-sm-13{grid-column:auto/span 13}.panel-grid .g-col-sm-14{grid-column:auto/span 14}.panel-grid .g-col-sm-15{grid-column:auto/span 15}.panel-grid .g-col-sm-16{grid-column:auto/span 16}.panel-grid .g-col-sm-17{grid-column:auto/span 17}.panel-grid .g-col-sm-18{grid-column:auto/span 18}.panel-grid .g-col-sm-19{grid-column:auto/span 19}.panel-grid .g-col-sm-20{grid-column:auto/span 20}.panel-grid .g-col-sm-21{grid-column:auto/span 21}.panel-grid .g-col-sm-22{grid-column:auto/span 22}.panel-grid .g-col-sm-23{grid-column:auto/span 23}.panel-grid .g-col-sm-24{grid-column:auto/span 24}.panel-grid .g-start-sm-1{grid-column-start:1}.panel-grid .g-start-sm-2{grid-column-start:2}.panel-grid .g-start-sm-3{grid-column-start:3}.panel-grid .g-start-sm-4{grid-column-start:4}.panel-grid .g-start-sm-5{grid-column-start:5}.panel-grid .g-start-sm-6{grid-column-start:6}.panel-grid .g-start-sm-7{grid-column-start:7}.panel-grid .g-start-sm-8{grid-column-start:8}.panel-grid .g-start-sm-9{grid-column-start:9}.panel-grid .g-start-sm-10{grid-column-start:10}.panel-grid .g-start-sm-11{grid-column-start:11}.panel-grid .g-start-sm-12{grid-column-start:12}.panel-grid .g-start-sm-13{grid-column-start:13}.panel-grid .g-start-sm-14{grid-column-start:14}.panel-grid .g-start-sm-15{grid-column-start:15}.panel-grid .g-start-sm-16{grid-column-start:16}.panel-grid .g-start-sm-17{grid-column-start:17}.panel-grid .g-start-sm-18{grid-column-start:18}.panel-grid .g-start-sm-19{grid-column-start:19}.panel-grid .g-start-sm-20{grid-column-start:20}.panel-grid .g-start-sm-21{grid-column-start:21}.panel-grid .g-start-sm-22{grid-column-start:22}.panel-grid .g-start-sm-23{grid-column-start:23}}@media(min-width: 768px){.panel-grid .g-col-md-1{grid-column:auto/span 1}.panel-grid .g-col-md-2{grid-column:auto/span 2}.panel-grid .g-col-md-3{grid-column:auto/span 3}.panel-grid .g-col-md-4{grid-column:auto/span 4}.panel-grid .g-col-md-5{grid-column:auto/span 5}.panel-grid .g-col-md-6{grid-column:auto/span 6}.panel-grid .g-col-md-7{grid-column:auto/span 7}.panel-grid .g-col-md-8{grid-column:auto/span 8}.panel-grid .g-col-md-9{grid-column:auto/span 9}.panel-grid .g-col-md-10{grid-column:auto/span 10}.panel-grid .g-col-md-11{grid-column:auto/span 11}.panel-grid .g-col-md-12{grid-column:auto/span 12}.panel-grid .g-col-md-13{grid-column:auto/span 13}.panel-grid .g-col-md-14{grid-column:auto/span 14}.panel-grid .g-col-md-15{grid-column:auto/span 15}.panel-grid .g-col-md-16{grid-column:auto/span 16}.panel-grid .g-col-md-17{grid-column:auto/span 17}.panel-grid .g-col-md-18{grid-column:auto/span 18}.panel-grid .g-col-md-19{grid-column:auto/span 19}.panel-grid .g-col-md-20{grid-column:auto/span 20}.panel-grid .g-col-md-21{grid-column:auto/span 21}.panel-grid .g-col-md-22{grid-column:auto/span 22}.panel-grid .g-col-md-23{grid-column:auto/span 23}.panel-grid .g-col-md-24{grid-column:auto/span 24}.panel-grid .g-start-md-1{grid-column-start:1}.panel-grid .g-start-md-2{grid-column-start:2}.panel-grid .g-start-md-3{grid-column-start:3}.panel-grid .g-start-md-4{grid-column-start:4}.panel-grid .g-start-md-5{grid-column-start:5}.panel-grid .g-start-md-6{grid-column-start:6}.panel-grid .g-start-md-7{grid-column-start:7}.panel-grid .g-start-md-8{grid-column-start:8}.panel-grid .g-start-md-9{grid-column-start:9}.panel-grid .g-start-md-10{grid-column-start:10}.panel-grid .g-start-md-11{grid-column-start:11}.panel-grid .g-start-md-12{grid-column-start:12}.panel-grid .g-start-md-13{grid-column-start:13}.panel-grid .g-start-md-14{grid-column-start:14}.panel-grid .g-start-md-15{grid-column-start:15}.panel-grid .g-start-md-16{grid-column-start:16}.panel-grid .g-start-md-17{grid-column-start:17}.panel-grid .g-start-md-18{grid-column-start:18}.panel-grid .g-start-md-19{grid-column-start:19}.panel-grid .g-start-md-20{grid-column-start:20}.panel-grid .g-start-md-21{grid-column-start:21}.panel-grid .g-start-md-22{grid-column-start:22}.panel-grid .g-start-md-23{grid-column-start:23}}@media(min-width: 992px){.panel-grid .g-col-lg-1{grid-column:auto/span 1}.panel-grid .g-col-lg-2{grid-column:auto/span 2}.panel-grid .g-col-lg-3{grid-column:auto/span 3}.panel-grid .g-col-lg-4{grid-column:auto/span 4}.panel-grid .g-col-lg-5{grid-column:auto/span 5}.panel-grid .g-col-lg-6{grid-column:auto/span 6}.panel-grid .g-col-lg-7{grid-column:auto/span 7}.panel-grid .g-col-lg-8{grid-column:auto/span 8}.panel-grid .g-col-lg-9{grid-column:auto/span 9}.panel-grid .g-col-lg-10{grid-column:auto/span 10}.panel-grid .g-col-lg-11{grid-column:auto/span 11}.panel-grid .g-col-lg-12{grid-column:auto/span 12}.panel-grid .g-col-lg-13{grid-column:auto/span 13}.panel-grid .g-col-lg-14{grid-column:auto/span 14}.panel-grid .g-col-lg-15{grid-column:auto/span 15}.panel-grid .g-col-lg-16{grid-column:auto/span 16}.panel-grid .g-col-lg-17{grid-column:auto/span 17}.panel-grid .g-col-lg-18{grid-column:auto/span 18}.panel-grid .g-col-lg-19{grid-column:auto/span 19}.panel-grid .g-col-lg-20{grid-column:auto/span 20}.panel-grid .g-col-lg-21{grid-column:auto/span 21}.panel-grid .g-col-lg-22{grid-column:auto/span 22}.panel-grid .g-col-lg-23{grid-column:auto/span 23}.panel-grid .g-col-lg-24{grid-column:auto/span 24}.panel-grid .g-start-lg-1{grid-column-start:1}.panel-grid .g-start-lg-2{grid-column-start:2}.panel-grid .g-start-lg-3{grid-column-start:3}.panel-grid .g-start-lg-4{grid-column-start:4}.panel-grid .g-start-lg-5{grid-column-start:5}.panel-grid .g-start-lg-6{grid-column-start:6}.panel-grid .g-start-lg-7{grid-column-start:7}.panel-grid .g-start-lg-8{grid-column-start:8}.panel-grid .g-start-lg-9{grid-column-start:9}.panel-grid .g-start-lg-10{grid-column-start:10}.panel-grid .g-start-lg-11{grid-column-start:11}.panel-grid .g-start-lg-12{grid-column-start:12}.panel-grid .g-start-lg-13{grid-column-start:13}.panel-grid .g-start-lg-14{grid-column-start:14}.panel-grid .g-start-lg-15{grid-column-start:15}.panel-grid .g-start-lg-16{grid-column-start:16}.panel-grid .g-start-lg-17{grid-column-start:17}.panel-grid .g-start-lg-18{grid-column-start:18}.panel-grid .g-start-lg-19{grid-column-start:19}.panel-grid .g-start-lg-20{grid-column-start:20}.panel-grid .g-start-lg-21{grid-column-start:21}.panel-grid .g-start-lg-22{grid-column-start:22}.panel-grid .g-start-lg-23{grid-column-start:23}}@media(min-width: 1200px){.panel-grid .g-col-xl-1{grid-column:auto/span 1}.panel-grid .g-col-xl-2{grid-column:auto/span 2}.panel-grid .g-col-xl-3{grid-column:auto/span 3}.panel-grid .g-col-xl-4{grid-column:auto/span 4}.panel-grid .g-col-xl-5{grid-column:auto/span 5}.panel-grid .g-col-xl-6{grid-column:auto/span 6}.panel-grid .g-col-xl-7{grid-column:auto/span 7}.panel-grid .g-col-xl-8{grid-column:auto/span 8}.panel-grid .g-col-xl-9{grid-column:auto/span 9}.panel-grid .g-col-xl-10{grid-column:auto/span 10}.panel-grid .g-col-xl-11{grid-column:auto/span 11}.panel-grid .g-col-xl-12{grid-column:auto/span 12}.panel-grid .g-col-xl-13{grid-column:auto/span 13}.panel-grid .g-col-xl-14{grid-column:auto/span 14}.panel-grid .g-col-xl-15{grid-column:auto/span 15}.panel-grid .g-col-xl-16{grid-column:auto/span 16}.panel-grid .g-col-xl-17{grid-column:auto/span 17}.panel-grid .g-col-xl-18{grid-column:auto/span 18}.panel-grid .g-col-xl-19{grid-column:auto/span 19}.panel-grid .g-col-xl-20{grid-column:auto/span 20}.panel-grid .g-col-xl-21{grid-column:auto/span 21}.panel-grid .g-col-xl-22{grid-column:auto/span 22}.panel-grid .g-col-xl-23{grid-column:auto/span 23}.panel-grid .g-col-xl-24{grid-column:auto/span 24}.panel-grid .g-start-xl-1{grid-column-start:1}.panel-grid .g-start-xl-2{grid-column-start:2}.panel-grid .g-start-xl-3{grid-column-start:3}.panel-grid .g-start-xl-4{grid-column-start:4}.panel-grid .g-start-xl-5{grid-column-start:5}.panel-grid .g-start-xl-6{grid-column-start:6}.panel-grid .g-start-xl-7{grid-column-start:7}.panel-grid .g-start-xl-8{grid-column-start:8}.panel-grid .g-start-xl-9{grid-column-start:9}.panel-grid .g-start-xl-10{grid-column-start:10}.panel-grid .g-start-xl-11{grid-column-start:11}.panel-grid .g-start-xl-12{grid-column-start:12}.panel-grid .g-start-xl-13{grid-column-start:13}.panel-grid .g-start-xl-14{grid-column-start:14}.panel-grid .g-start-xl-15{grid-column-start:15}.panel-grid .g-start-xl-16{grid-column-start:16}.panel-grid .g-start-xl-17{grid-column-start:17}.panel-grid .g-start-xl-18{grid-column-start:18}.panel-grid .g-start-xl-19{grid-column-start:19}.panel-grid .g-start-xl-20{grid-column-start:20}.panel-grid .g-start-xl-21{grid-column-start:21}.panel-grid .g-start-xl-22{grid-column-start:22}.panel-grid .g-start-xl-23{grid-column-start:23}}@media(min-width: 1400px){.panel-grid .g-col-xxl-1{grid-column:auto/span 1}.panel-grid .g-col-xxl-2{grid-column:auto/span 2}.panel-grid .g-col-xxl-3{grid-column:auto/span 3}.panel-grid .g-col-xxl-4{grid-column:auto/span 4}.panel-grid .g-col-xxl-5{grid-column:auto/span 5}.panel-grid .g-col-xxl-6{grid-column:auto/span 6}.panel-grid .g-col-xxl-7{grid-column:auto/span 7}.panel-grid .g-col-xxl-8{grid-column:auto/span 8}.panel-grid .g-col-xxl-9{grid-column:auto/span 9}.panel-grid .g-col-xxl-10{grid-column:auto/span 10}.panel-grid .g-col-xxl-11{grid-column:auto/span 11}.panel-grid .g-col-xxl-12{grid-column:auto/span 12}.panel-grid .g-col-xxl-13{grid-column:auto/span 13}.panel-grid .g-col-xxl-14{grid-column:auto/span 14}.panel-grid .g-col-xxl-15{grid-column:auto/span 15}.panel-grid .g-col-xxl-16{grid-column:auto/span 16}.panel-grid .g-col-xxl-17{grid-column:auto/span 17}.panel-grid .g-col-xxl-18{grid-column:auto/span 18}.panel-grid .g-col-xxl-19{grid-column:auto/span 19}.panel-grid .g-col-xxl-20{grid-column:auto/span 20}.panel-grid .g-col-xxl-21{grid-column:auto/span 21}.panel-grid .g-col-xxl-22{grid-column:auto/span 22}.panel-grid .g-col-xxl-23{grid-column:auto/span 23}.panel-grid .g-col-xxl-24{grid-column:auto/span 24}.panel-grid .g-start-xxl-1{grid-column-start:1}.panel-grid .g-start-xxl-2{grid-column-start:2}.panel-grid .g-start-xxl-3{grid-column-start:3}.panel-grid .g-start-xxl-4{grid-column-start:4}.panel-grid .g-start-xxl-5{grid-column-start:5}.panel-grid .g-start-xxl-6{grid-column-start:6}.panel-grid .g-start-xxl-7{grid-column-start:7}.panel-grid .g-start-xxl-8{grid-column-start:8}.panel-grid .g-start-xxl-9{grid-column-start:9}.panel-grid .g-start-xxl-10{grid-column-start:10}.panel-grid .g-start-xxl-11{grid-column-start:11}.panel-grid .g-start-xxl-12{grid-column-start:12}.panel-grid .g-start-xxl-13{grid-column-start:13}.panel-grid .g-start-xxl-14{grid-column-start:14}.panel-grid .g-start-xxl-15{grid-column-start:15}.panel-grid .g-start-xxl-16{grid-column-start:16}.panel-grid .g-start-xxl-17{grid-column-start:17}.panel-grid .g-start-xxl-18{grid-column-start:18}.panel-grid .g-start-xxl-19{grid-column-start:19}.panel-grid .g-start-xxl-20{grid-column-start:20}.panel-grid .g-start-xxl-21{grid-column-start:21}.panel-grid .g-start-xxl-22{grid-column-start:22}.panel-grid .g-start-xxl-23{grid-column-start:23}}main{margin-top:1em;margin-bottom:1em}h1,.h1,h2,.h2{color:inherit;margin-top:2rem;margin-bottom:1rem;font-weight:600}h1.title,.title.h1{margin-top:0}main.content>section:first-of-type>h2:first-child,main.content>section:first-of-type>.h2:first-child{margin-top:0}h2,.h2{border-bottom:1px solid #dee2e6;padding-bottom:.5rem}h3,.h3{font-weight:600}h3,.h3,h4,.h4{opacity:.9;margin-top:1.5rem}h5,.h5,h6,.h6{opacity:.9}.header-section-number{color:#5a6570}.nav-link.active .header-section-number{color:inherit}mark,.mark{padding:0em}.panel-caption,.figure-caption,.subfigure-caption,.table-caption,figcaption,caption{font-size:.9rem;color:#5a6570}.quarto-layout-cell[data-ref-parent] caption{color:#5a6570}.column-margin figcaption,.margin-caption,div.aside,aside,.column-margin{color:#5a6570;font-size:.825rem}.panel-caption.margin-caption{text-align:inherit}.column-margin.column-container p{margin-bottom:0}.column-margin.column-container>*:not(.collapse):first-child{padding-bottom:.5em;display:block}.column-margin.column-container>*:not(.collapse):not(:first-child){padding-top:.5em;padding-bottom:.5em;display:block}.column-margin.column-container>*.collapse:not(.show){display:none}@media(min-width: 768px){.column-margin.column-container .callout-margin-content:first-child{margin-top:4.5em}.column-margin.column-container .callout-margin-content-simple:first-child{margin-top:3.5em}}.margin-caption>*{padding-top:.5em;padding-bottom:.5em}@media(max-width: 767.98px){.quarto-layout-row{flex-direction:column}}.nav-tabs .nav-item{margin-top:1px;cursor:pointer}.tab-content{margin-top:0px;border-left:#dee2e6 1px solid;border-right:#dee2e6 1px solid;border-bottom:#dee2e6 1px solid;margin-left:0;padding:1em;margin-bottom:1em}@media(max-width: 767.98px){.layout-sidebar{margin-left:0;margin-right:0}}.panel-sidebar,.panel-sidebar .form-control,.panel-input,.panel-input .form-control,.selectize-dropdown{font-size:.9rem}.panel-sidebar .form-control,.panel-input .form-control{padding-top:.1rem}.tab-pane div.sourceCode{margin-top:0px}.tab-pane>p{padding-top:0}.tab-pane>p:nth-child(1){padding-top:0}.tab-pane>p:last-child{margin-bottom:0}.tab-pane>pre:last-child{margin-bottom:0}.tab-content>.tab-pane:not(.active){display:none !important}div.sourceCode{background-color:rgba(233,236,239,.65);border:1px solid rgba(233,236,239,.65);border-radius:.375rem}pre.sourceCode{background-color:rgba(0,0,0,0)}pre.sourceCode{border:none;font-size:.875em;overflow:visible !important;padding:.4em}.callout pre.sourceCode{padding-left:0}div.sourceCode{overflow-y:hidden}.callout div.sourceCode{margin-left:initial}.blockquote{font-size:inherit;padding-left:1rem;padding-right:1.5rem;color:#5a6570}.blockquote h1:first-child,.blockquote .h1:first-child,.blockquote h2:first-child,.blockquote .h2:first-child,.blockquote h3:first-child,.blockquote .h3:first-child,.blockquote h4:first-child,.blockquote .h4:first-child,.blockquote h5:first-child,.blockquote .h5:first-child{margin-top:0}pre{background-color:initial;padding:initial;border:initial}p pre code:not(.sourceCode),li pre code:not(.sourceCode),pre code:not(.sourceCode){background-color:initial}p code:not(.sourceCode),li code:not(.sourceCode),td code:not(.sourceCode){background-color:#f8f9fa;padding:.2em}nav p code:not(.sourceCode),nav li code:not(.sourceCode),nav td code:not(.sourceCode){background-color:rgba(0,0,0,0);padding:0}td code:not(.sourceCode){white-space:pre-wrap}#quarto-embedded-source-code-modal>.modal-dialog{max-width:1000px;padding-left:1.75rem;padding-right:1.75rem}#quarto-embedded-source-code-modal>.modal-dialog>.modal-content>.modal-body{padding:0}#quarto-embedded-source-code-modal>.modal-dialog>.modal-content>.modal-body div.sourceCode{margin:0;padding:.2rem .2rem;border-radius:0px;border:none}#quarto-embedded-source-code-modal>.modal-dialog>.modal-content>.modal-header{padding:.7rem}.code-tools-button{font-size:1rem;padding:.15rem .15rem;margin-left:5px;color:rgba(33,37,41,.75);background-color:rgba(0,0,0,0);transition:initial;cursor:pointer}.code-tools-button>.bi::before{display:inline-block;height:1rem;width:1rem;content:"";vertical-align:-0.125em;background-image:url('data:image/svg+xml,');background-repeat:no-repeat;background-size:1rem 1rem}.code-tools-button:hover>.bi::before{background-image:url('data:image/svg+xml,')}#quarto-embedded-source-code-modal .code-copy-button>.bi::before{background-image:url('data:image/svg+xml,')}#quarto-embedded-source-code-modal .code-copy-button-checked>.bi::before{background-image:url('data:image/svg+xml,')}.sidebar{will-change:top;transition:top 200ms linear;position:sticky;overflow-y:auto;padding-top:1.2em;max-height:100vh}.sidebar.toc-left,.sidebar.margin-sidebar{top:0px;padding-top:1em}.sidebar.quarto-banner-title-block-sidebar>*{padding-top:1.65em}figure .quarto-notebook-link{margin-top:.5em}.quarto-notebook-link{font-size:.75em;color:rgba(33,37,41,.75);margin-bottom:1em;text-decoration:none;display:block}.quarto-notebook-link:hover{text-decoration:underline;color:#0d6efd}.quarto-notebook-link::before{display:inline-block;height:.75rem;width:.75rem;margin-bottom:0em;margin-right:.25em;content:"";vertical-align:-0.125em;background-image:url('data:image/svg+xml,');background-repeat:no-repeat;background-size:.75rem .75rem}.toc-actions i.bi,.quarto-code-links i.bi,.quarto-other-links i.bi,.quarto-alternate-notebooks i.bi,.quarto-alternate-formats i.bi{margin-right:.4em;font-size:.8rem}.quarto-other-links-text-target .quarto-code-links i.bi,.quarto-other-links-text-target .quarto-other-links i.bi{margin-right:.2em}.quarto-other-formats-text-target .quarto-alternate-formats i.bi{margin-right:.1em}.toc-actions i.bi.empty,.quarto-code-links i.bi.empty,.quarto-other-links i.bi.empty,.quarto-alternate-notebooks i.bi.empty,.quarto-alternate-formats i.bi.empty{padding-left:1em}.quarto-notebook h2,.quarto-notebook .h2{border-bottom:none}.quarto-notebook .cell-container{display:flex}.quarto-notebook .cell-container .cell{flex-grow:4}.quarto-notebook .cell-container .cell-decorator{padding-top:1.5em;padding-right:1em;text-align:right}.quarto-notebook .cell-container.code-fold .cell-decorator{padding-top:3em}.quarto-notebook .cell-code code{white-space:pre-wrap}.quarto-notebook .cell .cell-output-stderr pre code,.quarto-notebook .cell .cell-output-stdout pre code{white-space:pre-wrap;overflow-wrap:anywhere}.toc-actions,.quarto-alternate-formats,.quarto-other-links,.quarto-code-links,.quarto-alternate-notebooks{padding-left:0em}.sidebar .toc-actions a,.sidebar .quarto-alternate-formats a,.sidebar .quarto-other-links a,.sidebar .quarto-code-links a,.sidebar .quarto-alternate-notebooks a,.sidebar nav[role=doc-toc] a{text-decoration:none}.sidebar .toc-actions a:hover,.sidebar .quarto-other-links a:hover,.sidebar .quarto-code-links a:hover,.sidebar .quarto-alternate-formats a:hover,.sidebar .quarto-alternate-notebooks a:hover{color:#0d6efd}.sidebar .toc-actions h2,.sidebar .toc-actions .h2,.sidebar .quarto-code-links h2,.sidebar .quarto-code-links .h2,.sidebar .quarto-other-links h2,.sidebar .quarto-other-links .h2,.sidebar .quarto-alternate-notebooks h2,.sidebar .quarto-alternate-notebooks .h2,.sidebar .quarto-alternate-formats h2,.sidebar .quarto-alternate-formats .h2,.sidebar nav[role=doc-toc]>h2,.sidebar nav[role=doc-toc]>.h2{font-weight:500;margin-bottom:.2rem;margin-top:.3rem;font-family:inherit;border-bottom:0;padding-bottom:0;padding-top:0px}.sidebar .toc-actions>h2,.sidebar .toc-actions>.h2,.sidebar .quarto-code-links>h2,.sidebar .quarto-code-links>.h2,.sidebar .quarto-other-links>h2,.sidebar .quarto-other-links>.h2,.sidebar .quarto-alternate-notebooks>h2,.sidebar .quarto-alternate-notebooks>.h2,.sidebar .quarto-alternate-formats>h2,.sidebar .quarto-alternate-formats>.h2{font-size:.8rem}.sidebar nav[role=doc-toc]>h2,.sidebar nav[role=doc-toc]>.h2{font-size:.875rem}.sidebar nav[role=doc-toc]>ul a{border-left:1px solid #e9ecef;padding-left:.6rem}.sidebar .toc-actions h2>ul a,.sidebar .toc-actions .h2>ul a,.sidebar .quarto-code-links h2>ul a,.sidebar .quarto-code-links .h2>ul a,.sidebar .quarto-other-links h2>ul a,.sidebar .quarto-other-links .h2>ul a,.sidebar .quarto-alternate-notebooks h2>ul a,.sidebar .quarto-alternate-notebooks .h2>ul a,.sidebar .quarto-alternate-formats h2>ul a,.sidebar .quarto-alternate-formats .h2>ul a{border-left:none;padding-left:.6rem}.sidebar .toc-actions ul a:empty,.sidebar .quarto-code-links ul a:empty,.sidebar .quarto-other-links ul a:empty,.sidebar .quarto-alternate-notebooks ul a:empty,.sidebar .quarto-alternate-formats ul a:empty,.sidebar nav[role=doc-toc]>ul a:empty{display:none}.sidebar .toc-actions ul,.sidebar .quarto-code-links ul,.sidebar .quarto-other-links ul,.sidebar .quarto-alternate-notebooks ul,.sidebar .quarto-alternate-formats ul{padding-left:0;list-style:none}.sidebar nav[role=doc-toc] ul{list-style:none;padding-left:0;list-style:none}.sidebar nav[role=doc-toc]>ul{margin-left:.45em}.quarto-margin-sidebar nav[role=doc-toc]{padding-left:.5em}.sidebar .toc-actions>ul,.sidebar .quarto-code-links>ul,.sidebar .quarto-other-links>ul,.sidebar .quarto-alternate-notebooks>ul,.sidebar .quarto-alternate-formats>ul{font-size:.8rem}.sidebar nav[role=doc-toc]>ul{font-size:.875rem}.sidebar .toc-actions ul li a,.sidebar .quarto-code-links ul li a,.sidebar .quarto-other-links ul li a,.sidebar .quarto-alternate-notebooks ul li a,.sidebar .quarto-alternate-formats ul li a,.sidebar nav[role=doc-toc]>ul li a{line-height:1.1rem;padding-bottom:.2rem;padding-top:.2rem;color:inherit}.sidebar nav[role=doc-toc] ul>li>ul>li>a{padding-left:1.2em}.sidebar nav[role=doc-toc] ul>li>ul>li>ul>li>a{padding-left:2.4em}.sidebar nav[role=doc-toc] ul>li>ul>li>ul>li>ul>li>a{padding-left:3.6em}.sidebar nav[role=doc-toc] ul>li>ul>li>ul>li>ul>li>ul>li>a{padding-left:4.8em}.sidebar nav[role=doc-toc] ul>li>ul>li>ul>li>ul>li>ul>li>ul>li>a{padding-left:6em}.sidebar nav[role=doc-toc] ul>li>a.active,.sidebar nav[role=doc-toc] ul>li>ul>li>a.active{border-left:1px solid #0d6efd;color:#0d6efd !important}.sidebar nav[role=doc-toc] ul>li>a:hover,.sidebar nav[role=doc-toc] ul>li>ul>li>a:hover{color:#0d6efd !important}kbd,.kbd{color:#212529;background-color:#f8f9fa;border:1px solid;border-radius:5px;border-color:#dee2e6}.quarto-appendix-contents div.hanging-indent{margin-left:0em}.quarto-appendix-contents div.hanging-indent div.csl-entry{margin-left:1em;text-indent:-1em}.citation a,.footnote-ref{text-decoration:none}.footnotes ol{padding-left:1em}.tippy-content>*{margin-bottom:.7em}.tippy-content>*:last-child{margin-bottom:0}.callout{margin-top:1.25rem;margin-bottom:1.25rem;border-radius:.375rem;overflow-wrap:break-word}.callout .callout-title-container{overflow-wrap:anywhere}.callout.callout-style-simple{padding:.4em .7em;border-left:5px solid;border-right:1px solid #dee2e6;border-top:1px solid #dee2e6;border-bottom:1px solid #dee2e6}.callout.callout-style-default{border-left:5px solid;border-right:1px solid #dee2e6;border-top:1px solid #dee2e6;border-bottom:1px solid #dee2e6}.callout .callout-body-container{flex-grow:1}.callout.callout-style-simple .callout-body{font-size:.9rem;font-weight:400}.callout.callout-style-default .callout-body{font-size:.9rem;font-weight:400}.callout:not(.no-icon).callout-titled.callout-style-simple .callout-body{padding-left:1.6em}.callout.callout-titled>.callout-header{padding-top:.2em;margin-bottom:-0.2em}.callout.callout-style-simple>div.callout-header{border-bottom:none;font-size:.9rem;font-weight:600;opacity:75%}.callout.callout-style-default>div.callout-header{border-bottom:none;font-weight:600;opacity:85%;font-size:.9rem;padding-left:.5em;padding-right:.5em}.callout.callout-style-default .callout-body{padding-left:.5em;padding-right:.5em}.callout.callout-style-default .callout-body>:first-child{padding-top:.5rem;margin-top:0}.callout>div.callout-header[data-bs-toggle=collapse]{cursor:pointer}.callout.callout-style-default .callout-header[aria-expanded=false],.callout.callout-style-default .callout-header[aria-expanded=true]{padding-top:0px;margin-bottom:0px;align-items:center}.callout.callout-titled .callout-body>:last-child:not(.sourceCode),.callout.callout-titled .callout-body>div>:last-child:not(.sourceCode){padding-bottom:.5rem;margin-bottom:0}.callout:not(.callout-titled) .callout-body>:first-child,.callout:not(.callout-titled) .callout-body>div>:first-child{margin-top:.25rem}.callout:not(.callout-titled) .callout-body>:last-child,.callout:not(.callout-titled) .callout-body>div>:last-child{margin-bottom:.2rem}.callout.callout-style-simple .callout-icon::before,.callout.callout-style-simple .callout-toggle::before{height:1rem;width:1rem;display:inline-block;content:"";background-repeat:no-repeat;background-size:1rem 1rem}.callout.callout-style-default .callout-icon::before,.callout.callout-style-default .callout-toggle::before{height:.9rem;width:.9rem;display:inline-block;content:"";background-repeat:no-repeat;background-size:.9rem .9rem}.callout.callout-style-default .callout-toggle::before{margin-top:5px}.callout .callout-btn-toggle .callout-toggle::before{transition:transform .2s linear}.callout .callout-header[aria-expanded=false] .callout-toggle::before{transform:rotate(-90deg)}.callout .callout-header[aria-expanded=true] .callout-toggle::before{transform:none}.callout.callout-style-simple:not(.no-icon) div.callout-icon-container{padding-top:.2em;padding-right:.55em}.callout.callout-style-default:not(.no-icon) div.callout-icon-container{padding-top:.1em;padding-right:.35em}.callout.callout-style-default:not(.no-icon) div.callout-title-container{margin-top:-1px}.callout.callout-style-default.callout-caution:not(.no-icon) div.callout-icon-container{padding-top:.3em;padding-right:.35em}.callout>.callout-body>.callout-icon-container>.no-icon,.callout>.callout-header>.callout-icon-container>.no-icon{display:none}div.callout.callout{border-left-color:rgba(33,37,41,.75)}div.callout.callout-style-default>.callout-header{background-color:rgba(33,37,41,.75)}div.callout-note.callout{border-left-color:#0d6efd}div.callout-note.callout-style-default>.callout-header{background-color:#e7f1ff}div.callout-note:not(.callout-titled) .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-note.callout-titled .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-note .callout-toggle::before{background-image:url('data:image/svg+xml,')}div.callout-tip.callout{border-left-color:#198754}div.callout-tip.callout-style-default>.callout-header{background-color:#e8f3ee}div.callout-tip:not(.callout-titled) .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-tip.callout-titled .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-tip .callout-toggle::before{background-image:url('data:image/svg+xml,')}div.callout-warning.callout{border-left-color:#ffc107}div.callout-warning.callout-style-default>.callout-header{background-color:#fff9e6}div.callout-warning:not(.callout-titled) .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-warning.callout-titled .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-warning .callout-toggle::before{background-image:url('data:image/svg+xml,')}div.callout-caution.callout{border-left-color:#fd7e14}div.callout-caution.callout-style-default>.callout-header{background-color:#fff2e8}div.callout-caution:not(.callout-titled) .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-caution.callout-titled .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-caution .callout-toggle::before{background-image:url('data:image/svg+xml,')}div.callout-important.callout{border-left-color:#dc3545}div.callout-important.callout-style-default>.callout-header{background-color:#fcebec}div.callout-important:not(.callout-titled) .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-important.callout-titled .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-important .callout-toggle::before{background-image:url('data:image/svg+xml,')}.quarto-toggle-container{display:flex;align-items:center}.quarto-reader-toggle .bi::before,.quarto-color-scheme-toggle .bi::before{display:inline-block;height:1rem;width:1rem;content:"";background-repeat:no-repeat;background-size:1rem 1rem}.sidebar-navigation{padding-left:20px}.navbar{background-color:#517699;color:#fdfefe}.navbar .quarto-color-scheme-toggle:not(.alternate) .bi::before{background-image:url('data:image/svg+xml,')}.navbar .quarto-color-scheme-toggle.alternate .bi::before{background-image:url('data:image/svg+xml,')}.sidebar-navigation .quarto-color-scheme-toggle:not(.alternate) .bi::before{background-image:url('data:image/svg+xml,')}.sidebar-navigation .quarto-color-scheme-toggle.alternate .bi::before{background-image:url('data:image/svg+xml,')}.quarto-sidebar-toggle{border-color:#dee2e6;border-bottom-left-radius:.375rem;border-bottom-right-radius:.375rem;border-style:solid;border-width:1px;overflow:hidden;border-top-width:0px;padding-top:0px !important}.quarto-sidebar-toggle-title{cursor:pointer;padding-bottom:2px;margin-left:.25em;text-align:center;font-weight:400;font-size:.775em}#quarto-content .quarto-sidebar-toggle{background:#fafafa}#quarto-content .quarto-sidebar-toggle-title{color:#212529}.quarto-sidebar-toggle-icon{color:#dee2e6;margin-right:.5em;float:right;transition:transform .2s ease}.quarto-sidebar-toggle-icon::before{padding-top:5px}.quarto-sidebar-toggle.expanded .quarto-sidebar-toggle-icon{transform:rotate(-180deg)}.quarto-sidebar-toggle.expanded .quarto-sidebar-toggle-title{border-bottom:solid #dee2e6 1px}.quarto-sidebar-toggle-contents{background-color:#fff;padding-right:10px;padding-left:10px;margin-top:0px !important;transition:max-height .5s ease}.quarto-sidebar-toggle.expanded .quarto-sidebar-toggle-contents{padding-top:1em;padding-bottom:10px}@media(max-width: 767.98px){.sidebar-menu-container{padding-bottom:5em}}.quarto-sidebar-toggle:not(.expanded) .quarto-sidebar-toggle-contents{padding-top:0px !important;padding-bottom:0px}nav[role=doc-toc]{z-index:1020}#quarto-sidebar>*,nav[role=doc-toc]>*{transition:opacity .1s ease,border .1s ease}#quarto-sidebar.slow>*,nav[role=doc-toc].slow>*{transition:opacity .4s ease,border .4s ease}.quarto-color-scheme-toggle:not(.alternate).top-right .bi::before{background-image:url('data:image/svg+xml,')}.quarto-color-scheme-toggle.alternate.top-right .bi::before{background-image:url('data:image/svg+xml,')}#quarto-appendix.default{border-top:1px solid #dee2e6}#quarto-appendix.default{background-color:#fff;padding-top:1.5em;margin-top:2em;z-index:998}#quarto-appendix.default .quarto-appendix-heading{margin-top:0;line-height:1.4em;font-weight:600;opacity:.9;border-bottom:none;margin-bottom:0}#quarto-appendix.default .footnotes ol,#quarto-appendix.default .footnotes ol li>p:last-of-type,#quarto-appendix.default .quarto-appendix-contents>p:last-of-type{margin-bottom:0}#quarto-appendix.default .footnotes ol{margin-left:.5em}#quarto-appendix.default .quarto-appendix-secondary-label{margin-bottom:.4em}#quarto-appendix.default .quarto-appendix-bibtex{font-size:.7em;padding:1em;border:solid 1px #dee2e6;margin-bottom:1em}#quarto-appendix.default .quarto-appendix-bibtex code.sourceCode{white-space:pre-wrap}#quarto-appendix.default .quarto-appendix-citeas{font-size:.9em;padding:1em;border:solid 1px #dee2e6;margin-bottom:1em}#quarto-appendix.default .quarto-appendix-heading{font-size:1em !important}#quarto-appendix.default *[role=doc-endnotes]>ol,#quarto-appendix.default .quarto-appendix-contents>*:not(h2):not(.h2){font-size:.9em}#quarto-appendix.default section{padding-bottom:1.5em}#quarto-appendix.default section *[role=doc-endnotes],#quarto-appendix.default section>*:not(a){opacity:.9;word-wrap:break-word}.btn.btn-quarto,div.cell-output-display .btn-quarto{--bs-btn-color: #fefefe;--bs-btn-bg: #6c757d;--bs-btn-border-color: #6c757d;--bs-btn-hover-color: #fefefe;--bs-btn-hover-bg: #828a91;--bs-btn-hover-border-color: #7b838a;--bs-btn-focus-shadow-rgb: 130, 138, 144;--bs-btn-active-color: #000;--bs-btn-active-bg: #899197;--bs-btn-active-border-color: #7b838a;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #ffffff;--bs-btn-disabled-bg: #6c757d;--bs-btn-disabled-border-color: #6c757d}nav.quarto-secondary-nav.color-navbar{background-color:#517699;color:#fdfefe}nav.quarto-secondary-nav.color-navbar h1,nav.quarto-secondary-nav.color-navbar .h1,nav.quarto-secondary-nav.color-navbar .quarto-btn-toggle{color:#fdfefe}@media(max-width: 991.98px){body.nav-sidebar .quarto-title-banner{margin-bottom:0;padding-bottom:1em}body.nav-sidebar #title-block-header{margin-block-end:0}}p.subtitle{margin-top:.25em;margin-bottom:.5em}code a:any-link{color:inherit;text-decoration-color:#6c757d}/*! light */div.observablehq table thead tr th{background-color:var(--bs-body-bg)}input,button,select,optgroup,textarea{background-color:var(--bs-body-bg)}.code-annotated .code-copy-button{margin-right:1.25em;margin-top:0;padding-bottom:0;padding-top:3px}.code-annotation-gutter-bg{background-color:#fff}.code-annotation-gutter{background-color:rgba(233,236,239,.65)}.code-annotation-gutter,.code-annotation-gutter-bg{height:100%;width:calc(20px + .5em);position:absolute;top:0;right:0}dl.code-annotation-container-grid dt{margin-right:1em;margin-top:.25rem}dl.code-annotation-container-grid dt{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;color:#383f45;border:solid #383f45 1px;border-radius:50%;height:22px;width:22px;line-height:22px;font-size:11px;text-align:center;vertical-align:middle;text-decoration:none}dl.code-annotation-container-grid dt[data-target-cell]{cursor:pointer}dl.code-annotation-container-grid dt[data-target-cell].code-annotation-active{color:#fff;border:solid #aaa 1px;background-color:#aaa}pre.code-annotation-code{padding-top:0;padding-bottom:0}pre.code-annotation-code code{z-index:3}#code-annotation-line-highlight-gutter{width:100%;border-top:solid rgba(170,170,170,.2666666667) 1px;border-bottom:solid rgba(170,170,170,.2666666667) 1px;z-index:2;background-color:rgba(170,170,170,.1333333333)}#code-annotation-line-highlight{margin-left:-4em;width:calc(100% + 4em);border-top:solid rgba(170,170,170,.2666666667) 1px;border-bottom:solid rgba(170,170,170,.2666666667) 1px;z-index:2;background-color:rgba(170,170,170,.1333333333)}code.sourceCode .code-annotation-anchor.code-annotation-active{background-color:var(--quarto-hl-normal-color, #aaaaaa);border:solid var(--quarto-hl-normal-color, #aaaaaa) 1px;color:#e9ecef;font-weight:bolder}code.sourceCode .code-annotation-anchor{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;color:var(--quarto-hl-co-color);border:solid var(--quarto-hl-co-color) 1px;border-radius:50%;height:18px;width:18px;font-size:9px;margin-top:2px}code.sourceCode button.code-annotation-anchor{padding:2px;user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none}code.sourceCode a.code-annotation-anchor{line-height:18px;text-align:center;vertical-align:middle;cursor:default;text-decoration:none}@media print{.page-columns .column-screen-inset{grid-column:page-start-inset/page-end-inset;z-index:998;opacity:.999}.page-columns .column-screen-inset table{background:#fff}.page-columns .column-screen-inset-left{grid-column:page-start-inset/body-content-end;z-index:998;opacity:.999}.page-columns .column-screen-inset-left table{background:#fff}.page-columns .column-screen-inset-right{grid-column:body-content-start/page-end-inset;z-index:998;opacity:.999}.page-columns .column-screen-inset-right table{background:#fff}.page-columns .column-screen{grid-column:page-start/page-end;z-index:998;opacity:.999}.page-columns .column-screen table{background:#fff}.page-columns .column-screen-left{grid-column:page-start/body-content-end;z-index:998;opacity:.999}.page-columns .column-screen-left table{background:#fff}.page-columns .column-screen-right{grid-column:body-content-start/page-end;z-index:998;opacity:.999}.page-columns .column-screen-right table{background:#fff}.page-columns .column-screen-inset-shaded{grid-column:page-start-inset/page-end-inset;padding:1em;background:#f8f9fa;z-index:998;opacity:.999;margin-bottom:1em}}.quarto-video{margin-bottom:1em}.table{border-top:1px solid #d3d8dc;border-bottom:1px solid #d3d8dc}.table>thead{border-top-width:0;border-bottom:1px solid #9ba5ae}.table a{word-break:break-word}.table>:not(caption)>*>*{background-color:unset;color:unset}#quarto-document-content .crosstalk-input .checkbox input[type=checkbox],#quarto-document-content .crosstalk-input .checkbox-inline input[type=checkbox]{position:unset;margin-top:unset;margin-left:unset}#quarto-document-content .row{margin-left:unset;margin-right:unset}.quarto-xref{white-space:nowrap}#quarto-draft-alert{margin-top:0px;margin-bottom:0px;padding:.3em;text-align:center;font-size:.9em}#quarto-draft-alert i{margin-right:.3em}a.external:after{content:"";background-image:url('data:image/svg+xml,');background-size:contain;background-repeat:no-repeat;background-position:center center;margin-left:.2em;padding-right:.75em}div.sourceCode code a.external:after{content:none}a.external:after:hover{cursor:pointer}.quarto-ext-icon{display:inline-block;font-size:.75em;padding-left:.3em}.code-with-filename .code-with-filename-file{margin-bottom:0;padding-bottom:2px;padding-top:2px;padding-left:.7em;border:var(--quarto-border-width) solid var(--quarto-border-color);border-radius:var(--quarto-border-radius);border-bottom:0;border-bottom-left-radius:0%;border-bottom-right-radius:0%}.code-with-filename div.sourceCode,.reveal .code-with-filename div.sourceCode{margin-top:0;border-top-left-radius:0%;border-top-right-radius:0%}.code-with-filename .code-with-filename-file pre{margin-bottom:0}.code-with-filename .code-with-filename-file{background-color:rgba(219,219,219,.8)}.quarto-dark .code-with-filename .code-with-filename-file{background-color:#555}.code-with-filename .code-with-filename-file strong{font-weight:400}.quarto-title-banner{margin-bottom:1em;color:#fdfefe;background:#517699}.quarto-title-banner a{color:#fdfefe}.quarto-title-banner h1,.quarto-title-banner .h1,.quarto-title-banner h2,.quarto-title-banner .h2{color:#fdfefe}.quarto-title-banner .code-tools-button{color:#b9dcdc}.quarto-title-banner .code-tools-button:hover{color:#fdfefe}.quarto-title-banner .code-tools-button>.bi::before{background-image:url('data:image/svg+xml,')}.quarto-title-banner .code-tools-button:hover>.bi::before{background-image:url('data:image/svg+xml,')}.quarto-title-banner .quarto-title .title{font-weight:600}.quarto-title-banner .quarto-categories{margin-top:.75em}@media(min-width: 992px){.quarto-title-banner{padding-top:2.5em;padding-bottom:2.5em}}@media(max-width: 991.98px){.quarto-title-banner{padding-top:1em;padding-bottom:1em}}@media(max-width: 767.98px){body.hypothesis-enabled #title-block-header>*{padding-right:20px}}main.quarto-banner-title-block>section:first-child>h2,main.quarto-banner-title-block>section:first-child>.h2,main.quarto-banner-title-block>section:first-child>h3,main.quarto-banner-title-block>section:first-child>.h3,main.quarto-banner-title-block>section:first-child>h4,main.quarto-banner-title-block>section:first-child>.h4{margin-top:0}.quarto-title .quarto-categories{display:flex;flex-wrap:wrap;row-gap:.5em;column-gap:.4em;padding-bottom:.5em;margin-top:.75em}.quarto-title .quarto-categories .quarto-category{padding:.25em .75em;font-size:.65em;text-transform:uppercase;border:solid 1px;border-radius:.375rem;opacity:.6}.quarto-title .quarto-categories .quarto-category a{color:inherit}.quarto-title-meta-container{display:grid;grid-template-columns:1fr auto}.quarto-title-meta-column-end{display:flex;flex-direction:column;padding-left:1em}.quarto-title-meta-column-end a .bi{margin-right:.3em}#title-block-header.quarto-title-block.default .quarto-title-meta{display:grid;grid-template-columns:repeat(2, 1fr);grid-column-gap:1em}#title-block-header.quarto-title-block.default .quarto-title .title{margin-bottom:0}#title-block-header.quarto-title-block.default .quarto-title-author-orcid img{margin-top:-0.2em;height:.8em;width:.8em}#title-block-header.quarto-title-block.default .quarto-title-author-email{opacity:.7}#title-block-header.quarto-title-block.default .quarto-description p:last-of-type{margin-bottom:0}#title-block-header.quarto-title-block.default .quarto-title-meta-contents p,#title-block-header.quarto-title-block.default .quarto-title-authors p,#title-block-header.quarto-title-block.default .quarto-title-affiliations p{margin-bottom:.1em}#title-block-header.quarto-title-block.default .quarto-title-meta-heading{text-transform:uppercase;margin-top:1em;font-size:.8em;opacity:.8;font-weight:400}#title-block-header.quarto-title-block.default .quarto-title-meta-contents{font-size:.9em}#title-block-header.quarto-title-block.default .quarto-title-meta-contents p.affiliation:last-of-type{margin-bottom:.1em}#title-block-header.quarto-title-block.default p.affiliation{margin-bottom:.1em}#title-block-header.quarto-title-block.default .keywords,#title-block-header.quarto-title-block.default .description,#title-block-header.quarto-title-block.default .abstract{margin-top:0}#title-block-header.quarto-title-block.default .keywords>p,#title-block-header.quarto-title-block.default .description>p,#title-block-header.quarto-title-block.default .abstract>p{font-size:.9em}#title-block-header.quarto-title-block.default .keywords>p:last-of-type,#title-block-header.quarto-title-block.default .description>p:last-of-type,#title-block-header.quarto-title-block.default .abstract>p:last-of-type{margin-bottom:0}#title-block-header.quarto-title-block.default .keywords .block-title,#title-block-header.quarto-title-block.default .description .block-title,#title-block-header.quarto-title-block.default .abstract .block-title{margin-top:1em;text-transform:uppercase;font-size:.8em;opacity:.8;font-weight:400}#title-block-header.quarto-title-block.default .quarto-title-meta-author{display:grid;grid-template-columns:minmax(max-content, 1fr) 1fr;grid-column-gap:1em}.quarto-title-tools-only{display:flex;justify-content:right} diff --git a/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/uncertainty_files/libs/bootstrap/bootstrap.min.js b/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/uncertainty_files/libs/bootstrap/bootstrap.min.js deleted file mode 100644 index e8f21f703..000000000 --- a/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/uncertainty_files/libs/bootstrap/bootstrap.min.js +++ /dev/null @@ -1,7 +0,0 @@ -/*! - * Bootstrap v5.3.1 (https://getbootstrap.com/) - * Copyright 2011-2023 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) - */ -!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).bootstrap=e()}(this,(function(){"use strict";const t=new Map,e={set(e,i,n){t.has(e)||t.set(e,new Map);const s=t.get(e);s.has(i)||0===s.size?s.set(i,n):console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(s.keys())[0]}.`)},get:(e,i)=>t.has(e)&&t.get(e).get(i)||null,remove(e,i){if(!t.has(e))return;const n=t.get(e);n.delete(i),0===n.size&&t.delete(e)}},i="transitionend",n=t=>(t&&window.CSS&&window.CSS.escape&&(t=t.replace(/#([^\s"#']+)/g,((t,e)=>`#${CSS.escape(e)}`))),t),s=t=>{t.dispatchEvent(new Event(i))},o=t=>!(!t||"object"!=typeof t)&&(void 0!==t.jquery&&(t=t[0]),void 0!==t.nodeType),r=t=>o(t)?t.jquery?t[0]:t:"string"==typeof t&&t.length>0?document.querySelector(n(t)):null,a=t=>{if(!o(t)||0===t.getClientRects().length)return!1;const e="visible"===getComputedStyle(t).getPropertyValue("visibility"),i=t.closest("details:not([open])");if(!i)return e;if(i!==t){const e=t.closest("summary");if(e&&e.parentNode!==i)return!1;if(null===e)return!1}return e},l=t=>!t||t.nodeType!==Node.ELEMENT_NODE||!!t.classList.contains("disabled")||(void 0!==t.disabled?t.disabled:t.hasAttribute("disabled")&&"false"!==t.getAttribute("disabled")),c=t=>{if(!document.documentElement.attachShadow)return null;if("function"==typeof t.getRootNode){const e=t.getRootNode();return e instanceof ShadowRoot?e:null}return t instanceof ShadowRoot?t:t.parentNode?c(t.parentNode):null},h=()=>{},d=t=>{t.offsetHeight},u=()=>window.jQuery&&!document.body.hasAttribute("data-bs-no-jquery")?window.jQuery:null,f=[],p=()=>"rtl"===document.documentElement.dir,m=t=>{var e;e=()=>{const e=u();if(e){const i=t.NAME,n=e.fn[i];e.fn[i]=t.jQueryInterface,e.fn[i].Constructor=t,e.fn[i].noConflict=()=>(e.fn[i]=n,t.jQueryInterface)}},"loading"===document.readyState?(f.length||document.addEventListener("DOMContentLoaded",(()=>{for(const t of f)t()})),f.push(e)):e()},g=(t,e=[],i=t)=>"function"==typeof t?t(...e):i,_=(t,e,n=!0)=>{if(!n)return void g(t);const o=(t=>{if(!t)return 0;let{transitionDuration:e,transitionDelay:i}=window.getComputedStyle(t);const n=Number.parseFloat(e),s=Number.parseFloat(i);return n||s?(e=e.split(",")[0],i=i.split(",")[0],1e3*(Number.parseFloat(e)+Number.parseFloat(i))):0})(e)+5;let r=!1;const a=({target:n})=>{n===e&&(r=!0,e.removeEventListener(i,a),g(t))};e.addEventListener(i,a),setTimeout((()=>{r||s(e)}),o)},b=(t,e,i,n)=>{const s=t.length;let o=t.indexOf(e);return-1===o?!i&&n?t[s-1]:t[0]:(o+=i?1:-1,n&&(o=(o+s)%s),t[Math.max(0,Math.min(o,s-1))])},v=/[^.]*(?=\..*)\.|.*/,y=/\..*/,w=/::\d+$/,A={};let E=1;const T={mouseenter:"mouseover",mouseleave:"mouseout"},C=new Set(["click","dblclick","mouseup","mousedown","contextmenu","mousewheel","DOMMouseScroll","mouseover","mouseout","mousemove","selectstart","selectend","keydown","keypress","keyup","orientationchange","touchstart","touchmove","touchend","touchcancel","pointerdown","pointermove","pointerup","pointerleave","pointercancel","gesturestart","gesturechange","gestureend","focus","blur","change","reset","select","submit","focusin","focusout","load","unload","beforeunload","resize","move","DOMContentLoaded","readystatechange","error","abort","scroll"]);function O(t,e){return e&&`${e}::${E++}`||t.uidEvent||E++}function x(t){const e=O(t);return t.uidEvent=e,A[e]=A[e]||{},A[e]}function k(t,e,i=null){return Object.values(t).find((t=>t.callable===e&&t.delegationSelector===i))}function L(t,e,i){const n="string"==typeof e,s=n?i:e||i;let o=I(t);return C.has(o)||(o=t),[n,s,o]}function S(t,e,i,n,s){if("string"!=typeof e||!t)return;let[o,r,a]=L(e,i,n);if(e in T){const t=t=>function(e){if(!e.relatedTarget||e.relatedTarget!==e.delegateTarget&&!e.delegateTarget.contains(e.relatedTarget))return t.call(this,e)};r=t(r)}const l=x(t),c=l[a]||(l[a]={}),h=k(c,r,o?i:null);if(h)return void(h.oneOff=h.oneOff&&s);const d=O(r,e.replace(v,"")),u=o?function(t,e,i){return function n(s){const o=t.querySelectorAll(e);for(let{target:r}=s;r&&r!==this;r=r.parentNode)for(const a of o)if(a===r)return P(s,{delegateTarget:r}),n.oneOff&&N.off(t,s.type,e,i),i.apply(r,[s])}}(t,i,r):function(t,e){return function i(n){return P(n,{delegateTarget:t}),i.oneOff&&N.off(t,n.type,e),e.apply(t,[n])}}(t,r);u.delegationSelector=o?i:null,u.callable=r,u.oneOff=s,u.uidEvent=d,c[d]=u,t.addEventListener(a,u,o)}function D(t,e,i,n,s){const o=k(e[i],n,s);o&&(t.removeEventListener(i,o,Boolean(s)),delete e[i][o.uidEvent])}function $(t,e,i,n){const s=e[i]||{};for(const[o,r]of Object.entries(s))o.includes(n)&&D(t,e,i,r.callable,r.delegationSelector)}function I(t){return t=t.replace(y,""),T[t]||t}const N={on(t,e,i,n){S(t,e,i,n,!1)},one(t,e,i,n){S(t,e,i,n,!0)},off(t,e,i,n){if("string"!=typeof e||!t)return;const[s,o,r]=L(e,i,n),a=r!==e,l=x(t),c=l[r]||{},h=e.startsWith(".");if(void 0===o){if(h)for(const i of Object.keys(l))$(t,l,i,e.slice(1));for(const[i,n]of Object.entries(c)){const s=i.replace(w,"");a&&!e.includes(s)||D(t,l,r,n.callable,n.delegationSelector)}}else{if(!Object.keys(c).length)return;D(t,l,r,o,s?i:null)}},trigger(t,e,i){if("string"!=typeof e||!t)return null;const n=u();let s=null,o=!0,r=!0,a=!1;e!==I(e)&&n&&(s=n.Event(e,i),n(t).trigger(s),o=!s.isPropagationStopped(),r=!s.isImmediatePropagationStopped(),a=s.isDefaultPrevented());const l=P(new Event(e,{bubbles:o,cancelable:!0}),i);return a&&l.preventDefault(),r&&t.dispatchEvent(l),l.defaultPrevented&&s&&s.preventDefault(),l}};function P(t,e={}){for(const[i,n]of Object.entries(e))try{t[i]=n}catch(e){Object.defineProperty(t,i,{configurable:!0,get:()=>n})}return t}function M(t){if("true"===t)return!0;if("false"===t)return!1;if(t===Number(t).toString())return Number(t);if(""===t||"null"===t)return null;if("string"!=typeof t)return t;try{return JSON.parse(decodeURIComponent(t))}catch(e){return t}}function j(t){return t.replace(/[A-Z]/g,(t=>`-${t.toLowerCase()}`))}const F={setDataAttribute(t,e,i){t.setAttribute(`data-bs-${j(e)}`,i)},removeDataAttribute(t,e){t.removeAttribute(`data-bs-${j(e)}`)},getDataAttributes(t){if(!t)return{};const e={},i=Object.keys(t.dataset).filter((t=>t.startsWith("bs")&&!t.startsWith("bsConfig")));for(const n of i){let i=n.replace(/^bs/,"");i=i.charAt(0).toLowerCase()+i.slice(1,i.length),e[i]=M(t.dataset[n])}return e},getDataAttribute:(t,e)=>M(t.getAttribute(`data-bs-${j(e)}`))};class H{static get Default(){return{}}static get DefaultType(){return{}}static get NAME(){throw new Error('You have to implement the static method "NAME", for each component!')}_getConfig(t){return t=this._mergeConfigObj(t),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}_configAfterMerge(t){return t}_mergeConfigObj(t,e){const i=o(e)?F.getDataAttribute(e,"config"):{};return{...this.constructor.Default,..."object"==typeof i?i:{},...o(e)?F.getDataAttributes(e):{},..."object"==typeof t?t:{}}}_typeCheckConfig(t,e=this.constructor.DefaultType){for(const[n,s]of Object.entries(e)){const e=t[n],r=o(e)?"element":null==(i=e)?`${i}`:Object.prototype.toString.call(i).match(/\s([a-z]+)/i)[1].toLowerCase();if(!new RegExp(s).test(r))throw new TypeError(`${this.constructor.NAME.toUpperCase()}: Option "${n}" provided type "${r}" but expected type "${s}".`)}var i}}class W extends H{constructor(t,i){super(),(t=r(t))&&(this._element=t,this._config=this._getConfig(i),e.set(this._element,this.constructor.DATA_KEY,this))}dispose(){e.remove(this._element,this.constructor.DATA_KEY),N.off(this._element,this.constructor.EVENT_KEY);for(const t of Object.getOwnPropertyNames(this))this[t]=null}_queueCallback(t,e,i=!0){_(t,e,i)}_getConfig(t){return t=this._mergeConfigObj(t,this._element),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}static getInstance(t){return e.get(r(t),this.DATA_KEY)}static getOrCreateInstance(t,e={}){return this.getInstance(t)||new this(t,"object"==typeof e?e:null)}static get VERSION(){return"5.3.1"}static get DATA_KEY(){return`bs.${this.NAME}`}static get EVENT_KEY(){return`.${this.DATA_KEY}`}static eventName(t){return`${t}${this.EVENT_KEY}`}}const B=t=>{let e=t.getAttribute("data-bs-target");if(!e||"#"===e){let i=t.getAttribute("href");if(!i||!i.includes("#")&&!i.startsWith("."))return null;i.includes("#")&&!i.startsWith("#")&&(i=`#${i.split("#")[1]}`),e=i&&"#"!==i?i.trim():null}return n(e)},z={find:(t,e=document.documentElement)=>[].concat(...Element.prototype.querySelectorAll.call(e,t)),findOne:(t,e=document.documentElement)=>Element.prototype.querySelector.call(e,t),children:(t,e)=>[].concat(...t.children).filter((t=>t.matches(e))),parents(t,e){const i=[];let n=t.parentNode.closest(e);for(;n;)i.push(n),n=n.parentNode.closest(e);return i},prev(t,e){let i=t.previousElementSibling;for(;i;){if(i.matches(e))return[i];i=i.previousElementSibling}return[]},next(t,e){let i=t.nextElementSibling;for(;i;){if(i.matches(e))return[i];i=i.nextElementSibling}return[]},focusableChildren(t){const e=["a","button","input","textarea","select","details","[tabindex]",'[contenteditable="true"]'].map((t=>`${t}:not([tabindex^="-"])`)).join(",");return this.find(e,t).filter((t=>!l(t)&&a(t)))},getSelectorFromElement(t){const e=B(t);return e&&z.findOne(e)?e:null},getElementFromSelector(t){const e=B(t);return e?z.findOne(e):null},getMultipleElementsFromSelector(t){const e=B(t);return e?z.find(e):[]}},R=(t,e="hide")=>{const i=`click.dismiss${t.EVENT_KEY}`,n=t.NAME;N.on(document,i,`[data-bs-dismiss="${n}"]`,(function(i){if(["A","AREA"].includes(this.tagName)&&i.preventDefault(),l(this))return;const s=z.getElementFromSelector(this)||this.closest(`.${n}`);t.getOrCreateInstance(s)[e]()}))},q=".bs.alert",V=`close${q}`,K=`closed${q}`;class Q extends W{static get NAME(){return"alert"}close(){if(N.trigger(this._element,V).defaultPrevented)return;this._element.classList.remove("show");const t=this._element.classList.contains("fade");this._queueCallback((()=>this._destroyElement()),this._element,t)}_destroyElement(){this._element.remove(),N.trigger(this._element,K),this.dispose()}static jQueryInterface(t){return this.each((function(){const e=Q.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}R(Q,"close"),m(Q);const X='[data-bs-toggle="button"]';class Y extends W{static get NAME(){return"button"}toggle(){this._element.setAttribute("aria-pressed",this._element.classList.toggle("active"))}static jQueryInterface(t){return this.each((function(){const e=Y.getOrCreateInstance(this);"toggle"===t&&e[t]()}))}}N.on(document,"click.bs.button.data-api",X,(t=>{t.preventDefault();const e=t.target.closest(X);Y.getOrCreateInstance(e).toggle()})),m(Y);const U=".bs.swipe",G=`touchstart${U}`,J=`touchmove${U}`,Z=`touchend${U}`,tt=`pointerdown${U}`,et=`pointerup${U}`,it={endCallback:null,leftCallback:null,rightCallback:null},nt={endCallback:"(function|null)",leftCallback:"(function|null)",rightCallback:"(function|null)"};class st extends H{constructor(t,e){super(),this._element=t,t&&st.isSupported()&&(this._config=this._getConfig(e),this._deltaX=0,this._supportPointerEvents=Boolean(window.PointerEvent),this._initEvents())}static get Default(){return it}static get DefaultType(){return nt}static get NAME(){return"swipe"}dispose(){N.off(this._element,U)}_start(t){this._supportPointerEvents?this._eventIsPointerPenTouch(t)&&(this._deltaX=t.clientX):this._deltaX=t.touches[0].clientX}_end(t){this._eventIsPointerPenTouch(t)&&(this._deltaX=t.clientX-this._deltaX),this._handleSwipe(),g(this._config.endCallback)}_move(t){this._deltaX=t.touches&&t.touches.length>1?0:t.touches[0].clientX-this._deltaX}_handleSwipe(){const t=Math.abs(this._deltaX);if(t<=40)return;const e=t/this._deltaX;this._deltaX=0,e&&g(e>0?this._config.rightCallback:this._config.leftCallback)}_initEvents(){this._supportPointerEvents?(N.on(this._element,tt,(t=>this._start(t))),N.on(this._element,et,(t=>this._end(t))),this._element.classList.add("pointer-event")):(N.on(this._element,G,(t=>this._start(t))),N.on(this._element,J,(t=>this._move(t))),N.on(this._element,Z,(t=>this._end(t))))}_eventIsPointerPenTouch(t){return this._supportPointerEvents&&("pen"===t.pointerType||"touch"===t.pointerType)}static isSupported(){return"ontouchstart"in document.documentElement||navigator.maxTouchPoints>0}}const ot=".bs.carousel",rt=".data-api",at="next",lt="prev",ct="left",ht="right",dt=`slide${ot}`,ut=`slid${ot}`,ft=`keydown${ot}`,pt=`mouseenter${ot}`,mt=`mouseleave${ot}`,gt=`dragstart${ot}`,_t=`load${ot}${rt}`,bt=`click${ot}${rt}`,vt="carousel",yt="active",wt=".active",At=".carousel-item",Et=wt+At,Tt={ArrowLeft:ht,ArrowRight:ct},Ct={interval:5e3,keyboard:!0,pause:"hover",ride:!1,touch:!0,wrap:!0},Ot={interval:"(number|boolean)",keyboard:"boolean",pause:"(string|boolean)",ride:"(boolean|string)",touch:"boolean",wrap:"boolean"};class xt extends W{constructor(t,e){super(t,e),this._interval=null,this._activeElement=null,this._isSliding=!1,this.touchTimeout=null,this._swipeHelper=null,this._indicatorsElement=z.findOne(".carousel-indicators",this._element),this._addEventListeners(),this._config.ride===vt&&this.cycle()}static get Default(){return Ct}static get DefaultType(){return Ot}static get NAME(){return"carousel"}next(){this._slide(at)}nextWhenVisible(){!document.hidden&&a(this._element)&&this.next()}prev(){this._slide(lt)}pause(){this._isSliding&&s(this._element),this._clearInterval()}cycle(){this._clearInterval(),this._updateInterval(),this._interval=setInterval((()=>this.nextWhenVisible()),this._config.interval)}_maybeEnableCycle(){this._config.ride&&(this._isSliding?N.one(this._element,ut,(()=>this.cycle())):this.cycle())}to(t){const e=this._getItems();if(t>e.length-1||t<0)return;if(this._isSliding)return void N.one(this._element,ut,(()=>this.to(t)));const i=this._getItemIndex(this._getActive());if(i===t)return;const n=t>i?at:lt;this._slide(n,e[t])}dispose(){this._swipeHelper&&this._swipeHelper.dispose(),super.dispose()}_configAfterMerge(t){return t.defaultInterval=t.interval,t}_addEventListeners(){this._config.keyboard&&N.on(this._element,ft,(t=>this._keydown(t))),"hover"===this._config.pause&&(N.on(this._element,pt,(()=>this.pause())),N.on(this._element,mt,(()=>this._maybeEnableCycle()))),this._config.touch&&st.isSupported()&&this._addTouchEventListeners()}_addTouchEventListeners(){for(const t of z.find(".carousel-item img",this._element))N.on(t,gt,(t=>t.preventDefault()));const t={leftCallback:()=>this._slide(this._directionToOrder(ct)),rightCallback:()=>this._slide(this._directionToOrder(ht)),endCallback:()=>{"hover"===this._config.pause&&(this.pause(),this.touchTimeout&&clearTimeout(this.touchTimeout),this.touchTimeout=setTimeout((()=>this._maybeEnableCycle()),500+this._config.interval))}};this._swipeHelper=new st(this._element,t)}_keydown(t){if(/input|textarea/i.test(t.target.tagName))return;const e=Tt[t.key];e&&(t.preventDefault(),this._slide(this._directionToOrder(e)))}_getItemIndex(t){return this._getItems().indexOf(t)}_setActiveIndicatorElement(t){if(!this._indicatorsElement)return;const e=z.findOne(wt,this._indicatorsElement);e.classList.remove(yt),e.removeAttribute("aria-current");const i=z.findOne(`[data-bs-slide-to="${t}"]`,this._indicatorsElement);i&&(i.classList.add(yt),i.setAttribute("aria-current","true"))}_updateInterval(){const t=this._activeElement||this._getActive();if(!t)return;const e=Number.parseInt(t.getAttribute("data-bs-interval"),10);this._config.interval=e||this._config.defaultInterval}_slide(t,e=null){if(this._isSliding)return;const i=this._getActive(),n=t===at,s=e||b(this._getItems(),i,n,this._config.wrap);if(s===i)return;const o=this._getItemIndex(s),r=e=>N.trigger(this._element,e,{relatedTarget:s,direction:this._orderToDirection(t),from:this._getItemIndex(i),to:o});if(r(dt).defaultPrevented)return;if(!i||!s)return;const a=Boolean(this._interval);this.pause(),this._isSliding=!0,this._setActiveIndicatorElement(o),this._activeElement=s;const l=n?"carousel-item-start":"carousel-item-end",c=n?"carousel-item-next":"carousel-item-prev";s.classList.add(c),d(s),i.classList.add(l),s.classList.add(l),this._queueCallback((()=>{s.classList.remove(l,c),s.classList.add(yt),i.classList.remove(yt,c,l),this._isSliding=!1,r(ut)}),i,this._isAnimated()),a&&this.cycle()}_isAnimated(){return this._element.classList.contains("slide")}_getActive(){return z.findOne(Et,this._element)}_getItems(){return z.find(At,this._element)}_clearInterval(){this._interval&&(clearInterval(this._interval),this._interval=null)}_directionToOrder(t){return p()?t===ct?lt:at:t===ct?at:lt}_orderToDirection(t){return p()?t===lt?ct:ht:t===lt?ht:ct}static jQueryInterface(t){return this.each((function(){const e=xt.getOrCreateInstance(this,t);if("number"!=typeof t){if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}else e.to(t)}))}}N.on(document,bt,"[data-bs-slide], [data-bs-slide-to]",(function(t){const e=z.getElementFromSelector(this);if(!e||!e.classList.contains(vt))return;t.preventDefault();const i=xt.getOrCreateInstance(e),n=this.getAttribute("data-bs-slide-to");return n?(i.to(n),void i._maybeEnableCycle()):"next"===F.getDataAttribute(this,"slide")?(i.next(),void i._maybeEnableCycle()):(i.prev(),void i._maybeEnableCycle())})),N.on(window,_t,(()=>{const t=z.find('[data-bs-ride="carousel"]');for(const e of t)xt.getOrCreateInstance(e)})),m(xt);const kt=".bs.collapse",Lt=`show${kt}`,St=`shown${kt}`,Dt=`hide${kt}`,$t=`hidden${kt}`,It=`click${kt}.data-api`,Nt="show",Pt="collapse",Mt="collapsing",jt=`:scope .${Pt} .${Pt}`,Ft='[data-bs-toggle="collapse"]',Ht={parent:null,toggle:!0},Wt={parent:"(null|element)",toggle:"boolean"};class Bt extends W{constructor(t,e){super(t,e),this._isTransitioning=!1,this._triggerArray=[];const i=z.find(Ft);for(const t of i){const e=z.getSelectorFromElement(t),i=z.find(e).filter((t=>t===this._element));null!==e&&i.length&&this._triggerArray.push(t)}this._initializeChildren(),this._config.parent||this._addAriaAndCollapsedClass(this._triggerArray,this._isShown()),this._config.toggle&&this.toggle()}static get Default(){return Ht}static get DefaultType(){return Wt}static get NAME(){return"collapse"}toggle(){this._isShown()?this.hide():this.show()}show(){if(this._isTransitioning||this._isShown())return;let t=[];if(this._config.parent&&(t=this._getFirstLevelChildren(".collapse.show, .collapse.collapsing").filter((t=>t!==this._element)).map((t=>Bt.getOrCreateInstance(t,{toggle:!1})))),t.length&&t[0]._isTransitioning)return;if(N.trigger(this._element,Lt).defaultPrevented)return;for(const e of t)e.hide();const e=this._getDimension();this._element.classList.remove(Pt),this._element.classList.add(Mt),this._element.style[e]=0,this._addAriaAndCollapsedClass(this._triggerArray,!0),this._isTransitioning=!0;const i=`scroll${e[0].toUpperCase()+e.slice(1)}`;this._queueCallback((()=>{this._isTransitioning=!1,this._element.classList.remove(Mt),this._element.classList.add(Pt,Nt),this._element.style[e]="",N.trigger(this._element,St)}),this._element,!0),this._element.style[e]=`${this._element[i]}px`}hide(){if(this._isTransitioning||!this._isShown())return;if(N.trigger(this._element,Dt).defaultPrevented)return;const t=this._getDimension();this._element.style[t]=`${this._element.getBoundingClientRect()[t]}px`,d(this._element),this._element.classList.add(Mt),this._element.classList.remove(Pt,Nt);for(const t of this._triggerArray){const e=z.getElementFromSelector(t);e&&!this._isShown(e)&&this._addAriaAndCollapsedClass([t],!1)}this._isTransitioning=!0,this._element.style[t]="",this._queueCallback((()=>{this._isTransitioning=!1,this._element.classList.remove(Mt),this._element.classList.add(Pt),N.trigger(this._element,$t)}),this._element,!0)}_isShown(t=this._element){return t.classList.contains(Nt)}_configAfterMerge(t){return t.toggle=Boolean(t.toggle),t.parent=r(t.parent),t}_getDimension(){return this._element.classList.contains("collapse-horizontal")?"width":"height"}_initializeChildren(){if(!this._config.parent)return;const t=this._getFirstLevelChildren(Ft);for(const e of t){const t=z.getElementFromSelector(e);t&&this._addAriaAndCollapsedClass([e],this._isShown(t))}}_getFirstLevelChildren(t){const e=z.find(jt,this._config.parent);return z.find(t,this._config.parent).filter((t=>!e.includes(t)))}_addAriaAndCollapsedClass(t,e){if(t.length)for(const i of t)i.classList.toggle("collapsed",!e),i.setAttribute("aria-expanded",e)}static jQueryInterface(t){const e={};return"string"==typeof t&&/show|hide/.test(t)&&(e.toggle=!1),this.each((function(){const i=Bt.getOrCreateInstance(this,e);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t]()}}))}}N.on(document,It,Ft,(function(t){("A"===t.target.tagName||t.delegateTarget&&"A"===t.delegateTarget.tagName)&&t.preventDefault();for(const t of z.getMultipleElementsFromSelector(this))Bt.getOrCreateInstance(t,{toggle:!1}).toggle()})),m(Bt);var zt="top",Rt="bottom",qt="right",Vt="left",Kt="auto",Qt=[zt,Rt,qt,Vt],Xt="start",Yt="end",Ut="clippingParents",Gt="viewport",Jt="popper",Zt="reference",te=Qt.reduce((function(t,e){return t.concat([e+"-"+Xt,e+"-"+Yt])}),[]),ee=[].concat(Qt,[Kt]).reduce((function(t,e){return t.concat([e,e+"-"+Xt,e+"-"+Yt])}),[]),ie="beforeRead",ne="read",se="afterRead",oe="beforeMain",re="main",ae="afterMain",le="beforeWrite",ce="write",he="afterWrite",de=[ie,ne,se,oe,re,ae,le,ce,he];function ue(t){return t?(t.nodeName||"").toLowerCase():null}function fe(t){if(null==t)return window;if("[object Window]"!==t.toString()){var e=t.ownerDocument;return e&&e.defaultView||window}return t}function pe(t){return t instanceof fe(t).Element||t instanceof Element}function me(t){return t instanceof fe(t).HTMLElement||t instanceof HTMLElement}function ge(t){return"undefined"!=typeof ShadowRoot&&(t instanceof fe(t).ShadowRoot||t instanceof ShadowRoot)}const _e={name:"applyStyles",enabled:!0,phase:"write",fn:function(t){var e=t.state;Object.keys(e.elements).forEach((function(t){var i=e.styles[t]||{},n=e.attributes[t]||{},s=e.elements[t];me(s)&&ue(s)&&(Object.assign(s.style,i),Object.keys(n).forEach((function(t){var e=n[t];!1===e?s.removeAttribute(t):s.setAttribute(t,!0===e?"":e)})))}))},effect:function(t){var e=t.state,i={popper:{position:e.options.strategy,left:"0",top:"0",margin:"0"},arrow:{position:"absolute"},reference:{}};return Object.assign(e.elements.popper.style,i.popper),e.styles=i,e.elements.arrow&&Object.assign(e.elements.arrow.style,i.arrow),function(){Object.keys(e.elements).forEach((function(t){var n=e.elements[t],s=e.attributes[t]||{},o=Object.keys(e.styles.hasOwnProperty(t)?e.styles[t]:i[t]).reduce((function(t,e){return t[e]="",t}),{});me(n)&&ue(n)&&(Object.assign(n.style,o),Object.keys(s).forEach((function(t){n.removeAttribute(t)})))}))}},requires:["computeStyles"]};function be(t){return t.split("-")[0]}var ve=Math.max,ye=Math.min,we=Math.round;function Ae(){var t=navigator.userAgentData;return null!=t&&t.brands&&Array.isArray(t.brands)?t.brands.map((function(t){return t.brand+"/"+t.version})).join(" "):navigator.userAgent}function Ee(){return!/^((?!chrome|android).)*safari/i.test(Ae())}function Te(t,e,i){void 0===e&&(e=!1),void 0===i&&(i=!1);var n=t.getBoundingClientRect(),s=1,o=1;e&&me(t)&&(s=t.offsetWidth>0&&we(n.width)/t.offsetWidth||1,o=t.offsetHeight>0&&we(n.height)/t.offsetHeight||1);var r=(pe(t)?fe(t):window).visualViewport,a=!Ee()&&i,l=(n.left+(a&&r?r.offsetLeft:0))/s,c=(n.top+(a&&r?r.offsetTop:0))/o,h=n.width/s,d=n.height/o;return{width:h,height:d,top:c,right:l+h,bottom:c+d,left:l,x:l,y:c}}function Ce(t){var e=Te(t),i=t.offsetWidth,n=t.offsetHeight;return Math.abs(e.width-i)<=1&&(i=e.width),Math.abs(e.height-n)<=1&&(n=e.height),{x:t.offsetLeft,y:t.offsetTop,width:i,height:n}}function Oe(t,e){var i=e.getRootNode&&e.getRootNode();if(t.contains(e))return!0;if(i&&ge(i)){var n=e;do{if(n&&t.isSameNode(n))return!0;n=n.parentNode||n.host}while(n)}return!1}function xe(t){return fe(t).getComputedStyle(t)}function ke(t){return["table","td","th"].indexOf(ue(t))>=0}function Le(t){return((pe(t)?t.ownerDocument:t.document)||window.document).documentElement}function Se(t){return"html"===ue(t)?t:t.assignedSlot||t.parentNode||(ge(t)?t.host:null)||Le(t)}function De(t){return me(t)&&"fixed"!==xe(t).position?t.offsetParent:null}function $e(t){for(var e=fe(t),i=De(t);i&&ke(i)&&"static"===xe(i).position;)i=De(i);return i&&("html"===ue(i)||"body"===ue(i)&&"static"===xe(i).position)?e:i||function(t){var e=/firefox/i.test(Ae());if(/Trident/i.test(Ae())&&me(t)&&"fixed"===xe(t).position)return null;var i=Se(t);for(ge(i)&&(i=i.host);me(i)&&["html","body"].indexOf(ue(i))<0;){var n=xe(i);if("none"!==n.transform||"none"!==n.perspective||"paint"===n.contain||-1!==["transform","perspective"].indexOf(n.willChange)||e&&"filter"===n.willChange||e&&n.filter&&"none"!==n.filter)return i;i=i.parentNode}return null}(t)||e}function Ie(t){return["top","bottom"].indexOf(t)>=0?"x":"y"}function Ne(t,e,i){return ve(t,ye(e,i))}function Pe(t){return Object.assign({},{top:0,right:0,bottom:0,left:0},t)}function Me(t,e){return e.reduce((function(e,i){return e[i]=t,e}),{})}const je={name:"arrow",enabled:!0,phase:"main",fn:function(t){var e,i=t.state,n=t.name,s=t.options,o=i.elements.arrow,r=i.modifiersData.popperOffsets,a=be(i.placement),l=Ie(a),c=[Vt,qt].indexOf(a)>=0?"height":"width";if(o&&r){var h=function(t,e){return Pe("number"!=typeof(t="function"==typeof t?t(Object.assign({},e.rects,{placement:e.placement})):t)?t:Me(t,Qt))}(s.padding,i),d=Ce(o),u="y"===l?zt:Vt,f="y"===l?Rt:qt,p=i.rects.reference[c]+i.rects.reference[l]-r[l]-i.rects.popper[c],m=r[l]-i.rects.reference[l],g=$e(o),_=g?"y"===l?g.clientHeight||0:g.clientWidth||0:0,b=p/2-m/2,v=h[u],y=_-d[c]-h[f],w=_/2-d[c]/2+b,A=Ne(v,w,y),E=l;i.modifiersData[n]=((e={})[E]=A,e.centerOffset=A-w,e)}},effect:function(t){var e=t.state,i=t.options.element,n=void 0===i?"[data-popper-arrow]":i;null!=n&&("string"!=typeof n||(n=e.elements.popper.querySelector(n)))&&Oe(e.elements.popper,n)&&(e.elements.arrow=n)},requires:["popperOffsets"],requiresIfExists:["preventOverflow"]};function Fe(t){return t.split("-")[1]}var He={top:"auto",right:"auto",bottom:"auto",left:"auto"};function We(t){var e,i=t.popper,n=t.popperRect,s=t.placement,o=t.variation,r=t.offsets,a=t.position,l=t.gpuAcceleration,c=t.adaptive,h=t.roundOffsets,d=t.isFixed,u=r.x,f=void 0===u?0:u,p=r.y,m=void 0===p?0:p,g="function"==typeof h?h({x:f,y:m}):{x:f,y:m};f=g.x,m=g.y;var _=r.hasOwnProperty("x"),b=r.hasOwnProperty("y"),v=Vt,y=zt,w=window;if(c){var A=$e(i),E="clientHeight",T="clientWidth";A===fe(i)&&"static"!==xe(A=Le(i)).position&&"absolute"===a&&(E="scrollHeight",T="scrollWidth"),(s===zt||(s===Vt||s===qt)&&o===Yt)&&(y=Rt,m-=(d&&A===w&&w.visualViewport?w.visualViewport.height:A[E])-n.height,m*=l?1:-1),s!==Vt&&(s!==zt&&s!==Rt||o!==Yt)||(v=qt,f-=(d&&A===w&&w.visualViewport?w.visualViewport.width:A[T])-n.width,f*=l?1:-1)}var C,O=Object.assign({position:a},c&&He),x=!0===h?function(t,e){var i=t.x,n=t.y,s=e.devicePixelRatio||1;return{x:we(i*s)/s||0,y:we(n*s)/s||0}}({x:f,y:m},fe(i)):{x:f,y:m};return f=x.x,m=x.y,l?Object.assign({},O,((C={})[y]=b?"0":"",C[v]=_?"0":"",C.transform=(w.devicePixelRatio||1)<=1?"translate("+f+"px, "+m+"px)":"translate3d("+f+"px, "+m+"px, 0)",C)):Object.assign({},O,((e={})[y]=b?m+"px":"",e[v]=_?f+"px":"",e.transform="",e))}const Be={name:"computeStyles",enabled:!0,phase:"beforeWrite",fn:function(t){var e=t.state,i=t.options,n=i.gpuAcceleration,s=void 0===n||n,o=i.adaptive,r=void 0===o||o,a=i.roundOffsets,l=void 0===a||a,c={placement:be(e.placement),variation:Fe(e.placement),popper:e.elements.popper,popperRect:e.rects.popper,gpuAcceleration:s,isFixed:"fixed"===e.options.strategy};null!=e.modifiersData.popperOffsets&&(e.styles.popper=Object.assign({},e.styles.popper,We(Object.assign({},c,{offsets:e.modifiersData.popperOffsets,position:e.options.strategy,adaptive:r,roundOffsets:l})))),null!=e.modifiersData.arrow&&(e.styles.arrow=Object.assign({},e.styles.arrow,We(Object.assign({},c,{offsets:e.modifiersData.arrow,position:"absolute",adaptive:!1,roundOffsets:l})))),e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-placement":e.placement})},data:{}};var ze={passive:!0};const Re={name:"eventListeners",enabled:!0,phase:"write",fn:function(){},effect:function(t){var e=t.state,i=t.instance,n=t.options,s=n.scroll,o=void 0===s||s,r=n.resize,a=void 0===r||r,l=fe(e.elements.popper),c=[].concat(e.scrollParents.reference,e.scrollParents.popper);return o&&c.forEach((function(t){t.addEventListener("scroll",i.update,ze)})),a&&l.addEventListener("resize",i.update,ze),function(){o&&c.forEach((function(t){t.removeEventListener("scroll",i.update,ze)})),a&&l.removeEventListener("resize",i.update,ze)}},data:{}};var qe={left:"right",right:"left",bottom:"top",top:"bottom"};function Ve(t){return t.replace(/left|right|bottom|top/g,(function(t){return qe[t]}))}var Ke={start:"end",end:"start"};function Qe(t){return t.replace(/start|end/g,(function(t){return Ke[t]}))}function Xe(t){var e=fe(t);return{scrollLeft:e.pageXOffset,scrollTop:e.pageYOffset}}function Ye(t){return Te(Le(t)).left+Xe(t).scrollLeft}function Ue(t){var e=xe(t),i=e.overflow,n=e.overflowX,s=e.overflowY;return/auto|scroll|overlay|hidden/.test(i+s+n)}function Ge(t){return["html","body","#document"].indexOf(ue(t))>=0?t.ownerDocument.body:me(t)&&Ue(t)?t:Ge(Se(t))}function Je(t,e){var i;void 0===e&&(e=[]);var n=Ge(t),s=n===(null==(i=t.ownerDocument)?void 0:i.body),o=fe(n),r=s?[o].concat(o.visualViewport||[],Ue(n)?n:[]):n,a=e.concat(r);return s?a:a.concat(Je(Se(r)))}function Ze(t){return Object.assign({},t,{left:t.x,top:t.y,right:t.x+t.width,bottom:t.y+t.height})}function ti(t,e,i){return e===Gt?Ze(function(t,e){var i=fe(t),n=Le(t),s=i.visualViewport,o=n.clientWidth,r=n.clientHeight,a=0,l=0;if(s){o=s.width,r=s.height;var c=Ee();(c||!c&&"fixed"===e)&&(a=s.offsetLeft,l=s.offsetTop)}return{width:o,height:r,x:a+Ye(t),y:l}}(t,i)):pe(e)?function(t,e){var i=Te(t,!1,"fixed"===e);return i.top=i.top+t.clientTop,i.left=i.left+t.clientLeft,i.bottom=i.top+t.clientHeight,i.right=i.left+t.clientWidth,i.width=t.clientWidth,i.height=t.clientHeight,i.x=i.left,i.y=i.top,i}(e,i):Ze(function(t){var e,i=Le(t),n=Xe(t),s=null==(e=t.ownerDocument)?void 0:e.body,o=ve(i.scrollWidth,i.clientWidth,s?s.scrollWidth:0,s?s.clientWidth:0),r=ve(i.scrollHeight,i.clientHeight,s?s.scrollHeight:0,s?s.clientHeight:0),a=-n.scrollLeft+Ye(t),l=-n.scrollTop;return"rtl"===xe(s||i).direction&&(a+=ve(i.clientWidth,s?s.clientWidth:0)-o),{width:o,height:r,x:a,y:l}}(Le(t)))}function ei(t){var e,i=t.reference,n=t.element,s=t.placement,o=s?be(s):null,r=s?Fe(s):null,a=i.x+i.width/2-n.width/2,l=i.y+i.height/2-n.height/2;switch(o){case zt:e={x:a,y:i.y-n.height};break;case Rt:e={x:a,y:i.y+i.height};break;case qt:e={x:i.x+i.width,y:l};break;case Vt:e={x:i.x-n.width,y:l};break;default:e={x:i.x,y:i.y}}var c=o?Ie(o):null;if(null!=c){var h="y"===c?"height":"width";switch(r){case Xt:e[c]=e[c]-(i[h]/2-n[h]/2);break;case Yt:e[c]=e[c]+(i[h]/2-n[h]/2)}}return e}function ii(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=void 0===n?t.placement:n,o=i.strategy,r=void 0===o?t.strategy:o,a=i.boundary,l=void 0===a?Ut:a,c=i.rootBoundary,h=void 0===c?Gt:c,d=i.elementContext,u=void 0===d?Jt:d,f=i.altBoundary,p=void 0!==f&&f,m=i.padding,g=void 0===m?0:m,_=Pe("number"!=typeof g?g:Me(g,Qt)),b=u===Jt?Zt:Jt,v=t.rects.popper,y=t.elements[p?b:u],w=function(t,e,i,n){var s="clippingParents"===e?function(t){var e=Je(Se(t)),i=["absolute","fixed"].indexOf(xe(t).position)>=0&&me(t)?$e(t):t;return pe(i)?e.filter((function(t){return pe(t)&&Oe(t,i)&&"body"!==ue(t)})):[]}(t):[].concat(e),o=[].concat(s,[i]),r=o[0],a=o.reduce((function(e,i){var s=ti(t,i,n);return e.top=ve(s.top,e.top),e.right=ye(s.right,e.right),e.bottom=ye(s.bottom,e.bottom),e.left=ve(s.left,e.left),e}),ti(t,r,n));return a.width=a.right-a.left,a.height=a.bottom-a.top,a.x=a.left,a.y=a.top,a}(pe(y)?y:y.contextElement||Le(t.elements.popper),l,h,r),A=Te(t.elements.reference),E=ei({reference:A,element:v,strategy:"absolute",placement:s}),T=Ze(Object.assign({},v,E)),C=u===Jt?T:A,O={top:w.top-C.top+_.top,bottom:C.bottom-w.bottom+_.bottom,left:w.left-C.left+_.left,right:C.right-w.right+_.right},x=t.modifiersData.offset;if(u===Jt&&x){var k=x[s];Object.keys(O).forEach((function(t){var e=[qt,Rt].indexOf(t)>=0?1:-1,i=[zt,Rt].indexOf(t)>=0?"y":"x";O[t]+=k[i]*e}))}return O}function ni(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=i.boundary,o=i.rootBoundary,r=i.padding,a=i.flipVariations,l=i.allowedAutoPlacements,c=void 0===l?ee:l,h=Fe(n),d=h?a?te:te.filter((function(t){return Fe(t)===h})):Qt,u=d.filter((function(t){return c.indexOf(t)>=0}));0===u.length&&(u=d);var f=u.reduce((function(e,i){return e[i]=ii(t,{placement:i,boundary:s,rootBoundary:o,padding:r})[be(i)],e}),{});return Object.keys(f).sort((function(t,e){return f[t]-f[e]}))}const si={name:"flip",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,n=t.name;if(!e.modifiersData[n]._skip){for(var s=i.mainAxis,o=void 0===s||s,r=i.altAxis,a=void 0===r||r,l=i.fallbackPlacements,c=i.padding,h=i.boundary,d=i.rootBoundary,u=i.altBoundary,f=i.flipVariations,p=void 0===f||f,m=i.allowedAutoPlacements,g=e.options.placement,_=be(g),b=l||(_!==g&&p?function(t){if(be(t)===Kt)return[];var e=Ve(t);return[Qe(t),e,Qe(e)]}(g):[Ve(g)]),v=[g].concat(b).reduce((function(t,i){return t.concat(be(i)===Kt?ni(e,{placement:i,boundary:h,rootBoundary:d,padding:c,flipVariations:p,allowedAutoPlacements:m}):i)}),[]),y=e.rects.reference,w=e.rects.popper,A=new Map,E=!0,T=v[0],C=0;C=0,S=L?"width":"height",D=ii(e,{placement:O,boundary:h,rootBoundary:d,altBoundary:u,padding:c}),$=L?k?qt:Vt:k?Rt:zt;y[S]>w[S]&&($=Ve($));var I=Ve($),N=[];if(o&&N.push(D[x]<=0),a&&N.push(D[$]<=0,D[I]<=0),N.every((function(t){return t}))){T=O,E=!1;break}A.set(O,N)}if(E)for(var P=function(t){var e=v.find((function(e){var i=A.get(e);if(i)return i.slice(0,t).every((function(t){return t}))}));if(e)return T=e,"break"},M=p?3:1;M>0&&"break"!==P(M);M--);e.placement!==T&&(e.modifiersData[n]._skip=!0,e.placement=T,e.reset=!0)}},requiresIfExists:["offset"],data:{_skip:!1}};function oi(t,e,i){return void 0===i&&(i={x:0,y:0}),{top:t.top-e.height-i.y,right:t.right-e.width+i.x,bottom:t.bottom-e.height+i.y,left:t.left-e.width-i.x}}function ri(t){return[zt,qt,Rt,Vt].some((function(e){return t[e]>=0}))}const ai={name:"hide",enabled:!0,phase:"main",requiresIfExists:["preventOverflow"],fn:function(t){var e=t.state,i=t.name,n=e.rects.reference,s=e.rects.popper,o=e.modifiersData.preventOverflow,r=ii(e,{elementContext:"reference"}),a=ii(e,{altBoundary:!0}),l=oi(r,n),c=oi(a,s,o),h=ri(l),d=ri(c);e.modifiersData[i]={referenceClippingOffsets:l,popperEscapeOffsets:c,isReferenceHidden:h,hasPopperEscaped:d},e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-reference-hidden":h,"data-popper-escaped":d})}},li={name:"offset",enabled:!0,phase:"main",requires:["popperOffsets"],fn:function(t){var e=t.state,i=t.options,n=t.name,s=i.offset,o=void 0===s?[0,0]:s,r=ee.reduce((function(t,i){return t[i]=function(t,e,i){var n=be(t),s=[Vt,zt].indexOf(n)>=0?-1:1,o="function"==typeof i?i(Object.assign({},e,{placement:t})):i,r=o[0],a=o[1];return r=r||0,a=(a||0)*s,[Vt,qt].indexOf(n)>=0?{x:a,y:r}:{x:r,y:a}}(i,e.rects,o),t}),{}),a=r[e.placement],l=a.x,c=a.y;null!=e.modifiersData.popperOffsets&&(e.modifiersData.popperOffsets.x+=l,e.modifiersData.popperOffsets.y+=c),e.modifiersData[n]=r}},ci={name:"popperOffsets",enabled:!0,phase:"read",fn:function(t){var e=t.state,i=t.name;e.modifiersData[i]=ei({reference:e.rects.reference,element:e.rects.popper,strategy:"absolute",placement:e.placement})},data:{}},hi={name:"preventOverflow",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,n=t.name,s=i.mainAxis,o=void 0===s||s,r=i.altAxis,a=void 0!==r&&r,l=i.boundary,c=i.rootBoundary,h=i.altBoundary,d=i.padding,u=i.tether,f=void 0===u||u,p=i.tetherOffset,m=void 0===p?0:p,g=ii(e,{boundary:l,rootBoundary:c,padding:d,altBoundary:h}),_=be(e.placement),b=Fe(e.placement),v=!b,y=Ie(_),w="x"===y?"y":"x",A=e.modifiersData.popperOffsets,E=e.rects.reference,T=e.rects.popper,C="function"==typeof m?m(Object.assign({},e.rects,{placement:e.placement})):m,O="number"==typeof C?{mainAxis:C,altAxis:C}:Object.assign({mainAxis:0,altAxis:0},C),x=e.modifiersData.offset?e.modifiersData.offset[e.placement]:null,k={x:0,y:0};if(A){if(o){var L,S="y"===y?zt:Vt,D="y"===y?Rt:qt,$="y"===y?"height":"width",I=A[y],N=I+g[S],P=I-g[D],M=f?-T[$]/2:0,j=b===Xt?E[$]:T[$],F=b===Xt?-T[$]:-E[$],H=e.elements.arrow,W=f&&H?Ce(H):{width:0,height:0},B=e.modifiersData["arrow#persistent"]?e.modifiersData["arrow#persistent"].padding:{top:0,right:0,bottom:0,left:0},z=B[S],R=B[D],q=Ne(0,E[$],W[$]),V=v?E[$]/2-M-q-z-O.mainAxis:j-q-z-O.mainAxis,K=v?-E[$]/2+M+q+R+O.mainAxis:F+q+R+O.mainAxis,Q=e.elements.arrow&&$e(e.elements.arrow),X=Q?"y"===y?Q.clientTop||0:Q.clientLeft||0:0,Y=null!=(L=null==x?void 0:x[y])?L:0,U=I+K-Y,G=Ne(f?ye(N,I+V-Y-X):N,I,f?ve(P,U):P);A[y]=G,k[y]=G-I}if(a){var J,Z="x"===y?zt:Vt,tt="x"===y?Rt:qt,et=A[w],it="y"===w?"height":"width",nt=et+g[Z],st=et-g[tt],ot=-1!==[zt,Vt].indexOf(_),rt=null!=(J=null==x?void 0:x[w])?J:0,at=ot?nt:et-E[it]-T[it]-rt+O.altAxis,lt=ot?et+E[it]+T[it]-rt-O.altAxis:st,ct=f&&ot?function(t,e,i){var n=Ne(t,e,i);return n>i?i:n}(at,et,lt):Ne(f?at:nt,et,f?lt:st);A[w]=ct,k[w]=ct-et}e.modifiersData[n]=k}},requiresIfExists:["offset"]};function di(t,e,i){void 0===i&&(i=!1);var n,s,o=me(e),r=me(e)&&function(t){var e=t.getBoundingClientRect(),i=we(e.width)/t.offsetWidth||1,n=we(e.height)/t.offsetHeight||1;return 1!==i||1!==n}(e),a=Le(e),l=Te(t,r,i),c={scrollLeft:0,scrollTop:0},h={x:0,y:0};return(o||!o&&!i)&&(("body"!==ue(e)||Ue(a))&&(c=(n=e)!==fe(n)&&me(n)?{scrollLeft:(s=n).scrollLeft,scrollTop:s.scrollTop}:Xe(n)),me(e)?((h=Te(e,!0)).x+=e.clientLeft,h.y+=e.clientTop):a&&(h.x=Ye(a))),{x:l.left+c.scrollLeft-h.x,y:l.top+c.scrollTop-h.y,width:l.width,height:l.height}}function ui(t){var e=new Map,i=new Set,n=[];function s(t){i.add(t.name),[].concat(t.requires||[],t.requiresIfExists||[]).forEach((function(t){if(!i.has(t)){var n=e.get(t);n&&s(n)}})),n.push(t)}return t.forEach((function(t){e.set(t.name,t)})),t.forEach((function(t){i.has(t.name)||s(t)})),n}var fi={placement:"bottom",modifiers:[],strategy:"absolute"};function pi(){for(var t=arguments.length,e=new Array(t),i=0;iNumber.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_getPopperConfig(){const t={placement:this._getPlacement(),modifiers:[{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"offset",options:{offset:this._getOffset()}}]};return(this._inNavbar||"static"===this._config.display)&&(F.setDataAttribute(this._menu,"popper","static"),t.modifiers=[{name:"applyStyles",enabled:!1}]),{...t,...g(this._config.popperConfig,[t])}}_selectMenuItem({key:t,target:e}){const i=z.find(".dropdown-menu .dropdown-item:not(.disabled):not(:disabled)",this._menu).filter((t=>a(t)));i.length&&b(i,e,t===Ti,!i.includes(e)).focus()}static jQueryInterface(t){return this.each((function(){const e=qi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}static clearMenus(t){if(2===t.button||"keyup"===t.type&&"Tab"!==t.key)return;const e=z.find(Ni);for(const i of e){const e=qi.getInstance(i);if(!e||!1===e._config.autoClose)continue;const n=t.composedPath(),s=n.includes(e._menu);if(n.includes(e._element)||"inside"===e._config.autoClose&&!s||"outside"===e._config.autoClose&&s)continue;if(e._menu.contains(t.target)&&("keyup"===t.type&&"Tab"===t.key||/input|select|option|textarea|form/i.test(t.target.tagName)))continue;const o={relatedTarget:e._element};"click"===t.type&&(o.clickEvent=t),e._completeHide(o)}}static dataApiKeydownHandler(t){const e=/input|textarea/i.test(t.target.tagName),i="Escape"===t.key,n=[Ei,Ti].includes(t.key);if(!n&&!i)return;if(e&&!i)return;t.preventDefault();const s=this.matches(Ii)?this:z.prev(this,Ii)[0]||z.next(this,Ii)[0]||z.findOne(Ii,t.delegateTarget.parentNode),o=qi.getOrCreateInstance(s);if(n)return t.stopPropagation(),o.show(),void o._selectMenuItem(t);o._isShown()&&(t.stopPropagation(),o.hide(),s.focus())}}N.on(document,Si,Ii,qi.dataApiKeydownHandler),N.on(document,Si,Pi,qi.dataApiKeydownHandler),N.on(document,Li,qi.clearMenus),N.on(document,Di,qi.clearMenus),N.on(document,Li,Ii,(function(t){t.preventDefault(),qi.getOrCreateInstance(this).toggle()})),m(qi);const Vi="backdrop",Ki="show",Qi=`mousedown.bs.${Vi}`,Xi={className:"modal-backdrop",clickCallback:null,isAnimated:!1,isVisible:!0,rootElement:"body"},Yi={className:"string",clickCallback:"(function|null)",isAnimated:"boolean",isVisible:"boolean",rootElement:"(element|string)"};class Ui extends H{constructor(t){super(),this._config=this._getConfig(t),this._isAppended=!1,this._element=null}static get Default(){return Xi}static get DefaultType(){return Yi}static get NAME(){return Vi}show(t){if(!this._config.isVisible)return void g(t);this._append();const e=this._getElement();this._config.isAnimated&&d(e),e.classList.add(Ki),this._emulateAnimation((()=>{g(t)}))}hide(t){this._config.isVisible?(this._getElement().classList.remove(Ki),this._emulateAnimation((()=>{this.dispose(),g(t)}))):g(t)}dispose(){this._isAppended&&(N.off(this._element,Qi),this._element.remove(),this._isAppended=!1)}_getElement(){if(!this._element){const t=document.createElement("div");t.className=this._config.className,this._config.isAnimated&&t.classList.add("fade"),this._element=t}return this._element}_configAfterMerge(t){return t.rootElement=r(t.rootElement),t}_append(){if(this._isAppended)return;const t=this._getElement();this._config.rootElement.append(t),N.on(t,Qi,(()=>{g(this._config.clickCallback)})),this._isAppended=!0}_emulateAnimation(t){_(t,this._getElement(),this._config.isAnimated)}}const Gi=".bs.focustrap",Ji=`focusin${Gi}`,Zi=`keydown.tab${Gi}`,tn="backward",en={autofocus:!0,trapElement:null},nn={autofocus:"boolean",trapElement:"element"};class sn extends H{constructor(t){super(),this._config=this._getConfig(t),this._isActive=!1,this._lastTabNavDirection=null}static get Default(){return en}static get DefaultType(){return nn}static get NAME(){return"focustrap"}activate(){this._isActive||(this._config.autofocus&&this._config.trapElement.focus(),N.off(document,Gi),N.on(document,Ji,(t=>this._handleFocusin(t))),N.on(document,Zi,(t=>this._handleKeydown(t))),this._isActive=!0)}deactivate(){this._isActive&&(this._isActive=!1,N.off(document,Gi))}_handleFocusin(t){const{trapElement:e}=this._config;if(t.target===document||t.target===e||e.contains(t.target))return;const i=z.focusableChildren(e);0===i.length?e.focus():this._lastTabNavDirection===tn?i[i.length-1].focus():i[0].focus()}_handleKeydown(t){"Tab"===t.key&&(this._lastTabNavDirection=t.shiftKey?tn:"forward")}}const on=".fixed-top, .fixed-bottom, .is-fixed, .sticky-top",rn=".sticky-top",an="padding-right",ln="margin-right";class cn{constructor(){this._element=document.body}getWidth(){const t=document.documentElement.clientWidth;return Math.abs(window.innerWidth-t)}hide(){const t=this.getWidth();this._disableOverFlow(),this._setElementAttributes(this._element,an,(e=>e+t)),this._setElementAttributes(on,an,(e=>e+t)),this._setElementAttributes(rn,ln,(e=>e-t))}reset(){this._resetElementAttributes(this._element,"overflow"),this._resetElementAttributes(this._element,an),this._resetElementAttributes(on,an),this._resetElementAttributes(rn,ln)}isOverflowing(){return this.getWidth()>0}_disableOverFlow(){this._saveInitialAttribute(this._element,"overflow"),this._element.style.overflow="hidden"}_setElementAttributes(t,e,i){const n=this.getWidth();this._applyManipulationCallback(t,(t=>{if(t!==this._element&&window.innerWidth>t.clientWidth+n)return;this._saveInitialAttribute(t,e);const s=window.getComputedStyle(t).getPropertyValue(e);t.style.setProperty(e,`${i(Number.parseFloat(s))}px`)}))}_saveInitialAttribute(t,e){const i=t.style.getPropertyValue(e);i&&F.setDataAttribute(t,e,i)}_resetElementAttributes(t,e){this._applyManipulationCallback(t,(t=>{const i=F.getDataAttribute(t,e);null!==i?(F.removeDataAttribute(t,e),t.style.setProperty(e,i)):t.style.removeProperty(e)}))}_applyManipulationCallback(t,e){if(o(t))e(t);else for(const i of z.find(t,this._element))e(i)}}const hn=".bs.modal",dn=`hide${hn}`,un=`hidePrevented${hn}`,fn=`hidden${hn}`,pn=`show${hn}`,mn=`shown${hn}`,gn=`resize${hn}`,_n=`click.dismiss${hn}`,bn=`mousedown.dismiss${hn}`,vn=`keydown.dismiss${hn}`,yn=`click${hn}.data-api`,wn="modal-open",An="show",En="modal-static",Tn={backdrop:!0,focus:!0,keyboard:!0},Cn={backdrop:"(boolean|string)",focus:"boolean",keyboard:"boolean"};class On extends W{constructor(t,e){super(t,e),this._dialog=z.findOne(".modal-dialog",this._element),this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._isShown=!1,this._isTransitioning=!1,this._scrollBar=new cn,this._addEventListeners()}static get Default(){return Tn}static get DefaultType(){return Cn}static get NAME(){return"modal"}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||this._isTransitioning||N.trigger(this._element,pn,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._isTransitioning=!0,this._scrollBar.hide(),document.body.classList.add(wn),this._adjustDialog(),this._backdrop.show((()=>this._showElement(t))))}hide(){this._isShown&&!this._isTransitioning&&(N.trigger(this._element,dn).defaultPrevented||(this._isShown=!1,this._isTransitioning=!0,this._focustrap.deactivate(),this._element.classList.remove(An),this._queueCallback((()=>this._hideModal()),this._element,this._isAnimated())))}dispose(){N.off(window,hn),N.off(this._dialog,hn),this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}handleUpdate(){this._adjustDialog()}_initializeBackDrop(){return new Ui({isVisible:Boolean(this._config.backdrop),isAnimated:this._isAnimated()})}_initializeFocusTrap(){return new sn({trapElement:this._element})}_showElement(t){document.body.contains(this._element)||document.body.append(this._element),this._element.style.display="block",this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.scrollTop=0;const e=z.findOne(".modal-body",this._dialog);e&&(e.scrollTop=0),d(this._element),this._element.classList.add(An),this._queueCallback((()=>{this._config.focus&&this._focustrap.activate(),this._isTransitioning=!1,N.trigger(this._element,mn,{relatedTarget:t})}),this._dialog,this._isAnimated())}_addEventListeners(){N.on(this._element,vn,(t=>{"Escape"===t.key&&(this._config.keyboard?this.hide():this._triggerBackdropTransition())})),N.on(window,gn,(()=>{this._isShown&&!this._isTransitioning&&this._adjustDialog()})),N.on(this._element,bn,(t=>{N.one(this._element,_n,(e=>{this._element===t.target&&this._element===e.target&&("static"!==this._config.backdrop?this._config.backdrop&&this.hide():this._triggerBackdropTransition())}))}))}_hideModal(){this._element.style.display="none",this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._isTransitioning=!1,this._backdrop.hide((()=>{document.body.classList.remove(wn),this._resetAdjustments(),this._scrollBar.reset(),N.trigger(this._element,fn)}))}_isAnimated(){return this._element.classList.contains("fade")}_triggerBackdropTransition(){if(N.trigger(this._element,un).defaultPrevented)return;const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._element.style.overflowY;"hidden"===e||this._element.classList.contains(En)||(t||(this._element.style.overflowY="hidden"),this._element.classList.add(En),this._queueCallback((()=>{this._element.classList.remove(En),this._queueCallback((()=>{this._element.style.overflowY=e}),this._dialog)}),this._dialog),this._element.focus())}_adjustDialog(){const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._scrollBar.getWidth(),i=e>0;if(i&&!t){const t=p()?"paddingLeft":"paddingRight";this._element.style[t]=`${e}px`}if(!i&&t){const t=p()?"paddingRight":"paddingLeft";this._element.style[t]=`${e}px`}}_resetAdjustments(){this._element.style.paddingLeft="",this._element.style.paddingRight=""}static jQueryInterface(t,e){return this.each((function(){const i=On.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t](e)}}))}}N.on(document,yn,'[data-bs-toggle="modal"]',(function(t){const e=z.getElementFromSelector(this);["A","AREA"].includes(this.tagName)&&t.preventDefault(),N.one(e,pn,(t=>{t.defaultPrevented||N.one(e,fn,(()=>{a(this)&&this.focus()}))}));const i=z.findOne(".modal.show");i&&On.getInstance(i).hide(),On.getOrCreateInstance(e).toggle(this)})),R(On),m(On);const xn=".bs.offcanvas",kn=".data-api",Ln=`load${xn}${kn}`,Sn="show",Dn="showing",$n="hiding",In=".offcanvas.show",Nn=`show${xn}`,Pn=`shown${xn}`,Mn=`hide${xn}`,jn=`hidePrevented${xn}`,Fn=`hidden${xn}`,Hn=`resize${xn}`,Wn=`click${xn}${kn}`,Bn=`keydown.dismiss${xn}`,zn={backdrop:!0,keyboard:!0,scroll:!1},Rn={backdrop:"(boolean|string)",keyboard:"boolean",scroll:"boolean"};class qn extends W{constructor(t,e){super(t,e),this._isShown=!1,this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._addEventListeners()}static get Default(){return zn}static get DefaultType(){return Rn}static get NAME(){return"offcanvas"}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||N.trigger(this._element,Nn,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._backdrop.show(),this._config.scroll||(new cn).hide(),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.classList.add(Dn),this._queueCallback((()=>{this._config.scroll&&!this._config.backdrop||this._focustrap.activate(),this._element.classList.add(Sn),this._element.classList.remove(Dn),N.trigger(this._element,Pn,{relatedTarget:t})}),this._element,!0))}hide(){this._isShown&&(N.trigger(this._element,Mn).defaultPrevented||(this._focustrap.deactivate(),this._element.blur(),this._isShown=!1,this._element.classList.add($n),this._backdrop.hide(),this._queueCallback((()=>{this._element.classList.remove(Sn,$n),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._config.scroll||(new cn).reset(),N.trigger(this._element,Fn)}),this._element,!0)))}dispose(){this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}_initializeBackDrop(){const t=Boolean(this._config.backdrop);return new Ui({className:"offcanvas-backdrop",isVisible:t,isAnimated:!0,rootElement:this._element.parentNode,clickCallback:t?()=>{"static"!==this._config.backdrop?this.hide():N.trigger(this._element,jn)}:null})}_initializeFocusTrap(){return new sn({trapElement:this._element})}_addEventListeners(){N.on(this._element,Bn,(t=>{"Escape"===t.key&&(this._config.keyboard?this.hide():N.trigger(this._element,jn))}))}static jQueryInterface(t){return this.each((function(){const e=qn.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}N.on(document,Wn,'[data-bs-toggle="offcanvas"]',(function(t){const e=z.getElementFromSelector(this);if(["A","AREA"].includes(this.tagName)&&t.preventDefault(),l(this))return;N.one(e,Fn,(()=>{a(this)&&this.focus()}));const i=z.findOne(In);i&&i!==e&&qn.getInstance(i).hide(),qn.getOrCreateInstance(e).toggle(this)})),N.on(window,Ln,(()=>{for(const t of z.find(In))qn.getOrCreateInstance(t).show()})),N.on(window,Hn,(()=>{for(const t of z.find("[aria-modal][class*=show][class*=offcanvas-]"))"fixed"!==getComputedStyle(t).position&&qn.getOrCreateInstance(t).hide()})),R(qn),m(qn);const Vn={"*":["class","dir","id","lang","role",/^aria-[\w-]*$/i],a:["target","href","title","rel"],area:[],b:[],br:[],col:[],code:[],div:[],em:[],hr:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],i:[],img:["src","srcset","alt","title","width","height"],li:[],ol:[],p:[],pre:[],s:[],small:[],span:[],sub:[],sup:[],strong:[],u:[],ul:[]},Kn=new Set(["background","cite","href","itemtype","longdesc","poster","src","xlink:href"]),Qn=/^(?!javascript:)(?:[a-z0-9+.-]+:|[^&:/?#]*(?:[/?#]|$))/i,Xn=(t,e)=>{const i=t.nodeName.toLowerCase();return e.includes(i)?!Kn.has(i)||Boolean(Qn.test(t.nodeValue)):e.filter((t=>t instanceof RegExp)).some((t=>t.test(i)))},Yn={allowList:Vn,content:{},extraClass:"",html:!1,sanitize:!0,sanitizeFn:null,template:"
"},Un={allowList:"object",content:"object",extraClass:"(string|function)",html:"boolean",sanitize:"boolean",sanitizeFn:"(null|function)",template:"string"},Gn={entry:"(string|element|function|null)",selector:"(string|element)"};class Jn extends H{constructor(t){super(),this._config=this._getConfig(t)}static get Default(){return Yn}static get DefaultType(){return Un}static get NAME(){return"TemplateFactory"}getContent(){return Object.values(this._config.content).map((t=>this._resolvePossibleFunction(t))).filter(Boolean)}hasContent(){return this.getContent().length>0}changeContent(t){return this._checkContent(t),this._config.content={...this._config.content,...t},this}toHtml(){const t=document.createElement("div");t.innerHTML=this._maybeSanitize(this._config.template);for(const[e,i]of Object.entries(this._config.content))this._setContent(t,i,e);const e=t.children[0],i=this._resolvePossibleFunction(this._config.extraClass);return i&&e.classList.add(...i.split(" ")),e}_typeCheckConfig(t){super._typeCheckConfig(t),this._checkContent(t.content)}_checkContent(t){for(const[e,i]of Object.entries(t))super._typeCheckConfig({selector:e,entry:i},Gn)}_setContent(t,e,i){const n=z.findOne(i,t);n&&((e=this._resolvePossibleFunction(e))?o(e)?this._putElementInTemplate(r(e),n):this._config.html?n.innerHTML=this._maybeSanitize(e):n.textContent=e:n.remove())}_maybeSanitize(t){return this._config.sanitize?function(t,e,i){if(!t.length)return t;if(i&&"function"==typeof i)return i(t);const n=(new window.DOMParser).parseFromString(t,"text/html"),s=[].concat(...n.body.querySelectorAll("*"));for(const t of s){const i=t.nodeName.toLowerCase();if(!Object.keys(e).includes(i)){t.remove();continue}const n=[].concat(...t.attributes),s=[].concat(e["*"]||[],e[i]||[]);for(const e of n)Xn(e,s)||t.removeAttribute(e.nodeName)}return n.body.innerHTML}(t,this._config.allowList,this._config.sanitizeFn):t}_resolvePossibleFunction(t){return g(t,[this])}_putElementInTemplate(t,e){if(this._config.html)return e.innerHTML="",void e.append(t);e.textContent=t.textContent}}const Zn=new Set(["sanitize","allowList","sanitizeFn"]),ts="fade",es="show",is=".modal",ns="hide.bs.modal",ss="hover",os="focus",rs={AUTO:"auto",TOP:"top",RIGHT:p()?"left":"right",BOTTOM:"bottom",LEFT:p()?"right":"left"},as={allowList:Vn,animation:!0,boundary:"clippingParents",container:!1,customClass:"",delay:0,fallbackPlacements:["top","right","bottom","left"],html:!1,offset:[0,6],placement:"top",popperConfig:null,sanitize:!0,sanitizeFn:null,selector:!1,template:'',title:"",trigger:"hover focus"},ls={allowList:"object",animation:"boolean",boundary:"(string|element)",container:"(string|element|boolean)",customClass:"(string|function)",delay:"(number|object)",fallbackPlacements:"array",html:"boolean",offset:"(array|string|function)",placement:"(string|function)",popperConfig:"(null|object|function)",sanitize:"boolean",sanitizeFn:"(null|function)",selector:"(string|boolean)",template:"string",title:"(string|element|function)",trigger:"string"};class cs extends W{constructor(t,e){if(void 0===vi)throw new TypeError("Bootstrap's tooltips require Popper (https://popper.js.org)");super(t,e),this._isEnabled=!0,this._timeout=0,this._isHovered=null,this._activeTrigger={},this._popper=null,this._templateFactory=null,this._newContent=null,this.tip=null,this._setListeners(),this._config.selector||this._fixTitle()}static get Default(){return as}static get DefaultType(){return ls}static get NAME(){return"tooltip"}enable(){this._isEnabled=!0}disable(){this._isEnabled=!1}toggleEnabled(){this._isEnabled=!this._isEnabled}toggle(){this._isEnabled&&(this._activeTrigger.click=!this._activeTrigger.click,this._isShown()?this._leave():this._enter())}dispose(){clearTimeout(this._timeout),N.off(this._element.closest(is),ns,this._hideModalHandler),this._element.getAttribute("data-bs-original-title")&&this._element.setAttribute("title",this._element.getAttribute("data-bs-original-title")),this._disposePopper(),super.dispose()}show(){if("none"===this._element.style.display)throw new Error("Please use show on visible elements");if(!this._isWithContent()||!this._isEnabled)return;const t=N.trigger(this._element,this.constructor.eventName("show")),e=(c(this._element)||this._element.ownerDocument.documentElement).contains(this._element);if(t.defaultPrevented||!e)return;this._disposePopper();const i=this._getTipElement();this._element.setAttribute("aria-describedby",i.getAttribute("id"));const{container:n}=this._config;if(this._element.ownerDocument.documentElement.contains(this.tip)||(n.append(i),N.trigger(this._element,this.constructor.eventName("inserted"))),this._popper=this._createPopper(i),i.classList.add(es),"ontouchstart"in document.documentElement)for(const t of[].concat(...document.body.children))N.on(t,"mouseover",h);this._queueCallback((()=>{N.trigger(this._element,this.constructor.eventName("shown")),!1===this._isHovered&&this._leave(),this._isHovered=!1}),this.tip,this._isAnimated())}hide(){if(this._isShown()&&!N.trigger(this._element,this.constructor.eventName("hide")).defaultPrevented){if(this._getTipElement().classList.remove(es),"ontouchstart"in document.documentElement)for(const t of[].concat(...document.body.children))N.off(t,"mouseover",h);this._activeTrigger.click=!1,this._activeTrigger[os]=!1,this._activeTrigger[ss]=!1,this._isHovered=null,this._queueCallback((()=>{this._isWithActiveTrigger()||(this._isHovered||this._disposePopper(),this._element.removeAttribute("aria-describedby"),N.trigger(this._element,this.constructor.eventName("hidden")))}),this.tip,this._isAnimated())}}update(){this._popper&&this._popper.update()}_isWithContent(){return Boolean(this._getTitle())}_getTipElement(){return this.tip||(this.tip=this._createTipElement(this._newContent||this._getContentForTemplate())),this.tip}_createTipElement(t){const e=this._getTemplateFactory(t).toHtml();if(!e)return null;e.classList.remove(ts,es),e.classList.add(`bs-${this.constructor.NAME}-auto`);const i=(t=>{do{t+=Math.floor(1e6*Math.random())}while(document.getElementById(t));return t})(this.constructor.NAME).toString();return e.setAttribute("id",i),this._isAnimated()&&e.classList.add(ts),e}setContent(t){this._newContent=t,this._isShown()&&(this._disposePopper(),this.show())}_getTemplateFactory(t){return this._templateFactory?this._templateFactory.changeContent(t):this._templateFactory=new Jn({...this._config,content:t,extraClass:this._resolvePossibleFunction(this._config.customClass)}),this._templateFactory}_getContentForTemplate(){return{".tooltip-inner":this._getTitle()}}_getTitle(){return this._resolvePossibleFunction(this._config.title)||this._element.getAttribute("data-bs-original-title")}_initializeOnDelegatedTarget(t){return this.constructor.getOrCreateInstance(t.delegateTarget,this._getDelegateConfig())}_isAnimated(){return this._config.animation||this.tip&&this.tip.classList.contains(ts)}_isShown(){return this.tip&&this.tip.classList.contains(es)}_createPopper(t){const e=g(this._config.placement,[this,t,this._element]),i=rs[e.toUpperCase()];return bi(this._element,t,this._getPopperConfig(i))}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map((t=>Number.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_resolvePossibleFunction(t){return g(t,[this._element])}_getPopperConfig(t){const e={placement:t,modifiers:[{name:"flip",options:{fallbackPlacements:this._config.fallbackPlacements}},{name:"offset",options:{offset:this._getOffset()}},{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"arrow",options:{element:`.${this.constructor.NAME}-arrow`}},{name:"preSetPlacement",enabled:!0,phase:"beforeMain",fn:t=>{this._getTipElement().setAttribute("data-popper-placement",t.state.placement)}}]};return{...e,...g(this._config.popperConfig,[e])}}_setListeners(){const t=this._config.trigger.split(" ");for(const e of t)if("click"===e)N.on(this._element,this.constructor.eventName("click"),this._config.selector,(t=>{this._initializeOnDelegatedTarget(t).toggle()}));else if("manual"!==e){const t=e===ss?this.constructor.eventName("mouseenter"):this.constructor.eventName("focusin"),i=e===ss?this.constructor.eventName("mouseleave"):this.constructor.eventName("focusout");N.on(this._element,t,this._config.selector,(t=>{const e=this._initializeOnDelegatedTarget(t);e._activeTrigger["focusin"===t.type?os:ss]=!0,e._enter()})),N.on(this._element,i,this._config.selector,(t=>{const e=this._initializeOnDelegatedTarget(t);e._activeTrigger["focusout"===t.type?os:ss]=e._element.contains(t.relatedTarget),e._leave()}))}this._hideModalHandler=()=>{this._element&&this.hide()},N.on(this._element.closest(is),ns,this._hideModalHandler)}_fixTitle(){const t=this._element.getAttribute("title");t&&(this._element.getAttribute("aria-label")||this._element.textContent.trim()||this._element.setAttribute("aria-label",t),this._element.setAttribute("data-bs-original-title",t),this._element.removeAttribute("title"))}_enter(){this._isShown()||this._isHovered?this._isHovered=!0:(this._isHovered=!0,this._setTimeout((()=>{this._isHovered&&this.show()}),this._config.delay.show))}_leave(){this._isWithActiveTrigger()||(this._isHovered=!1,this._setTimeout((()=>{this._isHovered||this.hide()}),this._config.delay.hide))}_setTimeout(t,e){clearTimeout(this._timeout),this._timeout=setTimeout(t,e)}_isWithActiveTrigger(){return Object.values(this._activeTrigger).includes(!0)}_getConfig(t){const e=F.getDataAttributes(this._element);for(const t of Object.keys(e))Zn.has(t)&&delete e[t];return t={...e,..."object"==typeof t&&t?t:{}},t=this._mergeConfigObj(t),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}_configAfterMerge(t){return t.container=!1===t.container?document.body:r(t.container),"number"==typeof t.delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),t}_getDelegateConfig(){const t={};for(const[e,i]of Object.entries(this._config))this.constructor.Default[e]!==i&&(t[e]=i);return t.selector=!1,t.trigger="manual",t}_disposePopper(){this._popper&&(this._popper.destroy(),this._popper=null),this.tip&&(this.tip.remove(),this.tip=null)}static jQueryInterface(t){return this.each((function(){const e=cs.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}m(cs);const hs={...cs.Default,content:"",offset:[0,8],placement:"right",template:'',trigger:"click"},ds={...cs.DefaultType,content:"(null|string|element|function)"};class us extends cs{static get Default(){return hs}static get DefaultType(){return ds}static get NAME(){return"popover"}_isWithContent(){return this._getTitle()||this._getContent()}_getContentForTemplate(){return{".popover-header":this._getTitle(),".popover-body":this._getContent()}}_getContent(){return this._resolvePossibleFunction(this._config.content)}static jQueryInterface(t){return this.each((function(){const e=us.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}m(us);const fs=".bs.scrollspy",ps=`activate${fs}`,ms=`click${fs}`,gs=`load${fs}.data-api`,_s="active",bs="[href]",vs=".nav-link",ys=`${vs}, .nav-item > ${vs}, .list-group-item`,ws={offset:null,rootMargin:"0px 0px -25%",smoothScroll:!1,target:null,threshold:[.1,.5,1]},As={offset:"(number|null)",rootMargin:"string",smoothScroll:"boolean",target:"element",threshold:"array"};class Es extends W{constructor(t,e){super(t,e),this._targetLinks=new Map,this._observableSections=new Map,this._rootElement="visible"===getComputedStyle(this._element).overflowY?null:this._element,this._activeTarget=null,this._observer=null,this._previousScrollData={visibleEntryTop:0,parentScrollTop:0},this.refresh()}static get Default(){return ws}static get DefaultType(){return As}static get NAME(){return"scrollspy"}refresh(){this._initializeTargetsAndObservables(),this._maybeEnableSmoothScroll(),this._observer?this._observer.disconnect():this._observer=this._getNewObserver();for(const t of this._observableSections.values())this._observer.observe(t)}dispose(){this._observer.disconnect(),super.dispose()}_configAfterMerge(t){return t.target=r(t.target)||document.body,t.rootMargin=t.offset?`${t.offset}px 0px -30%`:t.rootMargin,"string"==typeof t.threshold&&(t.threshold=t.threshold.split(",").map((t=>Number.parseFloat(t)))),t}_maybeEnableSmoothScroll(){this._config.smoothScroll&&(N.off(this._config.target,ms),N.on(this._config.target,ms,bs,(t=>{const e=this._observableSections.get(t.target.hash);if(e){t.preventDefault();const i=this._rootElement||window,n=e.offsetTop-this._element.offsetTop;if(i.scrollTo)return void i.scrollTo({top:n,behavior:"smooth"});i.scrollTop=n}})))}_getNewObserver(){const t={root:this._rootElement,threshold:this._config.threshold,rootMargin:this._config.rootMargin};return new IntersectionObserver((t=>this._observerCallback(t)),t)}_observerCallback(t){const e=t=>this._targetLinks.get(`#${t.target.id}`),i=t=>{this._previousScrollData.visibleEntryTop=t.target.offsetTop,this._process(e(t))},n=(this._rootElement||document.documentElement).scrollTop,s=n>=this._previousScrollData.parentScrollTop;this._previousScrollData.parentScrollTop=n;for(const o of t){if(!o.isIntersecting){this._activeTarget=null,this._clearActiveClass(e(o));continue}const t=o.target.offsetTop>=this._previousScrollData.visibleEntryTop;if(s&&t){if(i(o),!n)return}else s||t||i(o)}}_initializeTargetsAndObservables(){this._targetLinks=new Map,this._observableSections=new Map;const t=z.find(bs,this._config.target);for(const e of t){if(!e.hash||l(e))continue;const t=z.findOne(decodeURI(e.hash),this._element);a(t)&&(this._targetLinks.set(decodeURI(e.hash),e),this._observableSections.set(e.hash,t))}}_process(t){this._activeTarget!==t&&(this._clearActiveClass(this._config.target),this._activeTarget=t,t.classList.add(_s),this._activateParents(t),N.trigger(this._element,ps,{relatedTarget:t}))}_activateParents(t){if(t.classList.contains("dropdown-item"))z.findOne(".dropdown-toggle",t.closest(".dropdown")).classList.add(_s);else for(const e of z.parents(t,".nav, .list-group"))for(const t of z.prev(e,ys))t.classList.add(_s)}_clearActiveClass(t){t.classList.remove(_s);const e=z.find(`${bs}.${_s}`,t);for(const t of e)t.classList.remove(_s)}static jQueryInterface(t){return this.each((function(){const e=Es.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}))}}N.on(window,gs,(()=>{for(const t of z.find('[data-bs-spy="scroll"]'))Es.getOrCreateInstance(t)})),m(Es);const Ts=".bs.tab",Cs=`hide${Ts}`,Os=`hidden${Ts}`,xs=`show${Ts}`,ks=`shown${Ts}`,Ls=`click${Ts}`,Ss=`keydown${Ts}`,Ds=`load${Ts}`,$s="ArrowLeft",Is="ArrowRight",Ns="ArrowUp",Ps="ArrowDown",Ms="Home",js="End",Fs="active",Hs="fade",Ws="show",Bs=":not(.dropdown-toggle)",zs='[data-bs-toggle="tab"], [data-bs-toggle="pill"], [data-bs-toggle="list"]',Rs=`.nav-link${Bs}, .list-group-item${Bs}, [role="tab"]${Bs}, ${zs}`,qs=`.${Fs}[data-bs-toggle="tab"], .${Fs}[data-bs-toggle="pill"], .${Fs}[data-bs-toggle="list"]`;class Vs extends W{constructor(t){super(t),this._parent=this._element.closest('.list-group, .nav, [role="tablist"]'),this._parent&&(this._setInitialAttributes(this._parent,this._getChildren()),N.on(this._element,Ss,(t=>this._keydown(t))))}static get NAME(){return"tab"}show(){const t=this._element;if(this._elemIsActive(t))return;const e=this._getActiveElem(),i=e?N.trigger(e,Cs,{relatedTarget:t}):null;N.trigger(t,xs,{relatedTarget:e}).defaultPrevented||i&&i.defaultPrevented||(this._deactivate(e,t),this._activate(t,e))}_activate(t,e){t&&(t.classList.add(Fs),this._activate(z.getElementFromSelector(t)),this._queueCallback((()=>{"tab"===t.getAttribute("role")?(t.removeAttribute("tabindex"),t.setAttribute("aria-selected",!0),this._toggleDropDown(t,!0),N.trigger(t,ks,{relatedTarget:e})):t.classList.add(Ws)}),t,t.classList.contains(Hs)))}_deactivate(t,e){t&&(t.classList.remove(Fs),t.blur(),this._deactivate(z.getElementFromSelector(t)),this._queueCallback((()=>{"tab"===t.getAttribute("role")?(t.setAttribute("aria-selected",!1),t.setAttribute("tabindex","-1"),this._toggleDropDown(t,!1),N.trigger(t,Os,{relatedTarget:e})):t.classList.remove(Ws)}),t,t.classList.contains(Hs)))}_keydown(t){if(![$s,Is,Ns,Ps,Ms,js].includes(t.key))return;t.stopPropagation(),t.preventDefault();const e=this._getChildren().filter((t=>!l(t)));let i;if([Ms,js].includes(t.key))i=e[t.key===Ms?0:e.length-1];else{const n=[Is,Ps].includes(t.key);i=b(e,t.target,n,!0)}i&&(i.focus({preventScroll:!0}),Vs.getOrCreateInstance(i).show())}_getChildren(){return z.find(Rs,this._parent)}_getActiveElem(){return this._getChildren().find((t=>this._elemIsActive(t)))||null}_setInitialAttributes(t,e){this._setAttributeIfNotExists(t,"role","tablist");for(const t of e)this._setInitialAttributesOnChild(t)}_setInitialAttributesOnChild(t){t=this._getInnerElement(t);const e=this._elemIsActive(t),i=this._getOuterElement(t);t.setAttribute("aria-selected",e),i!==t&&this._setAttributeIfNotExists(i,"role","presentation"),e||t.setAttribute("tabindex","-1"),this._setAttributeIfNotExists(t,"role","tab"),this._setInitialAttributesOnTargetPanel(t)}_setInitialAttributesOnTargetPanel(t){const e=z.getElementFromSelector(t);e&&(this._setAttributeIfNotExists(e,"role","tabpanel"),t.id&&this._setAttributeIfNotExists(e,"aria-labelledby",`${t.id}`))}_toggleDropDown(t,e){const i=this._getOuterElement(t);if(!i.classList.contains("dropdown"))return;const n=(t,n)=>{const s=z.findOne(t,i);s&&s.classList.toggle(n,e)};n(".dropdown-toggle",Fs),n(".dropdown-menu",Ws),i.setAttribute("aria-expanded",e)}_setAttributeIfNotExists(t,e,i){t.hasAttribute(e)||t.setAttribute(e,i)}_elemIsActive(t){return t.classList.contains(Fs)}_getInnerElement(t){return t.matches(Rs)?t:z.findOne(Rs,t)}_getOuterElement(t){return t.closest(".nav-item, .list-group-item")||t}static jQueryInterface(t){return this.each((function(){const e=Vs.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}))}}N.on(document,Ls,zs,(function(t){["A","AREA"].includes(this.tagName)&&t.preventDefault(),l(this)||Vs.getOrCreateInstance(this).show()})),N.on(window,Ds,(()=>{for(const t of z.find(qs))Vs.getOrCreateInstance(t)})),m(Vs);const Ks=".bs.toast",Qs=`mouseover${Ks}`,Xs=`mouseout${Ks}`,Ys=`focusin${Ks}`,Us=`focusout${Ks}`,Gs=`hide${Ks}`,Js=`hidden${Ks}`,Zs=`show${Ks}`,to=`shown${Ks}`,eo="hide",io="show",no="showing",so={animation:"boolean",autohide:"boolean",delay:"number"},oo={animation:!0,autohide:!0,delay:5e3};class ro extends W{constructor(t,e){super(t,e),this._timeout=null,this._hasMouseInteraction=!1,this._hasKeyboardInteraction=!1,this._setListeners()}static get Default(){return oo}static get DefaultType(){return so}static get NAME(){return"toast"}show(){N.trigger(this._element,Zs).defaultPrevented||(this._clearTimeout(),this._config.animation&&this._element.classList.add("fade"),this._element.classList.remove(eo),d(this._element),this._element.classList.add(io,no),this._queueCallback((()=>{this._element.classList.remove(no),N.trigger(this._element,to),this._maybeScheduleHide()}),this._element,this._config.animation))}hide(){this.isShown()&&(N.trigger(this._element,Gs).defaultPrevented||(this._element.classList.add(no),this._queueCallback((()=>{this._element.classList.add(eo),this._element.classList.remove(no,io),N.trigger(this._element,Js)}),this._element,this._config.animation)))}dispose(){this._clearTimeout(),this.isShown()&&this._element.classList.remove(io),super.dispose()}isShown(){return this._element.classList.contains(io)}_maybeScheduleHide(){this._config.autohide&&(this._hasMouseInteraction||this._hasKeyboardInteraction||(this._timeout=setTimeout((()=>{this.hide()}),this._config.delay)))}_onInteraction(t,e){switch(t.type){case"mouseover":case"mouseout":this._hasMouseInteraction=e;break;case"focusin":case"focusout":this._hasKeyboardInteraction=e}if(e)return void this._clearTimeout();const i=t.relatedTarget;this._element===i||this._element.contains(i)||this._maybeScheduleHide()}_setListeners(){N.on(this._element,Qs,(t=>this._onInteraction(t,!0))),N.on(this._element,Xs,(t=>this._onInteraction(t,!1))),N.on(this._element,Ys,(t=>this._onInteraction(t,!0))),N.on(this._element,Us,(t=>this._onInteraction(t,!1)))}_clearTimeout(){clearTimeout(this._timeout),this._timeout=null}static jQueryInterface(t){return this.each((function(){const e=ro.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}return R(ro),m(ro),{Alert:Q,Button:Y,Carousel:xt,Collapse:Bt,Dropdown:qi,Modal:On,Offcanvas:qn,Popover:us,ScrollSpy:Es,Tab:Vs,Toast:ro,Tooltip:cs}})); -//# sourceMappingURL=bootstrap.bundle.min.js.map \ No newline at end of file diff --git a/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/uncertainty_files/libs/clipboard/clipboard.min.js b/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/uncertainty_files/libs/clipboard/clipboard.min.js deleted file mode 100644 index 1103f811e..000000000 --- a/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/uncertainty_files/libs/clipboard/clipboard.min.js +++ /dev/null @@ -1,7 +0,0 @@ -/*! - * clipboard.js v2.0.11 - * https://clipboardjs.com/ - * - * Licensed MIT © Zeno Rocha - */ -!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ClipboardJS=e():t.ClipboardJS=e()}(this,function(){return n={686:function(t,e,n){"use strict";n.d(e,{default:function(){return b}});var e=n(279),i=n.n(e),e=n(370),u=n.n(e),e=n(817),r=n.n(e);function c(t){try{return document.execCommand(t)}catch(t){return}}var a=function(t){t=r()(t);return c("cut"),t};function o(t,e){var n,o,t=(n=t,o="rtl"===document.documentElement.getAttribute("dir"),(t=document.createElement("textarea")).style.fontSize="12pt",t.style.border="0",t.style.padding="0",t.style.margin="0",t.style.position="absolute",t.style[o?"right":"left"]="-9999px",o=window.pageYOffset||document.documentElement.scrollTop,t.style.top="".concat(o,"px"),t.setAttribute("readonly",""),t.value=n,t);return e.container.appendChild(t),e=r()(t),c("copy"),t.remove(),e}var f=function(t){var e=1.anchorjs-link,.anchorjs-link:focus{opacity:1}",A.sheet.cssRules.length),A.sheet.insertRule("[data-anchorjs-icon]::after{content:attr(data-anchorjs-icon)}",A.sheet.cssRules.length),A.sheet.insertRule('@font-face{font-family:anchorjs-icons;src:url(data:n/a;base64,AAEAAAALAIAAAwAwT1MvMg8yG2cAAAE4AAAAYGNtYXDp3gC3AAABpAAAAExnYXNwAAAAEAAAA9wAAAAIZ2x5ZlQCcfwAAAH4AAABCGhlYWQHFvHyAAAAvAAAADZoaGVhBnACFwAAAPQAAAAkaG10eASAADEAAAGYAAAADGxvY2EACACEAAAB8AAAAAhtYXhwAAYAVwAAARgAAAAgbmFtZQGOH9cAAAMAAAAAunBvc3QAAwAAAAADvAAAACAAAQAAAAEAAHzE2p9fDzz1AAkEAAAAAADRecUWAAAAANQA6R8AAAAAAoACwAAAAAgAAgAAAAAAAAABAAADwP/AAAACgAAA/9MCrQABAAAAAAAAAAAAAAAAAAAAAwABAAAAAwBVAAIAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAMCQAGQAAUAAAKZAswAAACPApkCzAAAAesAMwEJAAAAAAAAAAAAAAAAAAAAARAAAAAAAAAAAAAAAAAAAAAAQAAg//0DwP/AAEADwABAAAAAAQAAAAAAAAAAAAAAIAAAAAAAAAIAAAACgAAxAAAAAwAAAAMAAAAcAAEAAwAAABwAAwABAAAAHAAEADAAAAAIAAgAAgAAACDpy//9//8AAAAg6cv//f///+EWNwADAAEAAAAAAAAAAAAAAAAACACEAAEAAAAAAAAAAAAAAAAxAAACAAQARAKAAsAAKwBUAAABIiYnJjQ3NzY2MzIWFxYUBwcGIicmNDc3NjQnJiYjIgYHBwYUFxYUBwYGIwciJicmNDc3NjIXFhQHBwYUFxYWMzI2Nzc2NCcmNDc2MhcWFAcHBgYjARQGDAUtLXoWOR8fORYtLTgKGwoKCjgaGg0gEhIgDXoaGgkJBQwHdR85Fi0tOAobCgoKOBoaDSASEiANehoaCQkKGwotLXoWOR8BMwUFLYEuehYXFxYugC44CQkKGwo4GkoaDQ0NDXoaShoKGwoFBe8XFi6ALjgJCQobCjgaShoNDQ0NehpKGgobCgoKLYEuehYXAAAADACWAAEAAAAAAAEACAAAAAEAAAAAAAIAAwAIAAEAAAAAAAMACAAAAAEAAAAAAAQACAAAAAEAAAAAAAUAAQALAAEAAAAAAAYACAAAAAMAAQQJAAEAEAAMAAMAAQQJAAIABgAcAAMAAQQJAAMAEAAMAAMAAQQJAAQAEAAMAAMAAQQJAAUAAgAiAAMAAQQJAAYAEAAMYW5jaG9yanM0MDBAAGEAbgBjAGgAbwByAGoAcwA0ADAAMABAAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAH//wAP) format("truetype")}',A.sheet.cssRules.length)),h=document.querySelectorAll("[id]"),t=[].map.call(h,function(A){return A.id}),i=0;i\]./()*\\\n\t\b\v\u00A0]/g,"-").replace(/-{2,}/g,"-").substring(0,this.options.truncate).replace(/^-+|-+$/gm,"").toLowerCase()},this.hasAnchorJSLink=function(A){var e=A.firstChild&&-1<(" "+A.firstChild.className+" ").indexOf(" anchorjs-link "),A=A.lastChild&&-1<(" "+A.lastChild.className+" ").indexOf(" anchorjs-link ");return e||A||!1}}}); -// @license-end \ No newline at end of file diff --git a/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/uncertainty_files/libs/quarto-html/popper.min.js b/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/uncertainty_files/libs/quarto-html/popper.min.js deleted file mode 100644 index e3726d728..000000000 --- a/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/uncertainty_files/libs/quarto-html/popper.min.js +++ /dev/null @@ -1,6 +0,0 @@ -/** - * @popperjs/core v2.11.7 - MIT License - */ - -!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).Popper={})}(this,(function(e){"use strict";function t(e){if(null==e)return window;if("[object Window]"!==e.toString()){var t=e.ownerDocument;return t&&t.defaultView||window}return e}function n(e){return e instanceof t(e).Element||e instanceof Element}function r(e){return e instanceof t(e).HTMLElement||e instanceof HTMLElement}function o(e){return"undefined"!=typeof ShadowRoot&&(e instanceof t(e).ShadowRoot||e instanceof ShadowRoot)}var i=Math.max,a=Math.min,s=Math.round;function f(){var e=navigator.userAgentData;return null!=e&&e.brands&&Array.isArray(e.brands)?e.brands.map((function(e){return e.brand+"/"+e.version})).join(" "):navigator.userAgent}function c(){return!/^((?!chrome|android).)*safari/i.test(f())}function p(e,o,i){void 0===o&&(o=!1),void 0===i&&(i=!1);var a=e.getBoundingClientRect(),f=1,p=1;o&&r(e)&&(f=e.offsetWidth>0&&s(a.width)/e.offsetWidth||1,p=e.offsetHeight>0&&s(a.height)/e.offsetHeight||1);var u=(n(e)?t(e):window).visualViewport,l=!c()&&i,d=(a.left+(l&&u?u.offsetLeft:0))/f,h=(a.top+(l&&u?u.offsetTop:0))/p,m=a.width/f,v=a.height/p;return{width:m,height:v,top:h,right:d+m,bottom:h+v,left:d,x:d,y:h}}function u(e){var n=t(e);return{scrollLeft:n.pageXOffset,scrollTop:n.pageYOffset}}function l(e){return e?(e.nodeName||"").toLowerCase():null}function d(e){return((n(e)?e.ownerDocument:e.document)||window.document).documentElement}function h(e){return p(d(e)).left+u(e).scrollLeft}function m(e){return t(e).getComputedStyle(e)}function v(e){var t=m(e),n=t.overflow,r=t.overflowX,o=t.overflowY;return/auto|scroll|overlay|hidden/.test(n+o+r)}function y(e,n,o){void 0===o&&(o=!1);var i,a,f=r(n),c=r(n)&&function(e){var t=e.getBoundingClientRect(),n=s(t.width)/e.offsetWidth||1,r=s(t.height)/e.offsetHeight||1;return 1!==n||1!==r}(n),m=d(n),y=p(e,c,o),g={scrollLeft:0,scrollTop:0},b={x:0,y:0};return(f||!f&&!o)&&(("body"!==l(n)||v(m))&&(g=(i=n)!==t(i)&&r(i)?{scrollLeft:(a=i).scrollLeft,scrollTop:a.scrollTop}:u(i)),r(n)?((b=p(n,!0)).x+=n.clientLeft,b.y+=n.clientTop):m&&(b.x=h(m))),{x:y.left+g.scrollLeft-b.x,y:y.top+g.scrollTop-b.y,width:y.width,height:y.height}}function g(e){var t=p(e),n=e.offsetWidth,r=e.offsetHeight;return Math.abs(t.width-n)<=1&&(n=t.width),Math.abs(t.height-r)<=1&&(r=t.height),{x:e.offsetLeft,y:e.offsetTop,width:n,height:r}}function b(e){return"html"===l(e)?e:e.assignedSlot||e.parentNode||(o(e)?e.host:null)||d(e)}function x(e){return["html","body","#document"].indexOf(l(e))>=0?e.ownerDocument.body:r(e)&&v(e)?e:x(b(e))}function w(e,n){var r;void 0===n&&(n=[]);var o=x(e),i=o===(null==(r=e.ownerDocument)?void 0:r.body),a=t(o),s=i?[a].concat(a.visualViewport||[],v(o)?o:[]):o,f=n.concat(s);return i?f:f.concat(w(b(s)))}function O(e){return["table","td","th"].indexOf(l(e))>=0}function j(e){return r(e)&&"fixed"!==m(e).position?e.offsetParent:null}function E(e){for(var n=t(e),i=j(e);i&&O(i)&&"static"===m(i).position;)i=j(i);return i&&("html"===l(i)||"body"===l(i)&&"static"===m(i).position)?n:i||function(e){var t=/firefox/i.test(f());if(/Trident/i.test(f())&&r(e)&&"fixed"===m(e).position)return null;var n=b(e);for(o(n)&&(n=n.host);r(n)&&["html","body"].indexOf(l(n))<0;){var i=m(n);if("none"!==i.transform||"none"!==i.perspective||"paint"===i.contain||-1!==["transform","perspective"].indexOf(i.willChange)||t&&"filter"===i.willChange||t&&i.filter&&"none"!==i.filter)return n;n=n.parentNode}return null}(e)||n}var D="top",A="bottom",L="right",P="left",M="auto",k=[D,A,L,P],W="start",B="end",H="viewport",T="popper",R=k.reduce((function(e,t){return e.concat([t+"-"+W,t+"-"+B])}),[]),S=[].concat(k,[M]).reduce((function(e,t){return e.concat([t,t+"-"+W,t+"-"+B])}),[]),V=["beforeRead","read","afterRead","beforeMain","main","afterMain","beforeWrite","write","afterWrite"];function q(e){var t=new Map,n=new Set,r=[];function o(e){n.add(e.name),[].concat(e.requires||[],e.requiresIfExists||[]).forEach((function(e){if(!n.has(e)){var r=t.get(e);r&&o(r)}})),r.push(e)}return e.forEach((function(e){t.set(e.name,e)})),e.forEach((function(e){n.has(e.name)||o(e)})),r}function C(e){return e.split("-")[0]}function N(e,t){var n=t.getRootNode&&t.getRootNode();if(e.contains(t))return!0;if(n&&o(n)){var r=t;do{if(r&&e.isSameNode(r))return!0;r=r.parentNode||r.host}while(r)}return!1}function I(e){return Object.assign({},e,{left:e.x,top:e.y,right:e.x+e.width,bottom:e.y+e.height})}function _(e,r,o){return r===H?I(function(e,n){var r=t(e),o=d(e),i=r.visualViewport,a=o.clientWidth,s=o.clientHeight,f=0,p=0;if(i){a=i.width,s=i.height;var u=c();(u||!u&&"fixed"===n)&&(f=i.offsetLeft,p=i.offsetTop)}return{width:a,height:s,x:f+h(e),y:p}}(e,o)):n(r)?function(e,t){var n=p(e,!1,"fixed"===t);return n.top=n.top+e.clientTop,n.left=n.left+e.clientLeft,n.bottom=n.top+e.clientHeight,n.right=n.left+e.clientWidth,n.width=e.clientWidth,n.height=e.clientHeight,n.x=n.left,n.y=n.top,n}(r,o):I(function(e){var t,n=d(e),r=u(e),o=null==(t=e.ownerDocument)?void 0:t.body,a=i(n.scrollWidth,n.clientWidth,o?o.scrollWidth:0,o?o.clientWidth:0),s=i(n.scrollHeight,n.clientHeight,o?o.scrollHeight:0,o?o.clientHeight:0),f=-r.scrollLeft+h(e),c=-r.scrollTop;return"rtl"===m(o||n).direction&&(f+=i(n.clientWidth,o?o.clientWidth:0)-a),{width:a,height:s,x:f,y:c}}(d(e)))}function F(e,t,o,s){var f="clippingParents"===t?function(e){var t=w(b(e)),o=["absolute","fixed"].indexOf(m(e).position)>=0&&r(e)?E(e):e;return n(o)?t.filter((function(e){return n(e)&&N(e,o)&&"body"!==l(e)})):[]}(e):[].concat(t),c=[].concat(f,[o]),p=c[0],u=c.reduce((function(t,n){var r=_(e,n,s);return t.top=i(r.top,t.top),t.right=a(r.right,t.right),t.bottom=a(r.bottom,t.bottom),t.left=i(r.left,t.left),t}),_(e,p,s));return u.width=u.right-u.left,u.height=u.bottom-u.top,u.x=u.left,u.y=u.top,u}function U(e){return e.split("-")[1]}function z(e){return["top","bottom"].indexOf(e)>=0?"x":"y"}function X(e){var t,n=e.reference,r=e.element,o=e.placement,i=o?C(o):null,a=o?U(o):null,s=n.x+n.width/2-r.width/2,f=n.y+n.height/2-r.height/2;switch(i){case D:t={x:s,y:n.y-r.height};break;case A:t={x:s,y:n.y+n.height};break;case L:t={x:n.x+n.width,y:f};break;case P:t={x:n.x-r.width,y:f};break;default:t={x:n.x,y:n.y}}var c=i?z(i):null;if(null!=c){var p="y"===c?"height":"width";switch(a){case W:t[c]=t[c]-(n[p]/2-r[p]/2);break;case B:t[c]=t[c]+(n[p]/2-r[p]/2)}}return t}function Y(e){return Object.assign({},{top:0,right:0,bottom:0,left:0},e)}function G(e,t){return t.reduce((function(t,n){return t[n]=e,t}),{})}function J(e,t){void 0===t&&(t={});var r=t,o=r.placement,i=void 0===o?e.placement:o,a=r.strategy,s=void 0===a?e.strategy:a,f=r.boundary,c=void 0===f?"clippingParents":f,u=r.rootBoundary,l=void 0===u?H:u,h=r.elementContext,m=void 0===h?T:h,v=r.altBoundary,y=void 0!==v&&v,g=r.padding,b=void 0===g?0:g,x=Y("number"!=typeof b?b:G(b,k)),w=m===T?"reference":T,O=e.rects.popper,j=e.elements[y?w:m],E=F(n(j)?j:j.contextElement||d(e.elements.popper),c,l,s),P=p(e.elements.reference),M=X({reference:P,element:O,strategy:"absolute",placement:i}),W=I(Object.assign({},O,M)),B=m===T?W:P,R={top:E.top-B.top+x.top,bottom:B.bottom-E.bottom+x.bottom,left:E.left-B.left+x.left,right:B.right-E.right+x.right},S=e.modifiersData.offset;if(m===T&&S){var V=S[i];Object.keys(R).forEach((function(e){var t=[L,A].indexOf(e)>=0?1:-1,n=[D,A].indexOf(e)>=0?"y":"x";R[e]+=V[n]*t}))}return R}var K={placement:"bottom",modifiers:[],strategy:"absolute"};function Q(){for(var e=arguments.length,t=new Array(e),n=0;n=0?-1:1,i="function"==typeof n?n(Object.assign({},t,{placement:e})):n,a=i[0],s=i[1];return a=a||0,s=(s||0)*o,[P,L].indexOf(r)>=0?{x:s,y:a}:{x:a,y:s}}(n,t.rects,i),e}),{}),s=a[t.placement],f=s.x,c=s.y;null!=t.modifiersData.popperOffsets&&(t.modifiersData.popperOffsets.x+=f,t.modifiersData.popperOffsets.y+=c),t.modifiersData[r]=a}},se={left:"right",right:"left",bottom:"top",top:"bottom"};function fe(e){return e.replace(/left|right|bottom|top/g,(function(e){return se[e]}))}var ce={start:"end",end:"start"};function pe(e){return e.replace(/start|end/g,(function(e){return ce[e]}))}function ue(e,t){void 0===t&&(t={});var n=t,r=n.placement,o=n.boundary,i=n.rootBoundary,a=n.padding,s=n.flipVariations,f=n.allowedAutoPlacements,c=void 0===f?S:f,p=U(r),u=p?s?R:R.filter((function(e){return U(e)===p})):k,l=u.filter((function(e){return c.indexOf(e)>=0}));0===l.length&&(l=u);var d=l.reduce((function(t,n){return t[n]=J(e,{placement:n,boundary:o,rootBoundary:i,padding:a})[C(n)],t}),{});return Object.keys(d).sort((function(e,t){return d[e]-d[t]}))}var le={name:"flip",enabled:!0,phase:"main",fn:function(e){var t=e.state,n=e.options,r=e.name;if(!t.modifiersData[r]._skip){for(var o=n.mainAxis,i=void 0===o||o,a=n.altAxis,s=void 0===a||a,f=n.fallbackPlacements,c=n.padding,p=n.boundary,u=n.rootBoundary,l=n.altBoundary,d=n.flipVariations,h=void 0===d||d,m=n.allowedAutoPlacements,v=t.options.placement,y=C(v),g=f||(y===v||!h?[fe(v)]:function(e){if(C(e)===M)return[];var t=fe(e);return[pe(e),t,pe(t)]}(v)),b=[v].concat(g).reduce((function(e,n){return e.concat(C(n)===M?ue(t,{placement:n,boundary:p,rootBoundary:u,padding:c,flipVariations:h,allowedAutoPlacements:m}):n)}),[]),x=t.rects.reference,w=t.rects.popper,O=new Map,j=!0,E=b[0],k=0;k=0,S=R?"width":"height",V=J(t,{placement:B,boundary:p,rootBoundary:u,altBoundary:l,padding:c}),q=R?T?L:P:T?A:D;x[S]>w[S]&&(q=fe(q));var N=fe(q),I=[];if(i&&I.push(V[H]<=0),s&&I.push(V[q]<=0,V[N]<=0),I.every((function(e){return e}))){E=B,j=!1;break}O.set(B,I)}if(j)for(var _=function(e){var t=b.find((function(t){var n=O.get(t);if(n)return n.slice(0,e).every((function(e){return e}))}));if(t)return E=t,"break"},F=h?3:1;F>0;F--){if("break"===_(F))break}t.placement!==E&&(t.modifiersData[r]._skip=!0,t.placement=E,t.reset=!0)}},requiresIfExists:["offset"],data:{_skip:!1}};function de(e,t,n){return i(e,a(t,n))}var he={name:"preventOverflow",enabled:!0,phase:"main",fn:function(e){var t=e.state,n=e.options,r=e.name,o=n.mainAxis,s=void 0===o||o,f=n.altAxis,c=void 0!==f&&f,p=n.boundary,u=n.rootBoundary,l=n.altBoundary,d=n.padding,h=n.tether,m=void 0===h||h,v=n.tetherOffset,y=void 0===v?0:v,b=J(t,{boundary:p,rootBoundary:u,padding:d,altBoundary:l}),x=C(t.placement),w=U(t.placement),O=!w,j=z(x),M="x"===j?"y":"x",k=t.modifiersData.popperOffsets,B=t.rects.reference,H=t.rects.popper,T="function"==typeof y?y(Object.assign({},t.rects,{placement:t.placement})):y,R="number"==typeof T?{mainAxis:T,altAxis:T}:Object.assign({mainAxis:0,altAxis:0},T),S=t.modifiersData.offset?t.modifiersData.offset[t.placement]:null,V={x:0,y:0};if(k){if(s){var q,N="y"===j?D:P,I="y"===j?A:L,_="y"===j?"height":"width",F=k[j],X=F+b[N],Y=F-b[I],G=m?-H[_]/2:0,K=w===W?B[_]:H[_],Q=w===W?-H[_]:-B[_],Z=t.elements.arrow,$=m&&Z?g(Z):{width:0,height:0},ee=t.modifiersData["arrow#persistent"]?t.modifiersData["arrow#persistent"].padding:{top:0,right:0,bottom:0,left:0},te=ee[N],ne=ee[I],re=de(0,B[_],$[_]),oe=O?B[_]/2-G-re-te-R.mainAxis:K-re-te-R.mainAxis,ie=O?-B[_]/2+G+re+ne+R.mainAxis:Q+re+ne+R.mainAxis,ae=t.elements.arrow&&E(t.elements.arrow),se=ae?"y"===j?ae.clientTop||0:ae.clientLeft||0:0,fe=null!=(q=null==S?void 0:S[j])?q:0,ce=F+ie-fe,pe=de(m?a(X,F+oe-fe-se):X,F,m?i(Y,ce):Y);k[j]=pe,V[j]=pe-F}if(c){var ue,le="x"===j?D:P,he="x"===j?A:L,me=k[M],ve="y"===M?"height":"width",ye=me+b[le],ge=me-b[he],be=-1!==[D,P].indexOf(x),xe=null!=(ue=null==S?void 0:S[M])?ue:0,we=be?ye:me-B[ve]-H[ve]-xe+R.altAxis,Oe=be?me+B[ve]+H[ve]-xe-R.altAxis:ge,je=m&&be?function(e,t,n){var r=de(e,t,n);return r>n?n:r}(we,me,Oe):de(m?we:ye,me,m?Oe:ge);k[M]=je,V[M]=je-me}t.modifiersData[r]=V}},requiresIfExists:["offset"]};var me={name:"arrow",enabled:!0,phase:"main",fn:function(e){var t,n=e.state,r=e.name,o=e.options,i=n.elements.arrow,a=n.modifiersData.popperOffsets,s=C(n.placement),f=z(s),c=[P,L].indexOf(s)>=0?"height":"width";if(i&&a){var p=function(e,t){return Y("number"!=typeof(e="function"==typeof e?e(Object.assign({},t.rects,{placement:t.placement})):e)?e:G(e,k))}(o.padding,n),u=g(i),l="y"===f?D:P,d="y"===f?A:L,h=n.rects.reference[c]+n.rects.reference[f]-a[f]-n.rects.popper[c],m=a[f]-n.rects.reference[f],v=E(i),y=v?"y"===f?v.clientHeight||0:v.clientWidth||0:0,b=h/2-m/2,x=p[l],w=y-u[c]-p[d],O=y/2-u[c]/2+b,j=de(x,O,w),M=f;n.modifiersData[r]=((t={})[M]=j,t.centerOffset=j-O,t)}},effect:function(e){var t=e.state,n=e.options.element,r=void 0===n?"[data-popper-arrow]":n;null!=r&&("string"!=typeof r||(r=t.elements.popper.querySelector(r)))&&N(t.elements.popper,r)&&(t.elements.arrow=r)},requires:["popperOffsets"],requiresIfExists:["preventOverflow"]};function ve(e,t,n){return void 0===n&&(n={x:0,y:0}),{top:e.top-t.height-n.y,right:e.right-t.width+n.x,bottom:e.bottom-t.height+n.y,left:e.left-t.width-n.x}}function ye(e){return[D,L,A,P].some((function(t){return e[t]>=0}))}var ge={name:"hide",enabled:!0,phase:"main",requiresIfExists:["preventOverflow"],fn:function(e){var t=e.state,n=e.name,r=t.rects.reference,o=t.rects.popper,i=t.modifiersData.preventOverflow,a=J(t,{elementContext:"reference"}),s=J(t,{altBoundary:!0}),f=ve(a,r),c=ve(s,o,i),p=ye(f),u=ye(c);t.modifiersData[n]={referenceClippingOffsets:f,popperEscapeOffsets:c,isReferenceHidden:p,hasPopperEscaped:u},t.attributes.popper=Object.assign({},t.attributes.popper,{"data-popper-reference-hidden":p,"data-popper-escaped":u})}},be=Z({defaultModifiers:[ee,te,oe,ie]}),xe=[ee,te,oe,ie,ae,le,he,me,ge],we=Z({defaultModifiers:xe});e.applyStyles=ie,e.arrow=me,e.computeStyles=oe,e.createPopper=we,e.createPopperLite=be,e.defaultModifiers=xe,e.detectOverflow=J,e.eventListeners=ee,e.flip=le,e.hide=ge,e.offset=ae,e.popperGenerator=Z,e.popperOffsets=te,e.preventOverflow=he,Object.defineProperty(e,"__esModule",{value:!0})})); - diff --git a/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/uncertainty_files/libs/quarto-html/quarto-syntax-highlighting.css b/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/uncertainty_files/libs/quarto-html/quarto-syntax-highlighting.css deleted file mode 100644 index b30ce5766..000000000 --- a/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/uncertainty_files/libs/quarto-html/quarto-syntax-highlighting.css +++ /dev/null @@ -1,205 +0,0 @@ -/* quarto syntax highlight colors */ -:root { - --quarto-hl-ot-color: #003B4F; - --quarto-hl-at-color: #657422; - --quarto-hl-ss-color: #20794D; - --quarto-hl-an-color: #5E5E5E; - --quarto-hl-fu-color: #4758AB; - --quarto-hl-st-color: #20794D; - --quarto-hl-cf-color: #003B4F; - --quarto-hl-op-color: #5E5E5E; - --quarto-hl-er-color: #AD0000; - --quarto-hl-bn-color: #AD0000; - --quarto-hl-al-color: #AD0000; - --quarto-hl-va-color: #111111; - --quarto-hl-bu-color: inherit; - --quarto-hl-ex-color: inherit; - --quarto-hl-pp-color: #AD0000; - --quarto-hl-in-color: #5E5E5E; - --quarto-hl-vs-color: #20794D; - --quarto-hl-wa-color: #5E5E5E; - --quarto-hl-do-color: #5E5E5E; - --quarto-hl-im-color: #00769E; - --quarto-hl-ch-color: #20794D; - --quarto-hl-dt-color: #AD0000; - --quarto-hl-fl-color: #AD0000; - --quarto-hl-co-color: #5E5E5E; - --quarto-hl-cv-color: #5E5E5E; - --quarto-hl-cn-color: #8f5902; - --quarto-hl-sc-color: #5E5E5E; - --quarto-hl-dv-color: #AD0000; - --quarto-hl-kw-color: #003B4F; -} - -/* other quarto variables */ -:root { - --quarto-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; -} - -pre > code.sourceCode > span { - color: #003B4F; -} - -code span { - color: #003B4F; -} - -code.sourceCode > span { - color: #003B4F; -} - -div.sourceCode, -div.sourceCode pre.sourceCode { - color: #003B4F; -} - -code span.ot { - color: #003B4F; - font-style: inherit; -} - -code span.at { - color: #657422; - font-style: inherit; -} - -code span.ss { - color: #20794D; - font-style: inherit; -} - -code span.an { - color: #5E5E5E; - font-style: inherit; -} - -code span.fu { - color: #4758AB; - font-style: inherit; -} - -code span.st { - color: #20794D; - font-style: inherit; -} - -code span.cf { - color: #003B4F; - font-weight: bold; - font-style: inherit; -} - -code span.op { - color: #5E5E5E; - font-style: inherit; -} - -code span.er { - color: #AD0000; - font-style: inherit; -} - -code span.bn { - color: #AD0000; - font-style: inherit; -} - -code span.al { - color: #AD0000; - font-style: inherit; -} - -code span.va { - color: #111111; - font-style: inherit; -} - -code span.bu { - font-style: inherit; -} - -code span.ex { - font-style: inherit; -} - -code span.pp { - color: #AD0000; - font-style: inherit; -} - -code span.in { - color: #5E5E5E; - font-style: inherit; -} - -code span.vs { - color: #20794D; - font-style: inherit; -} - -code span.wa { - color: #5E5E5E; - font-style: italic; -} - -code span.do { - color: #5E5E5E; - font-style: italic; -} - -code span.im { - color: #00769E; - font-style: inherit; -} - -code span.ch { - color: #20794D; - font-style: inherit; -} - -code span.dt { - color: #AD0000; - font-style: inherit; -} - -code span.fl { - color: #AD0000; - font-style: inherit; -} - -code span.co { - color: #5E5E5E; - font-style: inherit; -} - -code span.cv { - color: #5E5E5E; - font-style: italic; -} - -code span.cn { - color: #8f5902; - font-style: inherit; -} - -code span.sc { - color: #5E5E5E; - font-style: inherit; -} - -code span.dv { - color: #AD0000; - font-style: inherit; -} - -code span.kw { - color: #003B4F; - font-weight: bold; - font-style: inherit; -} - -.prevent-inlining { - content: " { - // Find any conflicting margin elements and add margins to the - // top to prevent overlap - const marginChildren = window.document.querySelectorAll( - ".column-margin.column-container > *, .margin-caption, .aside" - ); - - let lastBottom = 0; - for (const marginChild of marginChildren) { - if (marginChild.offsetParent !== null) { - // clear the top margin so we recompute it - marginChild.style.marginTop = null; - const top = marginChild.getBoundingClientRect().top + window.scrollY; - if (top < lastBottom) { - const marginChildStyle = window.getComputedStyle(marginChild); - const marginBottom = parseFloat(marginChildStyle["marginBottom"]); - const margin = lastBottom - top + marginBottom; - marginChild.style.marginTop = `${margin}px`; - } - const styles = window.getComputedStyle(marginChild); - const marginTop = parseFloat(styles["marginTop"]); - lastBottom = top + marginChild.getBoundingClientRect().height + marginTop; - } - } -}; - -window.document.addEventListener("DOMContentLoaded", function (_event) { - // Recompute the position of margin elements anytime the body size changes - if (window.ResizeObserver) { - const resizeObserver = new window.ResizeObserver( - throttle(() => { - layoutMarginEls(); - if ( - window.document.body.getBoundingClientRect().width < 990 && - isReaderMode() - ) { - quartoToggleReader(); - } - }, 50) - ); - resizeObserver.observe(window.document.body); - } - - const tocEl = window.document.querySelector('nav.toc-active[role="doc-toc"]'); - const sidebarEl = window.document.getElementById("quarto-sidebar"); - const leftTocEl = window.document.getElementById("quarto-sidebar-toc-left"); - const marginSidebarEl = window.document.getElementById( - "quarto-margin-sidebar" - ); - // function to determine whether the element has a previous sibling that is active - const prevSiblingIsActiveLink = (el) => { - const sibling = el.previousElementSibling; - if (sibling && sibling.tagName === "A") { - return sibling.classList.contains("active"); - } else { - return false; - } - }; - - // fire slideEnter for bootstrap tab activations (for htmlwidget resize behavior) - function fireSlideEnter(e) { - const event = window.document.createEvent("Event"); - event.initEvent("slideenter", true, true); - window.document.dispatchEvent(event); - } - const tabs = window.document.querySelectorAll('a[data-bs-toggle="tab"]'); - tabs.forEach((tab) => { - tab.addEventListener("shown.bs.tab", fireSlideEnter); - }); - - // fire slideEnter for tabby tab activations (for htmlwidget resize behavior) - document.addEventListener("tabby", fireSlideEnter, false); - - // Track scrolling and mark TOC links as active - // get table of contents and sidebar (bail if we don't have at least one) - const tocLinks = tocEl - ? [...tocEl.querySelectorAll("a[data-scroll-target]")] - : []; - const makeActive = (link) => tocLinks[link].classList.add("active"); - const removeActive = (link) => tocLinks[link].classList.remove("active"); - const removeAllActive = () => - [...Array(tocLinks.length).keys()].forEach((link) => removeActive(link)); - - // activate the anchor for a section associated with this TOC entry - tocLinks.forEach((link) => { - link.addEventListener("click", () => { - if (link.href.indexOf("#") !== -1) { - const anchor = link.href.split("#")[1]; - const heading = window.document.querySelector( - `[data-anchor-id="${anchor}"]` - ); - if (heading) { - // Add the class - heading.classList.add("reveal-anchorjs-link"); - - // function to show the anchor - const handleMouseout = () => { - heading.classList.remove("reveal-anchorjs-link"); - heading.removeEventListener("mouseout", handleMouseout); - }; - - // add a function to clear the anchor when the user mouses out of it - heading.addEventListener("mouseout", handleMouseout); - } - } - }); - }); - - const sections = tocLinks.map((link) => { - const target = link.getAttribute("data-scroll-target"); - if (target.startsWith("#")) { - return window.document.getElementById(decodeURI(`${target.slice(1)}`)); - } else { - return window.document.querySelector(decodeURI(`${target}`)); - } - }); - - const sectionMargin = 200; - let currentActive = 0; - // track whether we've initialized state the first time - let init = false; - - const updateActiveLink = () => { - // The index from bottom to top (e.g. reversed list) - let sectionIndex = -1; - if ( - window.innerHeight + window.pageYOffset >= - window.document.body.offsetHeight - ) { - // This is the no-scroll case where last section should be the active one - sectionIndex = 0; - } else { - // This finds the last section visible on screen that should be made active - sectionIndex = [...sections].reverse().findIndex((section) => { - if (section) { - return window.pageYOffset >= section.offsetTop - sectionMargin; - } else { - return false; - } - }); - } - if (sectionIndex > -1) { - const current = sections.length - sectionIndex - 1; - if (current !== currentActive) { - removeAllActive(); - currentActive = current; - makeActive(current); - if (init) { - window.dispatchEvent(sectionChanged); - } - init = true; - } - } - }; - - const inHiddenRegion = (top, bottom, hiddenRegions) => { - for (const region of hiddenRegions) { - if (top <= region.bottom && bottom >= region.top) { - return true; - } - } - return false; - }; - - const categorySelector = "header.quarto-title-block .quarto-category"; - const activateCategories = (href) => { - // Find any categories - // Surround them with a link pointing back to: - // #category=Authoring - try { - const categoryEls = window.document.querySelectorAll(categorySelector); - for (const categoryEl of categoryEls) { - const categoryText = categoryEl.textContent; - if (categoryText) { - const link = `${href}#category=${encodeURIComponent(categoryText)}`; - const linkEl = window.document.createElement("a"); - linkEl.setAttribute("href", link); - for (const child of categoryEl.childNodes) { - linkEl.append(child); - } - categoryEl.appendChild(linkEl); - } - } - } catch { - // Ignore errors - } - }; - function hasTitleCategories() { - return window.document.querySelector(categorySelector) !== null; - } - - function offsetRelativeUrl(url) { - const offset = getMeta("quarto:offset"); - return offset ? offset + url : url; - } - - function offsetAbsoluteUrl(url) { - const offset = getMeta("quarto:offset"); - const baseUrl = new URL(offset, window.location); - - const projRelativeUrl = url.replace(baseUrl, ""); - if (projRelativeUrl.startsWith("/")) { - return projRelativeUrl; - } else { - return "/" + projRelativeUrl; - } - } - - // read a meta tag value - function getMeta(metaName) { - const metas = window.document.getElementsByTagName("meta"); - for (let i = 0; i < metas.length; i++) { - if (metas[i].getAttribute("name") === metaName) { - return metas[i].getAttribute("content"); - } - } - return ""; - } - - async function findAndActivateCategories() { - const currentPagePath = offsetAbsoluteUrl(window.location.href); - const response = await fetch(offsetRelativeUrl("listings.json")); - if (response.status == 200) { - return response.json().then(function (listingPaths) { - const listingHrefs = []; - for (const listingPath of listingPaths) { - const pathWithoutLeadingSlash = listingPath.listing.substring(1); - for (const item of listingPath.items) { - if ( - item === currentPagePath || - item === currentPagePath + "index.html" - ) { - // Resolve this path against the offset to be sure - // we already are using the correct path to the listing - // (this adjusts the listing urls to be rooted against - // whatever root the page is actually running against) - const relative = offsetRelativeUrl(pathWithoutLeadingSlash); - const baseUrl = window.location; - const resolvedPath = new URL(relative, baseUrl); - listingHrefs.push(resolvedPath.pathname); - break; - } - } - } - - // Look up the tree for a nearby linting and use that if we find one - const nearestListing = findNearestParentListing( - offsetAbsoluteUrl(window.location.pathname), - listingHrefs - ); - if (nearestListing) { - activateCategories(nearestListing); - } else { - // See if the referrer is a listing page for this item - const referredRelativePath = offsetAbsoluteUrl(document.referrer); - const referrerListing = listingHrefs.find((listingHref) => { - const isListingReferrer = - listingHref === referredRelativePath || - listingHref === referredRelativePath + "index.html"; - return isListingReferrer; - }); - - if (referrerListing) { - // Try to use the referrer if possible - activateCategories(referrerListing); - } else if (listingHrefs.length > 0) { - // Otherwise, just fall back to the first listing - activateCategories(listingHrefs[0]); - } - } - }); - } - } - if (hasTitleCategories()) { - findAndActivateCategories(); - } - - const findNearestParentListing = (href, listingHrefs) => { - if (!href || !listingHrefs) { - return undefined; - } - // Look up the tree for a nearby linting and use that if we find one - const relativeParts = href.substring(1).split("/"); - while (relativeParts.length > 0) { - const path = relativeParts.join("/"); - for (const listingHref of listingHrefs) { - if (listingHref.startsWith(path)) { - return listingHref; - } - } - relativeParts.pop(); - } - - return undefined; - }; - - const manageSidebarVisiblity = (el, placeholderDescriptor) => { - let isVisible = true; - let elRect; - - return (hiddenRegions) => { - if (el === null) { - return; - } - - // Find the last element of the TOC - const lastChildEl = el.lastElementChild; - - if (lastChildEl) { - // Converts the sidebar to a menu - const convertToMenu = () => { - for (const child of el.children) { - child.style.opacity = 0; - child.style.overflow = "hidden"; - child.style.pointerEvents = "none"; - } - - nexttick(() => { - const toggleContainer = window.document.createElement("div"); - toggleContainer.style.width = "100%"; - toggleContainer.classList.add("zindex-over-content"); - toggleContainer.classList.add("quarto-sidebar-toggle"); - toggleContainer.classList.add("headroom-target"); // Marks this to be managed by headeroom - toggleContainer.id = placeholderDescriptor.id; - toggleContainer.style.position = "fixed"; - - const toggleIcon = window.document.createElement("i"); - toggleIcon.classList.add("quarto-sidebar-toggle-icon"); - toggleIcon.classList.add("bi"); - toggleIcon.classList.add("bi-caret-down-fill"); - - const toggleTitle = window.document.createElement("div"); - const titleEl = window.document.body.querySelector( - placeholderDescriptor.titleSelector - ); - if (titleEl) { - toggleTitle.append( - titleEl.textContent || titleEl.innerText, - toggleIcon - ); - } - toggleTitle.classList.add("zindex-over-content"); - toggleTitle.classList.add("quarto-sidebar-toggle-title"); - toggleContainer.append(toggleTitle); - - const toggleContents = window.document.createElement("div"); - toggleContents.classList = el.classList; - toggleContents.classList.add("zindex-over-content"); - toggleContents.classList.add("quarto-sidebar-toggle-contents"); - for (const child of el.children) { - if (child.id === "toc-title") { - continue; - } - - const clone = child.cloneNode(true); - clone.style.opacity = 1; - clone.style.pointerEvents = null; - clone.style.display = null; - toggleContents.append(clone); - } - toggleContents.style.height = "0px"; - const positionToggle = () => { - // position the element (top left of parent, same width as parent) - if (!elRect) { - elRect = el.getBoundingClientRect(); - } - toggleContainer.style.left = `${elRect.left}px`; - toggleContainer.style.top = `${elRect.top}px`; - toggleContainer.style.width = `${elRect.width}px`; - }; - positionToggle(); - - toggleContainer.append(toggleContents); - el.parentElement.prepend(toggleContainer); - - // Process clicks - let tocShowing = false; - // Allow the caller to control whether this is dismissed - // when it is clicked (e.g. sidebar navigation supports - // opening and closing the nav tree, so don't dismiss on click) - const clickEl = placeholderDescriptor.dismissOnClick - ? toggleContainer - : toggleTitle; - - const closeToggle = () => { - if (tocShowing) { - toggleContainer.classList.remove("expanded"); - toggleContents.style.height = "0px"; - tocShowing = false; - } - }; - - // Get rid of any expanded toggle if the user scrolls - window.document.addEventListener( - "scroll", - throttle(() => { - closeToggle(); - }, 50) - ); - - // Handle positioning of the toggle - window.addEventListener( - "resize", - throttle(() => { - elRect = undefined; - positionToggle(); - }, 50) - ); - - window.addEventListener("quarto-hrChanged", () => { - elRect = undefined; - }); - - // Process the click - clickEl.onclick = () => { - if (!tocShowing) { - toggleContainer.classList.add("expanded"); - toggleContents.style.height = null; - tocShowing = true; - } else { - closeToggle(); - } - }; - }); - }; - - // Converts a sidebar from a menu back to a sidebar - const convertToSidebar = () => { - for (const child of el.children) { - child.style.opacity = 1; - child.style.overflow = null; - child.style.pointerEvents = null; - } - - const placeholderEl = window.document.getElementById( - placeholderDescriptor.id - ); - if (placeholderEl) { - placeholderEl.remove(); - } - - el.classList.remove("rollup"); - }; - - if (isReaderMode()) { - convertToMenu(); - isVisible = false; - } else { - // Find the top and bottom o the element that is being managed - const elTop = el.offsetTop; - const elBottom = - elTop + lastChildEl.offsetTop + lastChildEl.offsetHeight; - - if (!isVisible) { - // If the element is current not visible reveal if there are - // no conflicts with overlay regions - if (!inHiddenRegion(elTop, elBottom, hiddenRegions)) { - convertToSidebar(); - isVisible = true; - } - } else { - // If the element is visible, hide it if it conflicts with overlay regions - // and insert a placeholder toggle (or if we're in reader mode) - if (inHiddenRegion(elTop, elBottom, hiddenRegions)) { - convertToMenu(); - isVisible = false; - } - } - } - } - }; - }; - - const tabEls = document.querySelectorAll('a[data-bs-toggle="tab"]'); - for (const tabEl of tabEls) { - const id = tabEl.getAttribute("data-bs-target"); - if (id) { - const columnEl = document.querySelector( - `${id} .column-margin, .tabset-margin-content` - ); - if (columnEl) - tabEl.addEventListener("shown.bs.tab", function (event) { - const el = event.srcElement; - if (el) { - const visibleCls = `${el.id}-margin-content`; - // walk up until we find a parent tabset - let panelTabsetEl = el.parentElement; - while (panelTabsetEl) { - if (panelTabsetEl.classList.contains("panel-tabset")) { - break; - } - panelTabsetEl = panelTabsetEl.parentElement; - } - - if (panelTabsetEl) { - const prevSib = panelTabsetEl.previousElementSibling; - if ( - prevSib && - prevSib.classList.contains("tabset-margin-container") - ) { - const childNodes = prevSib.querySelectorAll( - ".tabset-margin-content" - ); - for (const childEl of childNodes) { - if (childEl.classList.contains(visibleCls)) { - childEl.classList.remove("collapse"); - } else { - childEl.classList.add("collapse"); - } - } - } - } - } - - layoutMarginEls(); - }); - } - } - - // Manage the visibility of the toc and the sidebar - const marginScrollVisibility = manageSidebarVisiblity(marginSidebarEl, { - id: "quarto-toc-toggle", - titleSelector: "#toc-title", - dismissOnClick: true, - }); - const sidebarScrollVisiblity = manageSidebarVisiblity(sidebarEl, { - id: "quarto-sidebarnav-toggle", - titleSelector: ".title", - dismissOnClick: false, - }); - let tocLeftScrollVisibility; - if (leftTocEl) { - tocLeftScrollVisibility = manageSidebarVisiblity(leftTocEl, { - id: "quarto-lefttoc-toggle", - titleSelector: "#toc-title", - dismissOnClick: true, - }); - } - - // Find the first element that uses formatting in special columns - const conflictingEls = window.document.body.querySelectorAll( - '[class^="column-"], [class*=" column-"], aside, [class*="margin-caption"], [class*=" margin-caption"], [class*="margin-ref"], [class*=" margin-ref"]' - ); - - // Filter all the possibly conflicting elements into ones - // the do conflict on the left or ride side - const arrConflictingEls = Array.from(conflictingEls); - const leftSideConflictEls = arrConflictingEls.filter((el) => { - if (el.tagName === "ASIDE") { - return false; - } - return Array.from(el.classList).find((className) => { - return ( - className !== "column-body" && - className.startsWith("column-") && - !className.endsWith("right") && - !className.endsWith("container") && - className !== "column-margin" - ); - }); - }); - const rightSideConflictEls = arrConflictingEls.filter((el) => { - if (el.tagName === "ASIDE") { - return true; - } - - const hasMarginCaption = Array.from(el.classList).find((className) => { - return className == "margin-caption"; - }); - if (hasMarginCaption) { - return true; - } - - return Array.from(el.classList).find((className) => { - return ( - className !== "column-body" && - !className.endsWith("container") && - className.startsWith("column-") && - !className.endsWith("left") - ); - }); - }); - - const kOverlapPaddingSize = 10; - function toRegions(els) { - return els.map((el) => { - const boundRect = el.getBoundingClientRect(); - const top = - boundRect.top + - document.documentElement.scrollTop - - kOverlapPaddingSize; - return { - top, - bottom: top + el.scrollHeight + 2 * kOverlapPaddingSize, - }; - }); - } - - let hasObserved = false; - const visibleItemObserver = (els) => { - let visibleElements = [...els]; - const intersectionObserver = new IntersectionObserver( - (entries, _observer) => { - entries.forEach((entry) => { - if (entry.isIntersecting) { - if (visibleElements.indexOf(entry.target) === -1) { - visibleElements.push(entry.target); - } - } else { - visibleElements = visibleElements.filter((visibleEntry) => { - return visibleEntry !== entry; - }); - } - }); - - if (!hasObserved) { - hideOverlappedSidebars(); - } - hasObserved = true; - }, - {} - ); - els.forEach((el) => { - intersectionObserver.observe(el); - }); - - return { - getVisibleEntries: () => { - return visibleElements; - }, - }; - }; - - const rightElementObserver = visibleItemObserver(rightSideConflictEls); - const leftElementObserver = visibleItemObserver(leftSideConflictEls); - - const hideOverlappedSidebars = () => { - marginScrollVisibility(toRegions(rightElementObserver.getVisibleEntries())); - sidebarScrollVisiblity(toRegions(leftElementObserver.getVisibleEntries())); - if (tocLeftScrollVisibility) { - tocLeftScrollVisibility( - toRegions(leftElementObserver.getVisibleEntries()) - ); - } - }; - - window.quartoToggleReader = () => { - // Applies a slow class (or removes it) - // to update the transition speed - const slowTransition = (slow) => { - const manageTransition = (id, slow) => { - const el = document.getElementById(id); - if (el) { - if (slow) { - el.classList.add("slow"); - } else { - el.classList.remove("slow"); - } - } - }; - - manageTransition("TOC", slow); - manageTransition("quarto-sidebar", slow); - }; - const readerMode = !isReaderMode(); - setReaderModeValue(readerMode); - - // If we're entering reader mode, slow the transition - if (readerMode) { - slowTransition(readerMode); - } - highlightReaderToggle(readerMode); - hideOverlappedSidebars(); - - // If we're exiting reader mode, restore the non-slow transition - if (!readerMode) { - slowTransition(!readerMode); - } - }; - - const highlightReaderToggle = (readerMode) => { - const els = document.querySelectorAll(".quarto-reader-toggle"); - if (els) { - els.forEach((el) => { - if (readerMode) { - el.classList.add("reader"); - } else { - el.classList.remove("reader"); - } - }); - } - }; - - const setReaderModeValue = (val) => { - if (window.location.protocol !== "file:") { - window.localStorage.setItem("quarto-reader-mode", val); - } else { - localReaderMode = val; - } - }; - - const isReaderMode = () => { - if (window.location.protocol !== "file:") { - return window.localStorage.getItem("quarto-reader-mode") === "true"; - } else { - return localReaderMode; - } - }; - let localReaderMode = null; - - const tocOpenDepthStr = tocEl?.getAttribute("data-toc-expanded"); - const tocOpenDepth = tocOpenDepthStr ? Number(tocOpenDepthStr) : 1; - - // Walk the TOC and collapse/expand nodes - // Nodes are expanded if: - // - they are top level - // - they have children that are 'active' links - // - they are directly below an link that is 'active' - const walk = (el, depth) => { - // Tick depth when we enter a UL - if (el.tagName === "UL") { - depth = depth + 1; - } - - // It this is active link - let isActiveNode = false; - if (el.tagName === "A" && el.classList.contains("active")) { - isActiveNode = true; - } - - // See if there is an active child to this element - let hasActiveChild = false; - for (child of el.children) { - hasActiveChild = walk(child, depth) || hasActiveChild; - } - - // Process the collapse state if this is an UL - if (el.tagName === "UL") { - if (tocOpenDepth === -1 && depth > 1) { - // toc-expand: false - el.classList.add("collapse"); - } else if ( - depth <= tocOpenDepth || - hasActiveChild || - prevSiblingIsActiveLink(el) - ) { - el.classList.remove("collapse"); - } else { - el.classList.add("collapse"); - } - - // untick depth when we leave a UL - depth = depth - 1; - } - return hasActiveChild || isActiveNode; - }; - - // walk the TOC and expand / collapse any items that should be shown - if (tocEl) { - updateActiveLink(); - walk(tocEl, 0); - } - - // Throttle the scroll event and walk peridiocally - window.document.addEventListener( - "scroll", - throttle(() => { - if (tocEl) { - updateActiveLink(); - walk(tocEl, 0); - } - if (!isReaderMode()) { - hideOverlappedSidebars(); - } - }, 5) - ); - window.addEventListener( - "resize", - throttle(() => { - if (tocEl) { - updateActiveLink(); - walk(tocEl, 0); - } - if (!isReaderMode()) { - hideOverlappedSidebars(); - } - }, 10) - ); - hideOverlappedSidebars(); - highlightReaderToggle(isReaderMode()); -}); - -// grouped tabsets -window.addEventListener("pageshow", (_event) => { - function getTabSettings() { - const data = localStorage.getItem("quarto-persistent-tabsets-data"); - if (!data) { - localStorage.setItem("quarto-persistent-tabsets-data", "{}"); - return {}; - } - if (data) { - return JSON.parse(data); - } - } - - function setTabSettings(data) { - localStorage.setItem( - "quarto-persistent-tabsets-data", - JSON.stringify(data) - ); - } - - function setTabState(groupName, groupValue) { - const data = getTabSettings(); - data[groupName] = groupValue; - setTabSettings(data); - } - - function toggleTab(tab, active) { - const tabPanelId = tab.getAttribute("aria-controls"); - const tabPanel = document.getElementById(tabPanelId); - if (active) { - tab.classList.add("active"); - tabPanel.classList.add("active"); - } else { - tab.classList.remove("active"); - tabPanel.classList.remove("active"); - } - } - - function toggleAll(selectedGroup, selectorsToSync) { - for (const [thisGroup, tabs] of Object.entries(selectorsToSync)) { - const active = selectedGroup === thisGroup; - for (const tab of tabs) { - toggleTab(tab, active); - } - } - } - - function findSelectorsToSyncByLanguage() { - const result = {}; - const tabs = Array.from( - document.querySelectorAll(`div[data-group] a[id^='tabset-']`) - ); - for (const item of tabs) { - const div = item.parentElement.parentElement.parentElement; - const group = div.getAttribute("data-group"); - if (!result[group]) { - result[group] = {}; - } - const selectorsToSync = result[group]; - const value = item.innerHTML; - if (!selectorsToSync[value]) { - selectorsToSync[value] = []; - } - selectorsToSync[value].push(item); - } - return result; - } - - function setupSelectorSync() { - const selectorsToSync = findSelectorsToSyncByLanguage(); - Object.entries(selectorsToSync).forEach(([group, tabSetsByValue]) => { - Object.entries(tabSetsByValue).forEach(([value, items]) => { - items.forEach((item) => { - item.addEventListener("click", (_event) => { - setTabState(group, value); - toggleAll(value, selectorsToSync[group]); - }); - }); - }); - }); - return selectorsToSync; - } - - const selectorsToSync = setupSelectorSync(); - for (const [group, selectedName] of Object.entries(getTabSettings())) { - const selectors = selectorsToSync[group]; - // it's possible that stale state gives us empty selections, so we explicitly check here. - if (selectors) { - toggleAll(selectedName, selectors); - } - } -}); - -function throttle(func, wait) { - let waiting = false; - return function () { - if (!waiting) { - func.apply(this, arguments); - waiting = true; - setTimeout(function () { - waiting = false; - }, wait); - } - }; -} - -function nexttick(func) { - return setTimeout(func, 0); -} diff --git a/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/uncertainty_files/libs/quarto-html/tippy.css b/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/uncertainty_files/libs/quarto-html/tippy.css deleted file mode 100644 index e6ae635cb..000000000 --- a/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/uncertainty_files/libs/quarto-html/tippy.css +++ /dev/null @@ -1 +0,0 @@ -.tippy-box[data-animation=fade][data-state=hidden]{opacity:0}[data-tippy-root]{max-width:calc(100vw - 10px)}.tippy-box{position:relative;background-color:#333;color:#fff;border-radius:4px;font-size:14px;line-height:1.4;white-space:normal;outline:0;transition-property:transform,visibility,opacity}.tippy-box[data-placement^=top]>.tippy-arrow{bottom:0}.tippy-box[data-placement^=top]>.tippy-arrow:before{bottom:-7px;left:0;border-width:8px 8px 0;border-top-color:initial;transform-origin:center top}.tippy-box[data-placement^=bottom]>.tippy-arrow{top:0}.tippy-box[data-placement^=bottom]>.tippy-arrow:before{top:-7px;left:0;border-width:0 8px 8px;border-bottom-color:initial;transform-origin:center bottom}.tippy-box[data-placement^=left]>.tippy-arrow{right:0}.tippy-box[data-placement^=left]>.tippy-arrow:before{border-width:8px 0 8px 8px;border-left-color:initial;right:-7px;transform-origin:center left}.tippy-box[data-placement^=right]>.tippy-arrow{left:0}.tippy-box[data-placement^=right]>.tippy-arrow:before{left:-7px;border-width:8px 8px 8px 0;border-right-color:initial;transform-origin:center right}.tippy-box[data-inertia][data-state=visible]{transition-timing-function:cubic-bezier(.54,1.5,.38,1.11)}.tippy-arrow{width:16px;height:16px;color:#333}.tippy-arrow:before{content:"";position:absolute;border-color:transparent;border-style:solid}.tippy-content{position:relative;padding:5px 9px;z-index:1} \ No newline at end of file diff --git a/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/uncertainty_files/libs/quarto-html/tippy.umd.min.js b/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/uncertainty_files/libs/quarto-html/tippy.umd.min.js deleted file mode 100644 index ca292be32..000000000 --- a/pr-3694-381c450d92f0921c3f3391bf6c10786ed7f35c16/rendered-demo-notebooks/uncertainty_files/libs/quarto-html/tippy.umd.min.js +++ /dev/null @@ -1,2 +0,0 @@ -!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t(require("@popperjs/core")):"function"==typeof define&&define.amd?define(["@popperjs/core"],t):(e=e||self).tippy=t(e.Popper)}(this,(function(e){"use strict";var t={passive:!0,capture:!0},n=function(){return document.body};function r(e,t,n){if(Array.isArray(e)){var r=e[t];return null==r?Array.isArray(n)?n[t]:n:r}return e}function o(e,t){var n={}.toString.call(e);return 0===n.indexOf("[object")&&n.indexOf(t+"]")>-1}function i(e,t){return"function"==typeof e?e.apply(void 0,t):e}function a(e,t){return 0===t?e:function(r){clearTimeout(n),n=setTimeout((function(){e(r)}),t)};var n}function s(e,t){var n=Object.assign({},e);return t.forEach((function(e){delete n[e]})),n}function u(e){return[].concat(e)}function c(e,t){-1===e.indexOf(t)&&e.push(t)}function p(e){return e.split("-")[0]}function f(e){return[].slice.call(e)}function l(e){return Object.keys(e).reduce((function(t,n){return void 0!==e[n]&&(t[n]=e[n]),t}),{})}function d(){return document.createElement("div")}function v(e){return["Element","Fragment"].some((function(t){return o(e,t)}))}function m(e){return o(e,"MouseEvent")}function g(e){return!(!e||!e._tippy||e._tippy.reference!==e)}function h(e){return v(e)?[e]:function(e){return o(e,"NodeList")}(e)?f(e):Array.isArray(e)?e:f(document.querySelectorAll(e))}function b(e,t){e.forEach((function(e){e&&(e.style.transitionDuration=t+"ms")}))}function y(e,t){e.forEach((function(e){e&&e.setAttribute("data-state",t)}))}function w(e){var t,n=u(e)[0];return null!=n&&null!=(t=n.ownerDocument)&&t.body?n.ownerDocument:document}function E(e,t,n){var r=t+"EventListener";["transitionend","webkitTransitionEnd"].forEach((function(t){e[r](t,n)}))}function O(e,t){for(var n=t;n;){var r;if(e.contains(n))return!0;n=null==n.getRootNode||null==(r=n.getRootNode())?void 0:r.host}return!1}var x={isTouch:!1},C=0;function T(){x.isTouch||(x.isTouch=!0,window.performance&&document.addEventListener("mousemove",A))}function A(){var e=performance.now();e-C<20&&(x.isTouch=!1,document.removeEventListener("mousemove",A)),C=e}function L(){var e=document.activeElement;if(g(e)){var t=e._tippy;e.blur&&!t.state.isVisible&&e.blur()}}var D=!!("undefined"!=typeof window&&"undefined"!=typeof document)&&!!window.msCrypto,R=Object.assign({appendTo:n,aria:{content:"auto",expanded:"auto"},delay:0,duration:[300,250],getReferenceClientRect:null,hideOnClick:!0,ignoreAttributes:!1,interactive:!1,interactiveBorder:2,interactiveDebounce:0,moveTransition:"",offset:[0,10],onAfterUpdate:function(){},onBeforeUpdate:function(){},onCreate:function(){},onDestroy:function(){},onHidden:function(){},onHide:function(){},onMount:function(){},onShow:function(){},onShown:function(){},onTrigger:function(){},onUntrigger:function(){},onClickOutside:function(){},placement:"top",plugins:[],popperOptions:{},render:null,showOnCreate:!1,touch:!0,trigger:"mouseenter focus",triggerTarget:null},{animateFill:!1,followCursor:!1,inlinePositioning:!1,sticky:!1},{allowHTML:!1,animation:"fade",arrow:!0,content:"",inertia:!1,maxWidth:350,role:"tooltip",theme:"",zIndex:9999}),k=Object.keys(R);function P(e){var t=(e.plugins||[]).reduce((function(t,n){var r,o=n.name,i=n.defaultValue;o&&(t[o]=void 0!==e[o]?e[o]:null!=(r=R[o])?r:i);return t}),{});return Object.assign({},e,t)}function j(e,t){var n=Object.assign({},t,{content:i(t.content,[e])},t.ignoreAttributes?{}:function(e,t){return(t?Object.keys(P(Object.assign({},R,{plugins:t}))):k).reduce((function(t,n){var r=(e.getAttribute("data-tippy-"+n)||"").trim();if(!r)return t;if("content"===n)t[n]=r;else try{t[n]=JSON.parse(r)}catch(e){t[n]=r}return t}),{})}(e,t.plugins));return n.aria=Object.assign({},R.aria,n.aria),n.aria={expanded:"auto"===n.aria.expanded?t.interactive:n.aria.expanded,content:"auto"===n.aria.content?t.interactive?null:"describedby":n.aria.content},n}function M(e,t){e.innerHTML=t}function V(e){var t=d();return!0===e?t.className="tippy-arrow":(t.className="tippy-svg-arrow",v(e)?t.appendChild(e):M(t,e)),t}function I(e,t){v(t.content)?(M(e,""),e.appendChild(t.content)):"function"!=typeof t.content&&(t.allowHTML?M(e,t.content):e.textContent=t.content)}function S(e){var t=e.firstElementChild,n=f(t.children);return{box:t,content:n.find((function(e){return e.classList.contains("tippy-content")})),arrow:n.find((function(e){return e.classList.contains("tippy-arrow")||e.classList.contains("tippy-svg-arrow")})),backdrop:n.find((function(e){return e.classList.contains("tippy-backdrop")}))}}function N(e){var t=d(),n=d();n.className="tippy-box",n.setAttribute("data-state","hidden"),n.setAttribute("tabindex","-1");var r=d();function o(n,r){var o=S(t),i=o.box,a=o.content,s=o.arrow;r.theme?i.setAttribute("data-theme",r.theme):i.removeAttribute("data-theme"),"string"==typeof r.animation?i.setAttribute("data-animation",r.animation):i.removeAttribute("data-animation"),r.inertia?i.setAttribute("data-inertia",""):i.removeAttribute("data-inertia"),i.style.maxWidth="number"==typeof r.maxWidth?r.maxWidth+"px":r.maxWidth,r.role?i.setAttribute("role",r.role):i.removeAttribute("role"),n.content===r.content&&n.allowHTML===r.allowHTML||I(a,e.props),r.arrow?s?n.arrow!==r.arrow&&(i.removeChild(s),i.appendChild(V(r.arrow))):i.appendChild(V(r.arrow)):s&&i.removeChild(s)}return r.className="tippy-content",r.setAttribute("data-state","hidden"),I(r,e.props),t.appendChild(n),n.appendChild(r),o(e.props,e.props),{popper:t,onUpdate:o}}N.$$tippy=!0;var B=1,H=[],U=[];function _(o,s){var v,g,h,C,T,A,L,k,M=j(o,Object.assign({},R,P(l(s)))),V=!1,I=!1,N=!1,_=!1,F=[],W=a(we,M.interactiveDebounce),X=B++,Y=(k=M.plugins).filter((function(e,t){return k.indexOf(e)===t})),$={id:X,reference:o,popper:d(),popperInstance:null,props:M,state:{isEnabled:!0,isVisible:!1,isDestroyed:!1,isMounted:!1,isShown:!1},plugins:Y,clearDelayTimeouts:function(){clearTimeout(v),clearTimeout(g),cancelAnimationFrame(h)},setProps:function(e){if($.state.isDestroyed)return;ae("onBeforeUpdate",[$,e]),be();var t=$.props,n=j(o,Object.assign({},t,l(e),{ignoreAttributes:!0}));$.props=n,he(),t.interactiveDebounce!==n.interactiveDebounce&&(ce(),W=a(we,n.interactiveDebounce));t.triggerTarget&&!n.triggerTarget?u(t.triggerTarget).forEach((function(e){e.removeAttribute("aria-expanded")})):n.triggerTarget&&o.removeAttribute("aria-expanded");ue(),ie(),J&&J(t,n);$.popperInstance&&(Ce(),Ae().forEach((function(e){requestAnimationFrame(e._tippy.popperInstance.forceUpdate)})));ae("onAfterUpdate",[$,e])},setContent:function(e){$.setProps({content:e})},show:function(){var e=$.state.isVisible,t=$.state.isDestroyed,o=!$.state.isEnabled,a=x.isTouch&&!$.props.touch,s=r($.props.duration,0,R.duration);if(e||t||o||a)return;if(te().hasAttribute("disabled"))return;if(ae("onShow",[$],!1),!1===$.props.onShow($))return;$.state.isVisible=!0,ee()&&(z.style.visibility="visible");ie(),de(),$.state.isMounted||(z.style.transition="none");if(ee()){var u=re(),p=u.box,f=u.content;b([p,f],0)}A=function(){var e;if($.state.isVisible&&!_){if(_=!0,z.offsetHeight,z.style.transition=$.props.moveTransition,ee()&&$.props.animation){var t=re(),n=t.box,r=t.content;b([n,r],s),y([n,r],"visible")}se(),ue(),c(U,$),null==(e=$.popperInstance)||e.forceUpdate(),ae("onMount",[$]),$.props.animation&&ee()&&function(e,t){me(e,t)}(s,(function(){$.state.isShown=!0,ae("onShown",[$])}))}},function(){var e,t=$.props.appendTo,r=te();e=$.props.interactive&&t===n||"parent"===t?r.parentNode:i(t,[r]);e.contains(z)||e.appendChild(z);$.state.isMounted=!0,Ce()}()},hide:function(){var e=!$.state.isVisible,t=$.state.isDestroyed,n=!$.state.isEnabled,o=r($.props.duration,1,R.duration);if(e||t||n)return;if(ae("onHide",[$],!1),!1===$.props.onHide($))return;$.state.isVisible=!1,$.state.isShown=!1,_=!1,V=!1,ee()&&(z.style.visibility="hidden");if(ce(),ve(),ie(!0),ee()){var i=re(),a=i.box,s=i.content;$.props.animation&&(b([a,s],o),y([a,s],"hidden"))}se(),ue(),$.props.animation?ee()&&function(e,t){me(e,(function(){!$.state.isVisible&&z.parentNode&&z.parentNode.contains(z)&&t()}))}(o,$.unmount):$.unmount()},hideWithInteractivity:function(e){ne().addEventListener("mousemove",W),c(H,W),W(e)},enable:function(){$.state.isEnabled=!0},disable:function(){$.hide(),$.state.isEnabled=!1},unmount:function(){$.state.isVisible&&$.hide();if(!$.state.isMounted)return;Te(),Ae().forEach((function(e){e._tippy.unmount()})),z.parentNode&&z.parentNode.removeChild(z);U=U.filter((function(e){return e!==$})),$.state.isMounted=!1,ae("onHidden",[$])},destroy:function(){if($.state.isDestroyed)return;$.clearDelayTimeouts(),$.unmount(),be(),delete o._tippy,$.state.isDestroyed=!0,ae("onDestroy",[$])}};if(!M.render)return $;var q=M.render($),z=q.popper,J=q.onUpdate;z.setAttribute("data-tippy-root",""),z.id="tippy-"+$.id,$.popper=z,o._tippy=$,z._tippy=$;var G=Y.map((function(e){return e.fn($)})),K=o.hasAttribute("aria-expanded");return he(),ue(),ie(),ae("onCreate",[$]),M.showOnCreate&&Le(),z.addEventListener("mouseenter",(function(){$.props.interactive&&$.state.isVisible&&$.clearDelayTimeouts()})),z.addEventListener("mouseleave",(function(){$.props.interactive&&$.props.trigger.indexOf("mouseenter")>=0&&ne().addEventListener("mousemove",W)})),$;function Q(){var e=$.props.touch;return Array.isArray(e)?e:[e,0]}function Z(){return"hold"===Q()[0]}function ee(){var e;return!(null==(e=$.props.render)||!e.$$tippy)}function te(){return L||o}function ne(){var e=te().parentNode;return e?w(e):document}function re(){return S(z)}function oe(e){return $.state.isMounted&&!$.state.isVisible||x.isTouch||C&&"focus"===C.type?0:r($.props.delay,e?0:1,R.delay)}function ie(e){void 0===e&&(e=!1),z.style.pointerEvents=$.props.interactive&&!e?"":"none",z.style.zIndex=""+$.props.zIndex}function ae(e,t,n){var r;(void 0===n&&(n=!0),G.forEach((function(n){n[e]&&n[e].apply(n,t)})),n)&&(r=$.props)[e].apply(r,t)}function se(){var e=$.props.aria;if(e.content){var t="aria-"+e.content,n=z.id;u($.props.triggerTarget||o).forEach((function(e){var r=e.getAttribute(t);if($.state.isVisible)e.setAttribute(t,r?r+" "+n:n);else{var o=r&&r.replace(n,"").trim();o?e.setAttribute(t,o):e.removeAttribute(t)}}))}}function ue(){!K&&$.props.aria.expanded&&u($.props.triggerTarget||o).forEach((function(e){$.props.interactive?e.setAttribute("aria-expanded",$.state.isVisible&&e===te()?"true":"false"):e.removeAttribute("aria-expanded")}))}function ce(){ne().removeEventListener("mousemove",W),H=H.filter((function(e){return e!==W}))}function pe(e){if(!x.isTouch||!N&&"mousedown"!==e.type){var t=e.composedPath&&e.composedPath()[0]||e.target;if(!$.props.interactive||!O(z,t)){if(u($.props.triggerTarget||o).some((function(e){return O(e,t)}))){if(x.isTouch)return;if($.state.isVisible&&$.props.trigger.indexOf("click")>=0)return}else ae("onClickOutside",[$,e]);!0===$.props.hideOnClick&&($.clearDelayTimeouts(),$.hide(),I=!0,setTimeout((function(){I=!1})),$.state.isMounted||ve())}}}function fe(){N=!0}function le(){N=!1}function de(){var e=ne();e.addEventListener("mousedown",pe,!0),e.addEventListener("touchend",pe,t),e.addEventListener("touchstart",le,t),e.addEventListener("touchmove",fe,t)}function ve(){var e=ne();e.removeEventListener("mousedown",pe,!0),e.removeEventListener("touchend",pe,t),e.removeEventListener("touchstart",le,t),e.removeEventListener("touchmove",fe,t)}function me(e,t){var n=re().box;function r(e){e.target===n&&(E(n,"remove",r),t())}if(0===e)return t();E(n,"remove",T),E(n,"add",r),T=r}function ge(e,t,n){void 0===n&&(n=!1),u($.props.triggerTarget||o).forEach((function(r){r.addEventListener(e,t,n),F.push({node:r,eventType:e,handler:t,options:n})}))}function he(){var e;Z()&&(ge("touchstart",ye,{passive:!0}),ge("touchend",Ee,{passive:!0})),(e=$.props.trigger,e.split(/\s+/).filter(Boolean)).forEach((function(e){if("manual"!==e)switch(ge(e,ye),e){case"mouseenter":ge("mouseleave",Ee);break;case"focus":ge(D?"focusout":"blur",Oe);break;case"focusin":ge("focusout",Oe)}}))}function be(){F.forEach((function(e){var t=e.node,n=e.eventType,r=e.handler,o=e.options;t.removeEventListener(n,r,o)})),F=[]}function ye(e){var t,n=!1;if($.state.isEnabled&&!xe(e)&&!I){var r="focus"===(null==(t=C)?void 0:t.type);C=e,L=e.currentTarget,ue(),!$.state.isVisible&&m(e)&&H.forEach((function(t){return t(e)})),"click"===e.type&&($.props.trigger.indexOf("mouseenter")<0||V)&&!1!==$.props.hideOnClick&&$.state.isVisible?n=!0:Le(e),"click"===e.type&&(V=!n),n&&!r&&De(e)}}function we(e){var t=e.target,n=te().contains(t)||z.contains(t);"mousemove"===e.type&&n||function(e,t){var n=t.clientX,r=t.clientY;return e.every((function(e){var t=e.popperRect,o=e.popperState,i=e.props.interactiveBorder,a=p(o.placement),s=o.modifiersData.offset;if(!s)return!0;var u="bottom"===a?s.top.y:0,c="top"===a?s.bottom.y:0,f="right"===a?s.left.x:0,l="left"===a?s.right.x:0,d=t.top-r+u>i,v=r-t.bottom-c>i,m=t.left-n+f>i,g=n-t.right-l>i;return d||v||m||g}))}(Ae().concat(z).map((function(e){var t,n=null==(t=e._tippy.popperInstance)?void 0:t.state;return n?{popperRect:e.getBoundingClientRect(),popperState:n,props:M}:null})).filter(Boolean),e)&&(ce(),De(e))}function Ee(e){xe(e)||$.props.trigger.indexOf("click")>=0&&V||($.props.interactive?$.hideWithInteractivity(e):De(e))}function Oe(e){$.props.trigger.indexOf("focusin")<0&&e.target!==te()||$.props.interactive&&e.relatedTarget&&z.contains(e.relatedTarget)||De(e)}function xe(e){return!!x.isTouch&&Z()!==e.type.indexOf("touch")>=0}function Ce(){Te();var t=$.props,n=t.popperOptions,r=t.placement,i=t.offset,a=t.getReferenceClientRect,s=t.moveTransition,u=ee()?S(z).arrow:null,c=a?{getBoundingClientRect:a,contextElement:a.contextElement||te()}:o,p=[{name:"offset",options:{offset:i}},{name:"preventOverflow",options:{padding:{top:2,bottom:2,left:5,right:5}}},{name:"flip",options:{padding:5}},{name:"computeStyles",options:{adaptive:!s}},{name:"$$tippy",enabled:!0,phase:"beforeWrite",requires:["computeStyles"],fn:function(e){var t=e.state;if(ee()){var n=re().box;["placement","reference-hidden","escaped"].forEach((function(e){"placement"===e?n.setAttribute("data-placement",t.placement):t.attributes.popper["data-popper-"+e]?n.setAttribute("data-"+e,""):n.removeAttribute("data-"+e)})),t.attributes.popper={}}}}];ee()&&u&&p.push({name:"arrow",options:{element:u,padding:3}}),p.push.apply(p,(null==n?void 0:n.modifiers)||[]),$.popperInstance=e.createPopper(c,z,Object.assign({},n,{placement:r,onFirstUpdate:A,modifiers:p}))}function Te(){$.popperInstance&&($.popperInstance.destroy(),$.popperInstance=null)}function Ae(){return f(z.querySelectorAll("[data-tippy-root]"))}function Le(e){$.clearDelayTimeouts(),e&&ae("onTrigger",[$,e]),de();var t=oe(!0),n=Q(),r=n[0],o=n[1];x.isTouch&&"hold"===r&&o&&(t=o),t?v=setTimeout((function(){$.show()}),t):$.show()}function De(e){if($.clearDelayTimeouts(),ae("onUntrigger",[$,e]),$.state.isVisible){if(!($.props.trigger.indexOf("mouseenter")>=0&&$.props.trigger.indexOf("click")>=0&&["mouseleave","mousemove"].indexOf(e.type)>=0&&V)){var t=oe(!1);t?g=setTimeout((function(){$.state.isVisible&&$.hide()}),t):h=requestAnimationFrame((function(){$.hide()}))}}else ve()}}function F(e,n){void 0===n&&(n={});var r=R.plugins.concat(n.plugins||[]);document.addEventListener("touchstart",T,t),window.addEventListener("blur",L);var o=Object.assign({},n,{plugins:r}),i=h(e).reduce((function(e,t){var n=t&&_(t,o);return n&&e.push(n),e}),[]);return v(e)?i[0]:i}F.defaultProps=R,F.setDefaultProps=function(e){Object.keys(e).forEach((function(t){R[t]=e[t]}))},F.currentInput=x;var W=Object.assign({},e.applyStyles,{effect:function(e){var t=e.state,n={popper:{position:t.options.strategy,left:"0",top:"0",margin:"0"},arrow:{position:"absolute"},reference:{}};Object.assign(t.elements.popper.style,n.popper),t.styles=n,t.elements.arrow&&Object.assign(t.elements.arrow.style,n.arrow)}}),X={mouseover:"mouseenter",focusin:"focus",click:"click"};var Y={name:"animateFill",defaultValue:!1,fn:function(e){var t;if(null==(t=e.props.render)||!t.$$tippy)return{};var n=S(e.popper),r=n.box,o=n.content,i=e.props.animateFill?function(){var e=d();return e.className="tippy-backdrop",y([e],"hidden"),e}():null;return{onCreate:function(){i&&(r.insertBefore(i,r.firstElementChild),r.setAttribute("data-animatefill",""),r.style.overflow="hidden",e.setProps({arrow:!1,animation:"shift-away"}))},onMount:function(){if(i){var e=r.style.transitionDuration,t=Number(e.replace("ms",""));o.style.transitionDelay=Math.round(t/10)+"ms",i.style.transitionDuration=e,y([i],"visible")}},onShow:function(){i&&(i.style.transitionDuration="0ms")},onHide:function(){i&&y([i],"hidden")}}}};var $={clientX:0,clientY:0},q=[];function z(e){var t=e.clientX,n=e.clientY;$={clientX:t,clientY:n}}var J={name:"followCursor",defaultValue:!1,fn:function(e){var t=e.reference,n=w(e.props.triggerTarget||t),r=!1,o=!1,i=!0,a=e.props;function s(){return"initial"===e.props.followCursor&&e.state.isVisible}function u(){n.addEventListener("mousemove",f)}function c(){n.removeEventListener("mousemove",f)}function p(){r=!0,e.setProps({getReferenceClientRect:null}),r=!1}function f(n){var r=!n.target||t.contains(n.target),o=e.props.followCursor,i=n.clientX,a=n.clientY,s=t.getBoundingClientRect(),u=i-s.left,c=a-s.top;!r&&e.props.interactive||e.setProps({getReferenceClientRect:function(){var e=t.getBoundingClientRect(),n=i,r=a;"initial"===o&&(n=e.left+u,r=e.top+c);var s="horizontal"===o?e.top:r,p="vertical"===o?e.right:n,f="horizontal"===o?e.bottom:r,l="vertical"===o?e.left:n;return{width:p-l,height:f-s,top:s,right:p,bottom:f,left:l}}})}function l(){e.props.followCursor&&(q.push({instance:e,doc:n}),function(e){e.addEventListener("mousemove",z)}(n))}function d(){0===(q=q.filter((function(t){return t.instance!==e}))).filter((function(e){return e.doc===n})).length&&function(e){e.removeEventListener("mousemove",z)}(n)}return{onCreate:l,onDestroy:d,onBeforeUpdate:function(){a=e.props},onAfterUpdate:function(t,n){var i=n.followCursor;r||void 0!==i&&a.followCursor!==i&&(d(),i?(l(),!e.state.isMounted||o||s()||u()):(c(),p()))},onMount:function(){e.props.followCursor&&!o&&(i&&(f($),i=!1),s()||u())},onTrigger:function(e,t){m(t)&&($={clientX:t.clientX,clientY:t.clientY}),o="focus"===t.type},onHidden:function(){e.props.followCursor&&(p(),c(),i=!0)}}}};var G={name:"inlinePositioning",defaultValue:!1,fn:function(e){var t,n=e.reference;var r=-1,o=!1,i=[],a={name:"tippyInlinePositioning",enabled:!0,phase:"afterWrite",fn:function(o){var a=o.state;e.props.inlinePositioning&&(-1!==i.indexOf(a.placement)&&(i=[]),t!==a.placement&&-1===i.indexOf(a.placement)&&(i.push(a.placement),e.setProps({getReferenceClientRect:function(){return function(e){return function(e,t,n,r){if(n.length<2||null===e)return t;if(2===n.length&&r>=0&&n[0].left>n[1].right)return n[r]||t;switch(e){case"top":case"bottom":var o=n[0],i=n[n.length-1],a="top"===e,s=o.top,u=i.bottom,c=a?o.left:i.left,p=a?o.right:i.right;return{top:s,bottom:u,left:c,right:p,width:p-c,height:u-s};case"left":case"right":var f=Math.min.apply(Math,n.map((function(e){return e.left}))),l=Math.max.apply(Math,n.map((function(e){return e.right}))),d=n.filter((function(t){return"left"===e?t.left===f:t.right===l})),v=d[0].top,m=d[d.length-1].bottom;return{top:v,bottom:m,left:f,right:l,width:l-f,height:m-v};default:return t}}(p(e),n.getBoundingClientRect(),f(n.getClientRects()),r)}(a.placement)}})),t=a.placement)}};function s(){var t;o||(t=function(e,t){var n;return{popperOptions:Object.assign({},e.popperOptions,{modifiers:[].concat(((null==(n=e.popperOptions)?void 0:n.modifiers)||[]).filter((function(e){return e.name!==t.name})),[t])})}}(e.props,a),o=!0,e.setProps(t),o=!1)}return{onCreate:s,onAfterUpdate:s,onTrigger:function(t,n){if(m(n)){var o=f(e.reference.getClientRects()),i=o.find((function(e){return e.left-2<=n.clientX&&e.right+2>=n.clientX&&e.top-2<=n.clientY&&e.bottom+2>=n.clientY})),a=o.indexOf(i);r=a>-1?a:r}},onHidden:function(){r=-1}}}};var K={name:"sticky",defaultValue:!1,fn:function(e){var t=e.reference,n=e.popper;function r(t){return!0===e.props.sticky||e.props.sticky===t}var o=null,i=null;function a(){var s=r("reference")?(e.popperInstance?e.popperInstance.state.elements.reference:t).getBoundingClientRect():null,u=r("popper")?n.getBoundingClientRect():null;(s&&Q(o,s)||u&&Q(i,u))&&e.popperInstance&&e.popperInstance.update(),o=s,i=u,e.state.isMounted&&requestAnimationFrame(a)}return{onMount:function(){e.props.sticky&&a()}}}};function Q(e,t){return!e||!t||(e.top!==t.top||e.right!==t.right||e.bottom!==t.bottom||e.left!==t.left)}return F.setDefaultProps({plugins:[Y,J,G,K],render:N}),F.createSingleton=function(e,t){var n;void 0===t&&(t={});var r,o=e,i=[],a=[],c=t.overrides,p=[],f=!1;function l(){a=o.map((function(e){return u(e.props.triggerTarget||e.reference)})).reduce((function(e,t){return e.concat(t)}),[])}function v(){i=o.map((function(e){return e.reference}))}function m(e){o.forEach((function(t){e?t.enable():t.disable()}))}function g(e){return o.map((function(t){var n=t.setProps;return t.setProps=function(o){n(o),t.reference===r&&e.setProps(o)},function(){t.setProps=n}}))}function h(e,t){var n=a.indexOf(t);if(t!==r){r=t;var s=(c||[]).concat("content").reduce((function(e,t){return e[t]=o[n].props[t],e}),{});e.setProps(Object.assign({},s,{getReferenceClientRect:"function"==typeof s.getReferenceClientRect?s.getReferenceClientRect:function(){var e;return null==(e=i[n])?void 0:e.getBoundingClientRect()}}))}}m(!1),v(),l();var b={fn:function(){return{onDestroy:function(){m(!0)},onHidden:function(){r=null},onClickOutside:function(e){e.props.showOnCreate&&!f&&(f=!0,r=null)},onShow:function(e){e.props.showOnCreate&&!f&&(f=!0,h(e,i[0]))},onTrigger:function(e,t){h(e,t.currentTarget)}}}},y=F(d(),Object.assign({},s(t,["overrides"]),{plugins:[b].concat(t.plugins||[]),triggerTarget:a,popperOptions:Object.assign({},t.popperOptions,{modifiers:[].concat((null==(n=t.popperOptions)?void 0:n.modifiers)||[],[W])})})),w=y.show;y.show=function(e){if(w(),!r&&null==e)return h(y,i[0]);if(!r||null!=e){if("number"==typeof e)return i[e]&&h(y,i[e]);if(o.indexOf(e)>=0){var t=e.reference;return h(y,t)}return i.indexOf(e)>=0?h(y,e):void 0}},y.showNext=function(){var e=i[0];if(!r)return y.show(0);var t=i.indexOf(r);y.show(i[t+1]||e)},y.showPrevious=function(){var e=i[i.length-1];if(!r)return y.show(e);var t=i.indexOf(r),n=i[t-1]||e;y.show(n)};var E=y.setProps;return y.setProps=function(e){c=e.overrides||c,E(e)},y.setInstances=function(e){m(!0),p.forEach((function(e){return e()})),o=e,m(!1),v(),l(),p=g(y),y.setProps({triggerTarget:a})},p=g(y),y},F.delegate=function(e,n){var r=[],o=[],i=!1,a=n.target,c=s(n,["target"]),p=Object.assign({},c,{trigger:"manual",touch:!1}),f=Object.assign({touch:R.touch},c,{showOnCreate:!0}),l=F(e,p);function d(e){if(e.target&&!i){var t=e.target.closest(a);if(t){var r=t.getAttribute("data-tippy-trigger")||n.trigger||R.trigger;if(!t._tippy&&!("touchstart"===e.type&&"boolean"==typeof f.touch||"touchstart"!==e.type&&r.indexOf(X[e.type])<0)){var s=F(t,f);s&&(o=o.concat(s))}}}}function v(e,t,n,o){void 0===o&&(o=!1),e.addEventListener(t,n,o),r.push({node:e,eventType:t,handler:n,options:o})}return u(l).forEach((function(e){var n=e.destroy,a=e.enable,s=e.disable;e.destroy=function(e){void 0===e&&(e=!0),e&&o.forEach((function(e){e.destroy()})),o=[],r.forEach((function(e){var t=e.node,n=e.eventType,r=e.handler,o=e.options;t.removeEventListener(n,r,o)})),r=[],n()},e.enable=function(){a(),o.forEach((function(e){return e.enable()})),i=!1},e.disable=function(){s(),o.forEach((function(e){return e.disable()})),i=!0},function(e){var n=e.reference;v(n,"touchstart",d,t),v(n,"mouseover",d),v(n,"focusin",d),v(n,"click",d)}(e)})),l},F.hideAll=function(e){var t=void 0===e?{}:e,n=t.exclude,r=t.duration;U.forEach((function(e){var t=!1;if(n&&(t=g(n)?e.reference===n:e.popper===n.popper),!t){var o=e.props.duration;e.setProps({duration:r}),e.hide(),e.state.isDestroyed||e.setProps({duration:o})}}))},F.roundArrow='',F})); - diff --git a/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/README.txt b/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/README.txt deleted file mode 100644 index 40f7c3623..000000000 --- a/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/README.txt +++ /dev/null @@ -1 +0,0 @@ -Autogenerated by https://github.com/PecanProject/pecan/actions/workflows/render-quarto.yml diff --git a/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/run_pecan.html b/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/run_pecan.html deleted file mode 100644 index fce5f3693..000000000 --- a/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/run_pecan.html +++ /dev/null @@ -1,1215 +0,0 @@ - - - - - - - - - - - -Running Ecosystem Simulations Using PEcAn - - - - - - - - - - - - - - - - - - - -
- -
- -
-
-

Running Ecosystem Simulations Using PEcAn

-
- - - -
- -
-
Authors
-
-

Aritra Dey

-

David LeBauer

-
-
- - - -
- - - -
- - -
-

Introduction

-

Welcome to this PEcAn workflow notebook! This notebook will guide you through running an ecosystem model using PEcAn’s programmatic interface.

-
-

What Is PEcAn?

-

PEcAn (Predictive Ecosystem Analyzer) is a scientific workflow system designed to make ecosystem modeling more transparent, repeatable, and accessible. It helps researchers:

-
    -
  • Run ecosystem models with standardized inputs and outputs
  • -
  • Perform uncertainty analysis on model parameters
  • -
  • Compare model predictions with observations
  • -
  • Share and reproduce scientific workflows
  • -
-
-
-

What This Notebook Does

-

This notebook demonstrates how to:

-
    -
  1. Set up and configure a PEcAn workflow
  2. -
  3. Run an ecosystem model simulation
  4. -
  5. Analyze and visualize the results
  6. -
-
-

The Scenario Being Modeled:

-

We are modeling carbon and productivity dynamics at the Niwot Ridge Forest AmeriFlux site (US-NR1, a high-elevation temperate coniferous forest in Colorado. The model configuration uses the SIPNET process-based ecosystem model, parameterized with a temperate coniferous plant functional type (PFT).

-

The simulation is run for the full year 2004 (January 1 – December 31) using AmeriFlux LBL meteorological drivers from the Niwot Ridge site. The ensemble setup specifies one model run focusing on net primary productivity (NPP) as the target output variable.

-

This scenario is designed to be a minimal, reproducible example to demonstrate how to run SIPNET within the PEcAn workflow. In later steps, this same framework can be extended to include more ensemble members, additional PFTs, longer time periods, or alternative meteorological inputs.

-

This run is based on a study by Moore et. al. (2007) that uses SIPNET to understand the relationship between water and carbon balance at this site.

-
-
-
-

Prerequisites

-

Before running this notebook, make sure you have:

-
    -
  • All the PEcAn packages installed. You can install all PEcAn packages and their dependencies by running the following command in the root of your PEcAn repository:
  • -
-

-# Enable repository from pecanproject
-options(repos = c(
-  pecanproject = 'https://pecanproject.r-universe.dev',
-  CRAN = 'https://cloud.r-project.org'))
-# Download and install PEcAn.all in R
-install.packages('PEcAn.all')
-
-
    -
  • A valid pecan.xml configuration file or use the example provided: pecan/documentation/tutorials/Demo_1_Basic_Run/pecan.xml
  • -
-
-
-

How to Use This Notebook

-
    -
  1. Each section is clearly marked with a heading
  2. -
  3. Code chunks are provided with explanations
  4. -
  5. You can run the code chunks sequentially
  6. -
  7. Once you have successfully run the demo, you can modify parameters to configure new runs and analyses
  8. -
-

Objective:

-

This demo illustrates how to run a basic PEcAn workflow using an R-based Quarto notebook. It will cover loading settings, writing model configuration files, and running model simulations. This approach provides a programmatic alternative to the web-based PEcAn interface for executing ecosystem models.

-
-
-
-

Session Info

-

This section prints your R session information for reproducibility. Having this information at the beginning helps with debugging even if the notebook encounters errors later.

-
-
PEcAn.all::pecan_version()
-
-
 package               v1.9.0 installed  source              
- PEcAn.all             1.9.0  1.9.0.9000 local (/pecan/bas...
- PEcAn.allometry       1.7.4  1.7.4.9000 local (/pecan/mod...
- PEcAn.assim.batch     1.9.0  1.9.0.9000 local (/pecan/mod...
- PEcAn.BASGRA          1.8.1  1.8.1.9000 local (/pecan/mod...
- PEcAn.benchmark       1.7.4  1.7.4.9000 local (/pecan/mod...
- PEcAn.BIOCRO          1.7.4  1.7.5      local (/pecan/mod...
- PEcAn.CABLE           1.7.4  NA         NA                  
- PEcAn.CLM45           1.7.4  1.7.4.9000 local (/pecan/mod...
- PEcAn.DALEC           1.7.4  1.7.5      local (/pecan/mod...
- PEcAn.data.atmosphere 1.9.0  1.9.1      local (/pecan/mod...
- PEcAn.data.land       1.8.1  1.8.2      local (/pecan/mod...
- PEcAn.data.mining     1.7.4  NA         NA                  
- PEcAn.data.remote     1.9.0  1.9.1      local (/pecan/mod...
- PEcAn.DB              1.8.1  1.8.1.9000 local (/pecan/bas...
- PEcAn.dvmdostem       1.7.4  1.7.5      local (/pecan/mod...
- PEcAn.ED2             1.8.1  1.8.2      local (/pecan/mod...
- PEcAn.emulator        1.8.1  1.8.1.9000 local (/pecan/mod...
- PEcAn.FATES           1.8.0  1.8.1      local (/pecan/mod...
- PEcAn.GDAY            1.7.4  1.7.5      local (/pecan/mod...
- PEcAn.JULES           1.7.4  1.7.5      local (/pecan/mod...
- PEcAn.LDNDC           1.0.1  1.0.2      local (/pecan/mod...
- PEcAn.LINKAGES        1.7.4  1.7.5      local (/pecan/mod...
- PEcAn.logger          1.8.3  1.8.4      local (/pecan/bas...
- PEcAn.LPJGUESS        1.8.0  1.8.1      local (/pecan/mod...
- PEcAn.MA              1.7.4  1.7.4.9000 local (/pecan/mod...
- PEcAn.MAAT            1.7.4  1.7.5      local (/pecan/mod...
- PEcAn.MAESPA          1.7.4  1.7.5      local (/pecan/mod...
- PEcAn.ModelName       1.8.1  1.8.1.9000 local (/pecan/mod...
- PEcAn.photosynthesis  1.7.4  1.7.4.9000 local (/pecan/mod...
- PEcAn.PRELES          1.7.4  NA         NA                  
- PEcAn.priors          1.7.4  1.7.4.9000 local (/pecan/mod...
- PEcAn.qaqc            1.7.4  1.7.4.9000 local (/pecan/bas...
- PEcAn.remote          1.9.0  1.9.0.9000 local (/pecan/bas...
- PEcAn.settings        1.9.0  1.9.1      local (/pecan/bas...
- PEcAn.SIBCASA         0.0.2  0.0.3      local (/pecan/mod...
- PEcAn.SIPNET          1.9.0  1.9.1      local (/pecan/mod...
- PEcAn.STICS           1.8.1  1.8.2      local (/pecan/mod...
- PEcAn.uncertainty     1.8.1  1.8.2      local (/pecan/mod...
- PEcAn.utils           1.8.1  1.8.2      local (/pecan/bas...
- PEcAn.visualization   1.8.1  1.8.1.9000 local (/pecan/bas...
- PEcAn.workflow        1.9.0  1.9.0.9000 local (/pecan/bas...
- PEcAnAssimSequential  1.9.0  1.9.0.9000 local (/pecan/mod...
- PEcAnRTM              1.7.4  1.9.0.9000 local (/pecan/mod...
-
-
-
-
-

Install SIPNET v1.3.0

-

If you haven’t already installed the SIPNET binary, you can do so by running the following code. This will download the SIPNET binary to demo_outdir/sipnet and make it executable.

-
-

Note: The demo_outdir directory will be created in the root of your PEcAn installation (i.e., at pecan/demo_outdir/). This directory will contain the SIPNET binary as well as the output generated by PEcAn in this demo.

-
-
-
# Download and install SIPNET v1.3.0
-source(
-  here::here(
-    "documentation/tutorials/Demo_1_Basic_Run/download_sipnet.R"
-  )
-)
-
-
-

Note: You can find the most recent version of the SIPNET binary at: SIPNET GitHub Releases, but this notebook is designed to work with SIPNET v1.3.0.

-
-
-
-

Load PEcAn Packages

-

First, we need to load the PEcAn R packages. These packages provide all the functions we’ll use to run the workflow.

-
-
# Load the PEcAn.all package, which includes all necessary PEcAn functionality
-library("PEcAn.all")
-
-
Loading required package: PEcAn.DB
-
-
-
Loading required package: PEcAn.settings
-
-
-
Loading required package: PEcAn.MA
-
-
-
Loading required package: PEcAn.logger
-
-
-
Loading required package: PEcAn.utils
-
-
-
Loading required package: PEcAn.uncertainty
-
-
-
Loading required package: PEcAn.data.atmosphere
-
-
-
Loading required package: PEcAn.data.land
-
-
-
Loading required package: PEcAn.data.remote
-
-
-
Loading required package: PEcAn.assim.batch
-
-
-
Loading required package: PEcAn.emulator
-
-
-
Loading required package: PEcAn.priors
-
-
-
Loading required package: PEcAn.benchmark
-
-
-
Loading required package: PEcAn.remote
-
-
-
Loading required package: PEcAn.workflow
-
-
-
-
-

Load PEcAn Settings File

-

PEcAn uses an XML-based settings file (pecan.xml) to configure model runs. This file defines key information about the run including: PFT(s), site location, time period of the run, the location of input files and where outputs will be saved. Other settings outside the scope of this demo include the types of analyses that will be performed, how to connect to a database, and how to run it on a high performance computing cluster (we are using the default single model run on a single computer).

-

You can read more about the settings file in the “PEcAn XML” chapter of the documentation.

-

There is an example pecan.xml that has been configured for this demonstration. You can find it at pecan/documentation/tutorials/Demo_1_Basic_Run/pecan.xml.

-

This is how PEcAn loads the settings file:

-
-
settings_path <- here::here("documentation/tutorials/Demo_1_Basic_Run/pecan.xml")
-
-
-
-

Prepare and Validate Settings

-

After specifying the path to the pecan.xml file, the next step involves reading and preparing these settings. PEcAn provides utilities to process and validate the configurations before execution begins.

-
    -
  • PEcAn.settings::read.settings(settings_path): Reads the pecan.xml file and converts it to an R list object.
  • -
  • PEcAn.settings::prepare.settings(settings): Prepares and validates settings. It sets defaults for missing fields, changes file paths to absolute paths, and generally ensures consistency.
  • -
-
-
# Read the settings from the pecan.xml file
-settings <- PEcAn.settings::read.settings(settings_path)
-
-# Prepare and validate the settings
-settings <- PEcAn.settings::prepare.settings(settings)
-
-
-
-

Explore the Settings Object

-

Once the settings have been read and prepared, it is useful to inspect the structure of the settings object. This object is an R list containing all parameters and configurations for the PEcAn workflow.

-
    -
  • str(settings) displays the internal structure of the settings object. This shows how the settings are represented in R and is useful for debugging and verifying settings.
  • -
-
-
str(settings)
-
-
List of 12
- $ info         :List of 4
-  ..$ notes   : NULL
-  ..$ userid  : chr "-1"
-  ..$ username: NULL
-  ..$ date    : chr "2025-06-19-15-34-01"
- $ outdir       : chr "/work/documentation/tutorials/Demo_1_Basic_Run/demo_outdir"
- $ pfts         :List of 1
-  ..$ pft:List of 3
-  .. ..$ name           : chr "temperate.coniferous"
-  .. ..$ posterior.files: chr "pft/temperate.coniferous/prior.distns.Rdata"
-  .. ..$ outdir         : chr "pft/temperate.coniferous"
- $ ensemble     :List of 5
-  ..$ variable     : chr "NPP"
-  ..$ size         : num 1
-  ..$ start.year   : num 2004
-  ..$ end.year     : num 2004
-  ..$ samplingspace:List of 2
-  .. ..$ parameters:List of 1
-  .. .. ..$ method: chr "uniform"
-  .. ..$ met       :List of 1
-  .. .. ..$ method: chr "sampling"
- $ model        :List of 5
-  ..$ type      : chr "SIPNET"
-  ..$ revision  : chr "git"
-  ..$ delete.raw: chr "FALSE"
-  ..$ binary    : chr "demo_outdir/sipnet"
-  ..$ id        : num -1
- $ run          :List of 4
-  ..$ site      :List of 6
-  .. ..$ met.start: chr "2004/01/01"
-  .. ..$ met.end  : chr "2004/12/31"
-  .. ..$ name     : chr "Niwot Ridge Forest/LTER NWT1 (US-NR1)"
-  .. ..$ lat      : chr "40.0329"
-  .. ..$ lon      : chr "-105.546"
-  .. ..$ id       : num -1
-  ..$ inputs    :List of 1
-  .. ..$ met:List of 4
-  .. .. ..$ source  : chr "AmerifluxLBL"
-  .. .. ..$ output  : chr "SIPNET"
-  .. .. ..$ username: chr "Aritra_2004"
-  .. .. ..$ path    :List of 1
-  .. .. .. ..$ path1: chr "dbfiles/AMF_US-NR1_BASE_HH_23-5.2004-01-01.2004-12-31.clim"
-  ..$ start.date: chr "2004/01/01"
-  ..$ end.date  : chr "2004/12/31"
- $ host         :List of 3
-  ..$ name  : chr "localhost"
-  ..$ rundir: chr "/work/documentation/tutorials/Demo_1_Basic_Run/demo_outdir/run"
-  ..$ outdir: chr "/work/documentation/tutorials/Demo_1_Basic_Run/demo_outdir/out"
- $ settings.info:List of 3
-  ..$ deprecated.settings.fixed: logi TRUE
-  ..$ settings.updated         : logi TRUE
-  ..$ checked                  : logi TRUE
- $ database     :List of 1
-  ..$ dbfiles: chr "/root/.pecan/dbfiles"
- $ workflow     :List of 1
-  ..$ id: chr "2025-12-05-18-09-25"
- $ rundir       : chr "/work/documentation/tutorials/Demo_1_Basic_Run/demo_outdir/run"
- $ modeloutdir  : chr "/work/documentation/tutorials/Demo_1_Basic_Run/demo_outdir/out"
- - attr(*, "class")= chr [1:3] "Settings" "SafeList" "list"
-
-
-

Your turn: explore the settings object further using the following commands: * names(settings) to list the top-level keys in the settings object * Once you know the names, you can look at each component in detail, for example: * settings$run to access the run-specific settings, such as start and end dates, model type, and output directory * settings$pfts to explore the Plant Functional Types settings

-

Now you can update each of these settings. Here is a simple example:

-
-
settings$info <- list(
-  author = "Aritra Dey",
-  date = Sys.Date(),
-  description = "Demo run of PEcAn using SIPNET"
-)
-
-

Editing the more interesting settings to change the PFT (settings$pfts) or extend the run (settings$run$end.date) is beyond the scope of this demo. You could change the pft or the end date, but you would need a new file containing parameters for that PFT (settings$pfts$pft$posterior.files), or a climate file (settings$run$met$path$path1) that extends to the desired simulation period.

-

The directory structure created by PEcAn for this demo run will look like this:

-
demo_outdir/               # Root output directory
-├── run/                   # Configuration & execution metadata
-│   ├── runs.txt           # List of run IDs (one per model realization)
-│   ├── <runid>/           # Model-specific config copies (sometimes)
-│   └── config.*           # Generated model configs (e.g., SIPNET)
-├── out/                   # Raw model outputs by run ID
-│   └── <runid>/           # E.g., daily or sub-daily SIPNET output files
-

The root output directory is defined here as demo_outdir/ by settings$outdir. This directory contains log and record files from the PEcAn workflow. They provide a detailed record of how data was generated and are key components of the analysis metadata and provenance. These can be useful for debugging as well as for downstream analysis.

-

Key subdirectories include run/ and out/ that contain files used to configure and run the model, files generated by the underlying ecosystem model, and PEcAn standard outputs used in downstream analyses. These are described in subsequent sections.

-

Additional outputs include logs, a STATUS file that records the steps of the workflow along with timestamps and whether each step was successful, and a copy of the pecan.*.xml file.

-
-
-

Write Model Configuration Files

-

This step generates the model-specific configuration files and scripts that will be used to run the ecosystem model. The process involves:

-
    -
  1. Disabling database write operations because we are not using a database
  2. -
  3. Generating SIPNET configuration files using the runModule.run.write.configs() function.
  4. -
-
-
settings$database <- NULL # Disable database operations for this demo
-settings <- PEcAn.workflow::runModule.run.write.configs(settings)
-
-
Error in postgresqlNewConnection(drv, ...) : 
-  RPosgreSQL error: could not connect root@/var/run/postgresql:5432 on dbname "root": connection to server on socket "/var/run/postgresql/.s.PGSQL.5432" failed: No such file or directory
-    Is the server running locally and accepting connections on that socket?
-
-
-
Loading required package: PEcAn.SIPNET
-
-
-
-
-

Run Model Simulations and Fetch Results

-

This section executes the actual model simulations and retrieves the results. The process is managed by PEcAn’s workflow system, which handles the execution of your chosen ecosystem model.

-
    -
  • runModule_start_model_runs(settings): This function initiates the model runs based on your configuration. It manages the execution of your chosen ecosystem model, using the configuration files generated in the previous step.
  • -
-
-
PEcAn.workflow::runModule_start_model_runs(settings)
-
-

-  |                                                                            
-  |                                                                      |   0%
-  |                                                                            
-  |======================================================================| 100%
-
-
-

This step generates raw model outputs in model-specific format (in this case, sipnet.out) as well as log files.

-
-
-

Extract Model Results and Prepare for Analysis

-

After the model simulation completes, we need to extract the results and prepare them for analysis. This involves:

-
    -
  1. Reading the run ID
  2. -
  3. Setting up output paths
  4. -
  5. Defining time period
  6. -
  7. Loading model output
  8. -
  9. Convert to a standard format
  10. -
-
-
runid <- as.character(read.table(paste(settings$outdir, "/run/", "runs.txt", sep = ""))[1, 1]) # Note: if you are using an xml from a run with multiple ensembles this line will provide only the first run id
-outdir <- file.path(settings$outdir, "/out/", runid)
-start.year <- lubridate::year(settings$run$start.date)
-end.year <- lubridate::year(settings$run$end.date)
-model_output <- PEcAn.utils::read.output(
-  runid,
-  outdir,
-  start.year,
-  end.year,
-  variables = NULL,
-  dataframe = TRUE,
-  verbose = FALSE
-)
-available_vars <- names(model_output)[!names(model_output) %in% c("posix", "time_bounds")]
-
-

Running this code will convert model specific output files into a standardized netCDF ([year].nc) that can be downloaded for visualization and analysis (R, Matlab, ncview, panoply, etc). This is a key step, because this standardization enables PEcAn to apply downstream analyses to outputs from different ecosystem models.

-
-
-

Display Available Model Variables

-

This section shows all the variables that are available in the model output. These variables represent different ecosystem processes and states that the model has simulated.

-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Model Output Variables and Descriptions
VariableDescription
GPPGross Primary Productivity
NEENet Ecosystem Exchange
TotalRespTotal Respiration
AutoRespAutotrophic Respiration
HeteroRespHeterotrophic Respiration
SoilRespSoil Respiration
NPPNet Primary Productivity
GWBIGross Woody Biomass Increment
TotLivBiomTotal living biomass
AGBTotal aboveground biomass
LAILeaf Area Index
leaf_carbon_contentLeaf Carbon Content
fine_root_carbon_contentFine Root Carbon Content
coarse_root_carbon_contentCoarse Root Carbon Content
AbvGrndWoodAbove ground woody biomass
TotSoilCarbTotal Soil Carbon
litter_carbon_contentLitter Carbon Content
QleLatent heat
TranspTotal transpiration
SoilMoistAverage Layer Soil Moisture
SoilMoistFracAverage Layer Fraction of Saturation
SWESnow Water Equivalent
litter_mass_content_of_waterAverage layer litter moisture
yearYear
-
-
-
-
-

Visualize Model Results

-

This section provides examples of how to create time series plots of different model variables. The examples cover various ecosystem processes including carbon fluxes, carbon pools, water variables, and structural variables like Leaf Area Index (LAI).

-
-

Plot Carbon Fluxes

-
-
# Plot Gross Primary Productivity (GPP) and Net Primary Productivity (NPP)
-plot(model_output$posix, model_output$GPP,
-  type = "l",
-  col = "green",
-  xlab = "Date",
-  ylab = "Carbon Flux (kg C m-2 s-1)",
-  main = "Carbon Fluxes Over Time"
-)
-lines(model_output$posix, model_output$NPP, col = "blue")
-legend("topright", legend = c("GPP", "NPP"), col = c("green", "blue"), lty = 1)
-
-
-
-

-
-
-
-
-
-
-

Plot Carbon Pools

-
-
# Plot Total Live Biomass and Total Soil Carbon
-plot(model_output$posix, model_output$TotLivBiom,
-  type = "l",
-  col = "darkgreen",
-  xlab = "Date",
-  ylab = "Carbon Pool (kg C m-2)",
-  main = "Carbon Pools Over Time"
-)
-lines(model_output$posix, model_output$TotSoilCarb, col = "brown")
-legend("topright", legend = c("Total Live Biomass", "Total Soil Carbon"), col = c("darkgreen", "brown"), lty = 1)
-
-
-
-

-
-
-
-
-
-
-

Plot Water Variables

-
-
# Plot Soil Moisture and Snow Water Equivalent
-plot(model_output$posix, model_output$SoilMoist,
-  type = "l",
-  col = "blue",
-  xlab = "Date",
-  ylab = "Soil Moisture (kg m-2)",
-  main = "Soil Moisture Over Time"
-)
-lines(model_output$posix, model_output$SWE, col = "lightblue")
-legend("topright", legend = c("Soil Moisture", "Snow Water Equivalent"), col = c("blue", "lightblue"), lty = 1)
-
-
-
-

-
-
-
-
-
-
-

Plot LAI and Biomass

-
-
# Plot Leaf Area Index (LAI) and Above Ground Wood
-plot(model_output$posix, model_output$LAI,
-  type = "l",
-  col = "darkgreen",
-  xlab = "Date",
-  ylab = "LAI (m2 m-2)",
-  main = "Leaf Area Index Over Time"
-)
-lines(model_output$posix, model_output$AbvGrndWood, col = "brown")
-legend("topright", legend = c("LAI", "Above Ground Wood"), col = c("darkgreen", "brown"), lty = 1)
-
-
-
-

-
-
-
-
-
-
-
-

Conclusion

-

This notebook demonstrated how to set up, run, and analyze a PEcAn ecosystem model workflow programmatically. You can now modify parameters, try different models, or extend the analysis as needed.

-

Try editing the pecan.xml file. Give it a new name and update the settings_path variable at the beginning of this Demo to point to the new file. See how the changes affect the model output!

-
-
-

Clean Up Workflow Output (Optional)

-

If you want to remove all files and directories created by this workflow and start fresh, you can run the following code. This will delete the entire output directory specified in your settings. Use with caution!

-
-
# WARNING: This will permanently delete all workflow output files!
-# Uncomment the line below to enable cleanup.
-# fs::dir_delete(settings$outdir)
-
-
-
-

Session Info

-

This section prints your R session information for reproducibility.

-
-
sessionInfo()
-
-
R version 4.4.3 (2025-02-28)
-Platform: x86_64-pc-linux-gnu
-Running under: Ubuntu 24.04.2 LTS
-
-Matrix products: default
-BLAS:   /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3 
-LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.26.so;  LAPACK version 3.12.0
-
-locale:
- [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C              
- [3] LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8    
- [5] LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8   
- [7] LC_PAPER=en_US.UTF-8       LC_NAME=C                 
- [9] LC_ADDRESS=C               LC_TELEPHONE=C            
-[11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       
-
-time zone: Etc/UTC
-tzcode source: system (glibc)
-
-attached base packages:
-[1] stats     graphics  grDevices utils     datasets  methods   base     
-
-other attached packages:
- [1] PEcAn.SIPNET_1.9.1           PEcAn.all_1.9.0.9000        
- [3] PEcAn.workflow_1.9.0.9000    PEcAn.remote_1.9.0.9000     
- [5] PEcAn.benchmark_1.7.4.9000   PEcAn.priors_1.7.4.9000     
- [7] PEcAn.emulator_1.8.1.9000    PEcAn.assim.batch_1.9.0.9000
- [9] PEcAn.data.remote_1.9.1      PEcAn.data.land_1.8.2       
-[11] PEcAn.data.atmosphere_1.9.1  PEcAn.uncertainty_1.8.2     
-[13] PEcAn.utils_1.8.2            PEcAn.logger_1.8.4          
-[15] PEcAn.MA_1.7.4.9000          PEcAn.settings_1.9.1        
-[17] PEcAn.DB_1.8.1.9000         
-
-loaded via a namespace (and not attached):
- [1] PEcAn.qaqc_1.7.4.9000           DBI_1.2.3                      
- [3] PEcAn.allometry_1.7.4.9000      rlang_1.1.5                    
- [5] magrittr_2.0.3                  furrr_0.3.1                    
- [7] e1071_1.7-16                    compiler_4.4.3                 
- [9] vctrs_0.6.5                     stringr_1.5.1                  
-[11] pkgconfig_2.0.3                 PEcAn.MAESPA_1.7.5             
-[13] fastmap_1.2.0                   PEcAn.ED2_1.8.2                
-[15] PEcAn.dvmdostem_1.7.5           PEcAn.ModelName_1.8.1.9000     
-[17] rmarkdown_2.29                  sessioninfo_1.2.3              
-[19] pracma_2.4.4                    purrr_1.0.4                    
-[21] xfun_0.52                       PEcAn.JULES_1.7.5              
-[23] jsonlite_2.0.0                  PEcAn.LINKAGES_1.7.5           
-[25] PEcAn.SIBCASA_0.0.3             parallel_4.4.3                 
-[27] R6_2.6.1                        PEcAn.DALEC_1.7.5              
-[29] stringi_1.8.7                   RPostgreSQL_0.7-8              
-[31] PEcAn.CLM45_1.7.4.9000          parallelly_1.43.0              
-[33] lubridate_1.9.4                 numDeriv_2016.8-1.1            
-[35] Rcpp_1.0.14                     iterators_1.0.14               
-[37] knitr_1.50                      PEcAnAssimSequential_1.9.0.9000
-[39] igraph_2.1.4                    timechange_0.3.0               
-[41] tidyselect_1.2.1                abind_1.4-8                    
-[43] yaml_2.3.10                     PEcAn.LPJGUESS_1.8.1           
-[45] codetools_0.2-20                listenv_0.9.1                  
-[47] lattice_0.22-6                  tibble_3.2.1                   
-[49] withr_3.0.2                     coda_0.19-4.1                  
-[51] evaluate_1.0.3                  future_1.34.0                  
-[53] sf_1.0-20                       units_0.8-7                    
-[55] proxy_0.4-27                    PEcAn.BASGRA_1.8.1.9000        
-[57] pillar_1.10.2                   PEcAn.BIOCRO_1.7.5             
-[59] KernSmooth_2.23-26              foreach_1.5.2                  
-[61] ncdf4_1.24                      generics_0.1.3                 
-[63] nimble_1.3.0                    rprojroot_2.0.4                
-[65] ggplot2_3.5.2                   munsell_0.5.1                  
-[67] scales_1.3.0                    globals_0.16.3                 
-[69] PEcAn.MAAT_1.7.5                PEcAn.STICS_1.8.2              
-[71] class_7.3-23                    glue_1.8.0                     
-[73] tools_4.4.3                     data.table_1.17.0              
-[75] XML_3.99-0.18                   grid_4.4.3                     
-[77] PEcAn.visualization_1.8.1.9000  PEcAn.photosynthesis_1.7.4.9000
-[79] colorspace_2.1-1                cli_3.6.4                      
-[81] PEcAnRTM_1.9.0.9000             dplyr_1.1.4                    
-[83] PEcAn.GDAY_1.7.5                gtable_0.3.6                   
-[85] PEcAn.FATES_1.8.1               digest_0.6.37                  
-[87] classInt_0.4-11                 PEcAn.LDNDC_1.0.2              
-[89] rjson_0.2.23                    htmlwidgets_1.6.4              
-[91] htmltools_0.5.8.1               lifecycle_1.0.4                
-[93] here_1.0.1                     
-
-
-
- -
- - -
- - - - - \ No newline at end of file diff --git a/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/run_pecan_files/figure-html/plot-carbon-fluxes-1.png b/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/run_pecan_files/figure-html/plot-carbon-fluxes-1.png deleted file mode 100644 index e3171f62b..000000000 Binary files a/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/run_pecan_files/figure-html/plot-carbon-fluxes-1.png and /dev/null differ diff --git a/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/run_pecan_files/figure-html/plot-carbon-pools-1.png b/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/run_pecan_files/figure-html/plot-carbon-pools-1.png deleted file mode 100644 index c4bbbb310..000000000 Binary files a/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/run_pecan_files/figure-html/plot-carbon-pools-1.png and /dev/null differ diff --git a/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/run_pecan_files/figure-html/plot-lai-biomass-1.png b/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/run_pecan_files/figure-html/plot-lai-biomass-1.png deleted file mode 100644 index 78d16c955..000000000 Binary files a/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/run_pecan_files/figure-html/plot-lai-biomass-1.png and /dev/null differ diff --git a/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/run_pecan_files/figure-html/plot-water-variables-1.png b/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/run_pecan_files/figure-html/plot-water-variables-1.png deleted file mode 100644 index 43eb1d6e8..000000000 Binary files a/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/run_pecan_files/figure-html/plot-water-variables-1.png and /dev/null differ diff --git a/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/run_pecan_files/libs/bootstrap/bootstrap-icons.css b/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/run_pecan_files/libs/bootstrap/bootstrap-icons.css deleted file mode 100644 index 285e4448f..000000000 --- a/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/run_pecan_files/libs/bootstrap/bootstrap-icons.css +++ /dev/null @@ -1,2078 +0,0 @@ -/*! - * Bootstrap Icons v1.11.1 (https://icons.getbootstrap.com/) - * Copyright 2019-2023 The Bootstrap Authors - * Licensed under MIT (https://github.com/twbs/icons/blob/main/LICENSE) - */ - -@font-face { - font-display: block; - font-family: "bootstrap-icons"; - src: -url("./bootstrap-icons.woff?2820a3852bdb9a5832199cc61cec4e65") format("woff"); -} - -.bi::before, -[class^="bi-"]::before, -[class*=" bi-"]::before { - display: inline-block; - font-family: bootstrap-icons !important; - font-style: normal; - font-weight: normal !important; - font-variant: normal; - text-transform: none; - line-height: 1; - vertical-align: -.125em; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -.bi-123::before { content: "\f67f"; } -.bi-alarm-fill::before { content: "\f101"; } -.bi-alarm::before { content: "\f102"; } -.bi-align-bottom::before { content: "\f103"; } -.bi-align-center::before { content: "\f104"; } -.bi-align-end::before { content: "\f105"; } -.bi-align-middle::before { content: "\f106"; } -.bi-align-start::before { content: "\f107"; } -.bi-align-top::before { content: "\f108"; } -.bi-alt::before { content: "\f109"; } -.bi-app-indicator::before { content: "\f10a"; } -.bi-app::before { content: "\f10b"; } -.bi-archive-fill::before { content: "\f10c"; } -.bi-archive::before { content: "\f10d"; } -.bi-arrow-90deg-down::before { content: "\f10e"; } -.bi-arrow-90deg-left::before { content: "\f10f"; } -.bi-arrow-90deg-right::before { content: "\f110"; } -.bi-arrow-90deg-up::before { content: "\f111"; } -.bi-arrow-bar-down::before { content: "\f112"; } -.bi-arrow-bar-left::before { content: "\f113"; } -.bi-arrow-bar-right::before { content: "\f114"; } -.bi-arrow-bar-up::before { content: "\f115"; } -.bi-arrow-clockwise::before { content: "\f116"; } -.bi-arrow-counterclockwise::before { content: "\f117"; } -.bi-arrow-down-circle-fill::before { content: "\f118"; } -.bi-arrow-down-circle::before { content: "\f119"; } -.bi-arrow-down-left-circle-fill::before { content: "\f11a"; } -.bi-arrow-down-left-circle::before { content: "\f11b"; } -.bi-arrow-down-left-square-fill::before { content: "\f11c"; } -.bi-arrow-down-left-square::before { content: "\f11d"; } -.bi-arrow-down-left::before { content: "\f11e"; } -.bi-arrow-down-right-circle-fill::before { content: "\f11f"; } -.bi-arrow-down-right-circle::before { content: "\f120"; } -.bi-arrow-down-right-square-fill::before { content: "\f121"; } -.bi-arrow-down-right-square::before { content: "\f122"; } -.bi-arrow-down-right::before { content: "\f123"; } -.bi-arrow-down-short::before { content: "\f124"; } -.bi-arrow-down-square-fill::before { content: "\f125"; } -.bi-arrow-down-square::before { content: "\f126"; } -.bi-arrow-down-up::before { content: "\f127"; } -.bi-arrow-down::before { content: "\f128"; } -.bi-arrow-left-circle-fill::before { content: "\f129"; } -.bi-arrow-left-circle::before { content: "\f12a"; } -.bi-arrow-left-right::before { content: "\f12b"; } -.bi-arrow-left-short::before { content: "\f12c"; } -.bi-arrow-left-square-fill::before { content: "\f12d"; } -.bi-arrow-left-square::before { content: "\f12e"; } -.bi-arrow-left::before { content: "\f12f"; } -.bi-arrow-repeat::before { content: "\f130"; } -.bi-arrow-return-left::before { content: "\f131"; } -.bi-arrow-return-right::before { content: "\f132"; } -.bi-arrow-right-circle-fill::before { content: "\f133"; } -.bi-arrow-right-circle::before { content: "\f134"; } -.bi-arrow-right-short::before { content: "\f135"; } -.bi-arrow-right-square-fill::before { content: "\f136"; } -.bi-arrow-right-square::before { content: "\f137"; } -.bi-arrow-right::before { content: "\f138"; } -.bi-arrow-up-circle-fill::before { content: "\f139"; } -.bi-arrow-up-circle::before { content: "\f13a"; } -.bi-arrow-up-left-circle-fill::before { content: "\f13b"; } -.bi-arrow-up-left-circle::before { content: "\f13c"; } -.bi-arrow-up-left-square-fill::before { content: "\f13d"; } -.bi-arrow-up-left-square::before { content: "\f13e"; } -.bi-arrow-up-left::before { content: "\f13f"; } -.bi-arrow-up-right-circle-fill::before { content: "\f140"; } -.bi-arrow-up-right-circle::before { content: "\f141"; } -.bi-arrow-up-right-square-fill::before { content: "\f142"; } -.bi-arrow-up-right-square::before { content: "\f143"; } -.bi-arrow-up-right::before { content: "\f144"; } -.bi-arrow-up-short::before { content: "\f145"; } -.bi-arrow-up-square-fill::before { content: "\f146"; } -.bi-arrow-up-square::before { content: "\f147"; } -.bi-arrow-up::before { content: "\f148"; } -.bi-arrows-angle-contract::before { content: "\f149"; } -.bi-arrows-angle-expand::before { content: "\f14a"; } -.bi-arrows-collapse::before { content: "\f14b"; } -.bi-arrows-expand::before { content: "\f14c"; } -.bi-arrows-fullscreen::before { content: "\f14d"; } -.bi-arrows-move::before { content: "\f14e"; } -.bi-aspect-ratio-fill::before { content: "\f14f"; } -.bi-aspect-ratio::before { content: "\f150"; } -.bi-asterisk::before { content: "\f151"; } -.bi-at::before { content: "\f152"; } -.bi-award-fill::before { content: "\f153"; } -.bi-award::before { content: "\f154"; } -.bi-back::before { content: "\f155"; } -.bi-backspace-fill::before { content: "\f156"; } -.bi-backspace-reverse-fill::before { content: "\f157"; } -.bi-backspace-reverse::before { content: "\f158"; } -.bi-backspace::before { content: "\f159"; } -.bi-badge-3d-fill::before { content: "\f15a"; } -.bi-badge-3d::before { content: "\f15b"; } -.bi-badge-4k-fill::before { content: "\f15c"; } -.bi-badge-4k::before { content: "\f15d"; } -.bi-badge-8k-fill::before { content: "\f15e"; } -.bi-badge-8k::before { content: "\f15f"; } -.bi-badge-ad-fill::before { content: "\f160"; } -.bi-badge-ad::before { content: "\f161"; } -.bi-badge-ar-fill::before { content: "\f162"; } -.bi-badge-ar::before { content: "\f163"; } -.bi-badge-cc-fill::before { content: "\f164"; } -.bi-badge-cc::before { content: "\f165"; } -.bi-badge-hd-fill::before { content: "\f166"; } -.bi-badge-hd::before { content: "\f167"; } -.bi-badge-tm-fill::before { content: "\f168"; } -.bi-badge-tm::before { content: "\f169"; } -.bi-badge-vo-fill::before { content: "\f16a"; } -.bi-badge-vo::before { content: "\f16b"; } -.bi-badge-vr-fill::before { content: "\f16c"; } -.bi-badge-vr::before { content: "\f16d"; } -.bi-badge-wc-fill::before { content: "\f16e"; } -.bi-badge-wc::before { content: "\f16f"; } -.bi-bag-check-fill::before { content: "\f170"; } -.bi-bag-check::before { content: "\f171"; } -.bi-bag-dash-fill::before { content: "\f172"; } -.bi-bag-dash::before { content: "\f173"; } -.bi-bag-fill::before { content: "\f174"; } -.bi-bag-plus-fill::before { content: "\f175"; } -.bi-bag-plus::before { content: "\f176"; } -.bi-bag-x-fill::before { content: "\f177"; } -.bi-bag-x::before { content: "\f178"; } -.bi-bag::before { content: "\f179"; } -.bi-bar-chart-fill::before { content: "\f17a"; } -.bi-bar-chart-line-fill::before { content: "\f17b"; } -.bi-bar-chart-line::before { content: "\f17c"; } -.bi-bar-chart-steps::before { content: "\f17d"; } -.bi-bar-chart::before { content: "\f17e"; } -.bi-basket-fill::before { content: "\f17f"; } -.bi-basket::before { content: "\f180"; } -.bi-basket2-fill::before { content: "\f181"; } -.bi-basket2::before { content: "\f182"; } -.bi-basket3-fill::before { content: "\f183"; } -.bi-basket3::before { content: "\f184"; } -.bi-battery-charging::before { content: "\f185"; } -.bi-battery-full::before { content: "\f186"; } -.bi-battery-half::before { content: "\f187"; } -.bi-battery::before { content: "\f188"; } -.bi-bell-fill::before { content: "\f189"; } -.bi-bell::before { content: "\f18a"; } -.bi-bezier::before { content: "\f18b"; } -.bi-bezier2::before { content: "\f18c"; } -.bi-bicycle::before { content: "\f18d"; } -.bi-binoculars-fill::before { content: "\f18e"; } -.bi-binoculars::before { content: "\f18f"; } -.bi-blockquote-left::before { content: "\f190"; } -.bi-blockquote-right::before { content: "\f191"; } -.bi-book-fill::before { content: "\f192"; } -.bi-book-half::before { content: "\f193"; } -.bi-book::before { content: "\f194"; } -.bi-bookmark-check-fill::before { content: "\f195"; } -.bi-bookmark-check::before { content: "\f196"; } -.bi-bookmark-dash-fill::before { content: "\f197"; } -.bi-bookmark-dash::before { content: "\f198"; } -.bi-bookmark-fill::before { content: "\f199"; } -.bi-bookmark-heart-fill::before { content: "\f19a"; } -.bi-bookmark-heart::before { content: "\f19b"; } -.bi-bookmark-plus-fill::before { content: "\f19c"; } -.bi-bookmark-plus::before { content: "\f19d"; } -.bi-bookmark-star-fill::before { content: "\f19e"; } -.bi-bookmark-star::before { content: "\f19f"; } -.bi-bookmark-x-fill::before { content: "\f1a0"; } -.bi-bookmark-x::before { content: "\f1a1"; } -.bi-bookmark::before { content: "\f1a2"; } -.bi-bookmarks-fill::before { content: "\f1a3"; } -.bi-bookmarks::before { content: "\f1a4"; } -.bi-bookshelf::before { content: "\f1a5"; } -.bi-bootstrap-fill::before { content: "\f1a6"; } -.bi-bootstrap-reboot::before { content: "\f1a7"; } -.bi-bootstrap::before { content: "\f1a8"; } -.bi-border-all::before { content: "\f1a9"; } -.bi-border-bottom::before { content: "\f1aa"; } -.bi-border-center::before { content: "\f1ab"; } -.bi-border-inner::before { content: "\f1ac"; } -.bi-border-left::before { content: "\f1ad"; } -.bi-border-middle::before { content: "\f1ae"; } -.bi-border-outer::before { content: "\f1af"; } -.bi-border-right::before { content: "\f1b0"; } -.bi-border-style::before { content: "\f1b1"; } -.bi-border-top::before { content: "\f1b2"; } -.bi-border-width::before { content: "\f1b3"; } -.bi-border::before { content: "\f1b4"; } -.bi-bounding-box-circles::before { content: "\f1b5"; } -.bi-bounding-box::before { content: "\f1b6"; } -.bi-box-arrow-down-left::before { content: "\f1b7"; } -.bi-box-arrow-down-right::before { content: "\f1b8"; } -.bi-box-arrow-down::before { content: "\f1b9"; } -.bi-box-arrow-in-down-left::before { content: "\f1ba"; } -.bi-box-arrow-in-down-right::before { content: "\f1bb"; } -.bi-box-arrow-in-down::before { content: "\f1bc"; } -.bi-box-arrow-in-left::before { content: "\f1bd"; } -.bi-box-arrow-in-right::before { content: "\f1be"; } -.bi-box-arrow-in-up-left::before { content: "\f1bf"; } -.bi-box-arrow-in-up-right::before { content: "\f1c0"; } -.bi-box-arrow-in-up::before { content: "\f1c1"; } -.bi-box-arrow-left::before { content: "\f1c2"; } -.bi-box-arrow-right::before { content: "\f1c3"; } -.bi-box-arrow-up-left::before { content: "\f1c4"; } -.bi-box-arrow-up-right::before { content: "\f1c5"; } -.bi-box-arrow-up::before { content: "\f1c6"; } -.bi-box-seam::before { content: "\f1c7"; } -.bi-box::before { content: "\f1c8"; } -.bi-braces::before { content: "\f1c9"; } -.bi-bricks::before { content: "\f1ca"; } -.bi-briefcase-fill::before { content: "\f1cb"; } -.bi-briefcase::before { content: "\f1cc"; } -.bi-brightness-alt-high-fill::before { content: "\f1cd"; } -.bi-brightness-alt-high::before { content: "\f1ce"; } -.bi-brightness-alt-low-fill::before { content: "\f1cf"; } -.bi-brightness-alt-low::before { content: "\f1d0"; } -.bi-brightness-high-fill::before { content: "\f1d1"; } -.bi-brightness-high::before { content: "\f1d2"; } -.bi-brightness-low-fill::before { content: "\f1d3"; } -.bi-brightness-low::before { content: "\f1d4"; } -.bi-broadcast-pin::before { content: "\f1d5"; } -.bi-broadcast::before { content: "\f1d6"; } -.bi-brush-fill::before { content: "\f1d7"; } -.bi-brush::before { content: "\f1d8"; } -.bi-bucket-fill::before { content: "\f1d9"; } -.bi-bucket::before { content: "\f1da"; } -.bi-bug-fill::before { content: "\f1db"; } -.bi-bug::before { content: "\f1dc"; } -.bi-building::before { content: "\f1dd"; } -.bi-bullseye::before { content: "\f1de"; } -.bi-calculator-fill::before { content: "\f1df"; } -.bi-calculator::before { content: "\f1e0"; } -.bi-calendar-check-fill::before { content: "\f1e1"; } -.bi-calendar-check::before { content: "\f1e2"; } -.bi-calendar-date-fill::before { content: "\f1e3"; } -.bi-calendar-date::before { content: "\f1e4"; } -.bi-calendar-day-fill::before { content: "\f1e5"; } -.bi-calendar-day::before { content: "\f1e6"; } -.bi-calendar-event-fill::before { content: "\f1e7"; } -.bi-calendar-event::before { content: "\f1e8"; } -.bi-calendar-fill::before { content: "\f1e9"; } -.bi-calendar-minus-fill::before { content: "\f1ea"; } -.bi-calendar-minus::before { content: "\f1eb"; } -.bi-calendar-month-fill::before { content: "\f1ec"; } -.bi-calendar-month::before { content: "\f1ed"; } -.bi-calendar-plus-fill::before { content: "\f1ee"; } -.bi-calendar-plus::before { content: "\f1ef"; } -.bi-calendar-range-fill::before { content: "\f1f0"; } -.bi-calendar-range::before { content: "\f1f1"; } -.bi-calendar-week-fill::before { content: "\f1f2"; } -.bi-calendar-week::before { content: "\f1f3"; } -.bi-calendar-x-fill::before { content: "\f1f4"; } -.bi-calendar-x::before { content: "\f1f5"; } -.bi-calendar::before { content: "\f1f6"; } -.bi-calendar2-check-fill::before { content: "\f1f7"; } -.bi-calendar2-check::before { content: "\f1f8"; } -.bi-calendar2-date-fill::before { content: "\f1f9"; } -.bi-calendar2-date::before { content: "\f1fa"; } -.bi-calendar2-day-fill::before { content: "\f1fb"; } -.bi-calendar2-day::before { content: "\f1fc"; } -.bi-calendar2-event-fill::before { content: "\f1fd"; } -.bi-calendar2-event::before { content: "\f1fe"; } -.bi-calendar2-fill::before { content: "\f1ff"; } -.bi-calendar2-minus-fill::before { content: "\f200"; } -.bi-calendar2-minus::before { content: "\f201"; } -.bi-calendar2-month-fill::before { content: "\f202"; } -.bi-calendar2-month::before { content: "\f203"; } -.bi-calendar2-plus-fill::before { content: "\f204"; } -.bi-calendar2-plus::before { content: "\f205"; } -.bi-calendar2-range-fill::before { content: "\f206"; } -.bi-calendar2-range::before { content: "\f207"; } -.bi-calendar2-week-fill::before { content: "\f208"; } -.bi-calendar2-week::before { content: "\f209"; } -.bi-calendar2-x-fill::before { content: "\f20a"; } -.bi-calendar2-x::before { content: "\f20b"; } -.bi-calendar2::before { content: "\f20c"; } -.bi-calendar3-event-fill::before { content: "\f20d"; } -.bi-calendar3-event::before { content: "\f20e"; } -.bi-calendar3-fill::before { content: "\f20f"; } -.bi-calendar3-range-fill::before { content: "\f210"; } -.bi-calendar3-range::before { content: "\f211"; } -.bi-calendar3-week-fill::before { content: "\f212"; } -.bi-calendar3-week::before { content: "\f213"; } -.bi-calendar3::before { content: "\f214"; } -.bi-calendar4-event::before { content: "\f215"; } -.bi-calendar4-range::before { content: "\f216"; } -.bi-calendar4-week::before { content: "\f217"; } -.bi-calendar4::before { content: "\f218"; } -.bi-camera-fill::before { content: "\f219"; } -.bi-camera-reels-fill::before { content: "\f21a"; } -.bi-camera-reels::before { content: "\f21b"; } -.bi-camera-video-fill::before { content: "\f21c"; } -.bi-camera-video-off-fill::before { content: "\f21d"; } -.bi-camera-video-off::before { content: "\f21e"; } -.bi-camera-video::before { content: "\f21f"; } -.bi-camera::before { content: "\f220"; } -.bi-camera2::before { content: "\f221"; } -.bi-capslock-fill::before { content: "\f222"; } -.bi-capslock::before { content: "\f223"; } -.bi-card-checklist::before { content: "\f224"; } -.bi-card-heading::before { content: "\f225"; } -.bi-card-image::before { content: "\f226"; } -.bi-card-list::before { content: "\f227"; } -.bi-card-text::before { content: "\f228"; } -.bi-caret-down-fill::before { content: "\f229"; } -.bi-caret-down-square-fill::before { content: "\f22a"; } -.bi-caret-down-square::before { content: "\f22b"; } -.bi-caret-down::before { content: "\f22c"; } -.bi-caret-left-fill::before { content: "\f22d"; } -.bi-caret-left-square-fill::before { content: "\f22e"; } -.bi-caret-left-square::before { content: "\f22f"; } -.bi-caret-left::before { content: "\f230"; } -.bi-caret-right-fill::before { content: "\f231"; } -.bi-caret-right-square-fill::before { content: "\f232"; } -.bi-caret-right-square::before { content: "\f233"; } -.bi-caret-right::before { content: "\f234"; } -.bi-caret-up-fill::before { content: "\f235"; } -.bi-caret-up-square-fill::before { content: "\f236"; } -.bi-caret-up-square::before { content: "\f237"; } -.bi-caret-up::before { content: "\f238"; } -.bi-cart-check-fill::before { content: "\f239"; } -.bi-cart-check::before { content: "\f23a"; } -.bi-cart-dash-fill::before { content: "\f23b"; } -.bi-cart-dash::before { content: "\f23c"; } -.bi-cart-fill::before { content: "\f23d"; } -.bi-cart-plus-fill::before { content: "\f23e"; } -.bi-cart-plus::before { content: "\f23f"; } -.bi-cart-x-fill::before { content: "\f240"; } -.bi-cart-x::before { content: "\f241"; } -.bi-cart::before { content: "\f242"; } -.bi-cart2::before { content: "\f243"; } -.bi-cart3::before { content: "\f244"; } -.bi-cart4::before { content: "\f245"; } -.bi-cash-stack::before { content: "\f246"; } -.bi-cash::before { content: "\f247"; } -.bi-cast::before { content: "\f248"; } -.bi-chat-dots-fill::before { content: "\f249"; } -.bi-chat-dots::before { content: "\f24a"; } -.bi-chat-fill::before { content: "\f24b"; } -.bi-chat-left-dots-fill::before { content: "\f24c"; } -.bi-chat-left-dots::before { content: "\f24d"; } -.bi-chat-left-fill::before { content: "\f24e"; } -.bi-chat-left-quote-fill::before { content: "\f24f"; } -.bi-chat-left-quote::before { content: "\f250"; } -.bi-chat-left-text-fill::before { content: "\f251"; } -.bi-chat-left-text::before { content: "\f252"; } -.bi-chat-left::before { content: "\f253"; } -.bi-chat-quote-fill::before { content: "\f254"; } -.bi-chat-quote::before { content: "\f255"; } -.bi-chat-right-dots-fill::before { content: "\f256"; } -.bi-chat-right-dots::before { content: "\f257"; } -.bi-chat-right-fill::before { content: "\f258"; } -.bi-chat-right-quote-fill::before { content: "\f259"; } -.bi-chat-right-quote::before { content: "\f25a"; } -.bi-chat-right-text-fill::before { content: "\f25b"; } -.bi-chat-right-text::before { content: "\f25c"; } -.bi-chat-right::before { content: "\f25d"; } -.bi-chat-square-dots-fill::before { content: "\f25e"; } -.bi-chat-square-dots::before { content: "\f25f"; } -.bi-chat-square-fill::before { content: "\f260"; } -.bi-chat-square-quote-fill::before { content: "\f261"; } -.bi-chat-square-quote::before { content: "\f262"; } -.bi-chat-square-text-fill::before { content: "\f263"; } -.bi-chat-square-text::before { content: "\f264"; } -.bi-chat-square::before { content: "\f265"; } -.bi-chat-text-fill::before { content: "\f266"; } -.bi-chat-text::before { content: "\f267"; } -.bi-chat::before { content: "\f268"; } -.bi-check-all::before { content: "\f269"; } -.bi-check-circle-fill::before { content: "\f26a"; } -.bi-check-circle::before { content: "\f26b"; } -.bi-check-square-fill::before { content: "\f26c"; } -.bi-check-square::before { content: "\f26d"; } -.bi-check::before { content: "\f26e"; } -.bi-check2-all::before { content: "\f26f"; } -.bi-check2-circle::before { content: "\f270"; } -.bi-check2-square::before { content: "\f271"; } -.bi-check2::before { content: "\f272"; } -.bi-chevron-bar-contract::before { content: "\f273"; } -.bi-chevron-bar-down::before { content: "\f274"; } -.bi-chevron-bar-expand::before { content: "\f275"; } -.bi-chevron-bar-left::before { content: "\f276"; } -.bi-chevron-bar-right::before { content: "\f277"; } -.bi-chevron-bar-up::before { content: "\f278"; } -.bi-chevron-compact-down::before { content: "\f279"; } -.bi-chevron-compact-left::before { content: "\f27a"; } -.bi-chevron-compact-right::before { content: "\f27b"; } -.bi-chevron-compact-up::before { content: "\f27c"; } -.bi-chevron-contract::before { content: "\f27d"; } -.bi-chevron-double-down::before { content: "\f27e"; } -.bi-chevron-double-left::before { content: "\f27f"; } -.bi-chevron-double-right::before { content: "\f280"; } -.bi-chevron-double-up::before { content: "\f281"; } -.bi-chevron-down::before { content: "\f282"; } -.bi-chevron-expand::before { content: "\f283"; } -.bi-chevron-left::before { content: "\f284"; } -.bi-chevron-right::before { content: "\f285"; } -.bi-chevron-up::before { content: "\f286"; } -.bi-circle-fill::before { content: "\f287"; } -.bi-circle-half::before { content: "\f288"; } -.bi-circle-square::before { content: "\f289"; } -.bi-circle::before { content: "\f28a"; } -.bi-clipboard-check::before { content: "\f28b"; } -.bi-clipboard-data::before { content: "\f28c"; } -.bi-clipboard-minus::before { content: "\f28d"; } -.bi-clipboard-plus::before { content: "\f28e"; } -.bi-clipboard-x::before { content: "\f28f"; } -.bi-clipboard::before { content: "\f290"; } -.bi-clock-fill::before { content: "\f291"; } -.bi-clock-history::before { content: "\f292"; } -.bi-clock::before { content: "\f293"; } -.bi-cloud-arrow-down-fill::before { content: "\f294"; } -.bi-cloud-arrow-down::before { content: "\f295"; } -.bi-cloud-arrow-up-fill::before { content: "\f296"; } -.bi-cloud-arrow-up::before { content: "\f297"; } -.bi-cloud-check-fill::before { content: "\f298"; } -.bi-cloud-check::before { content: "\f299"; } -.bi-cloud-download-fill::before { content: "\f29a"; } -.bi-cloud-download::before { content: "\f29b"; } -.bi-cloud-drizzle-fill::before { content: "\f29c"; } -.bi-cloud-drizzle::before { content: "\f29d"; } -.bi-cloud-fill::before { content: "\f29e"; } -.bi-cloud-fog-fill::before { content: "\f29f"; } -.bi-cloud-fog::before { content: "\f2a0"; } -.bi-cloud-fog2-fill::before { content: "\f2a1"; } -.bi-cloud-fog2::before { content: "\f2a2"; } -.bi-cloud-hail-fill::before { content: "\f2a3"; } -.bi-cloud-hail::before { content: "\f2a4"; } -.bi-cloud-haze-fill::before { content: "\f2a6"; } -.bi-cloud-haze::before { content: "\f2a7"; } -.bi-cloud-haze2-fill::before { content: "\f2a8"; } -.bi-cloud-lightning-fill::before { content: "\f2a9"; } -.bi-cloud-lightning-rain-fill::before { content: "\f2aa"; } -.bi-cloud-lightning-rain::before { content: "\f2ab"; } -.bi-cloud-lightning::before { content: "\f2ac"; } -.bi-cloud-minus-fill::before { content: "\f2ad"; } -.bi-cloud-minus::before { content: "\f2ae"; } -.bi-cloud-moon-fill::before { content: "\f2af"; } -.bi-cloud-moon::before { content: "\f2b0"; } -.bi-cloud-plus-fill::before { content: "\f2b1"; } -.bi-cloud-plus::before { content: "\f2b2"; } -.bi-cloud-rain-fill::before { content: "\f2b3"; } -.bi-cloud-rain-heavy-fill::before { content: "\f2b4"; } -.bi-cloud-rain-heavy::before { content: "\f2b5"; } -.bi-cloud-rain::before { content: "\f2b6"; } -.bi-cloud-slash-fill::before { content: "\f2b7"; } -.bi-cloud-slash::before { content: "\f2b8"; } -.bi-cloud-sleet-fill::before { content: "\f2b9"; } -.bi-cloud-sleet::before { content: "\f2ba"; } -.bi-cloud-snow-fill::before { content: "\f2bb"; } -.bi-cloud-snow::before { content: "\f2bc"; } -.bi-cloud-sun-fill::before { content: "\f2bd"; } -.bi-cloud-sun::before { content: "\f2be"; } -.bi-cloud-upload-fill::before { content: "\f2bf"; } -.bi-cloud-upload::before { content: "\f2c0"; } -.bi-cloud::before { content: "\f2c1"; } -.bi-clouds-fill::before { content: "\f2c2"; } -.bi-clouds::before { content: "\f2c3"; } -.bi-cloudy-fill::before { content: "\f2c4"; } -.bi-cloudy::before { content: "\f2c5"; } -.bi-code-slash::before { content: "\f2c6"; } -.bi-code-square::before { content: "\f2c7"; } -.bi-code::before { content: "\f2c8"; } -.bi-collection-fill::before { content: "\f2c9"; } -.bi-collection-play-fill::before { content: "\f2ca"; } -.bi-collection-play::before { content: "\f2cb"; } -.bi-collection::before { content: "\f2cc"; } -.bi-columns-gap::before { content: "\f2cd"; } -.bi-columns::before { content: "\f2ce"; } -.bi-command::before { content: "\f2cf"; } -.bi-compass-fill::before { content: "\f2d0"; } -.bi-compass::before { content: "\f2d1"; } -.bi-cone-striped::before { content: "\f2d2"; } -.bi-cone::before { content: "\f2d3"; } -.bi-controller::before { content: "\f2d4"; } -.bi-cpu-fill::before { content: "\f2d5"; } -.bi-cpu::before { content: "\f2d6"; } -.bi-credit-card-2-back-fill::before { content: "\f2d7"; } -.bi-credit-card-2-back::before { content: "\f2d8"; } -.bi-credit-card-2-front-fill::before { content: "\f2d9"; } -.bi-credit-card-2-front::before { content: "\f2da"; } -.bi-credit-card-fill::before { content: "\f2db"; } -.bi-credit-card::before { content: "\f2dc"; } -.bi-crop::before { content: "\f2dd"; } -.bi-cup-fill::before { content: "\f2de"; } -.bi-cup-straw::before { content: "\f2df"; } -.bi-cup::before { content: "\f2e0"; } -.bi-cursor-fill::before { content: "\f2e1"; } -.bi-cursor-text::before { content: "\f2e2"; } -.bi-cursor::before { content: "\f2e3"; } -.bi-dash-circle-dotted::before { content: "\f2e4"; } -.bi-dash-circle-fill::before { content: "\f2e5"; } -.bi-dash-circle::before { content: "\f2e6"; } -.bi-dash-square-dotted::before { content: "\f2e7"; } -.bi-dash-square-fill::before { content: "\f2e8"; } -.bi-dash-square::before { content: "\f2e9"; } -.bi-dash::before { content: "\f2ea"; } -.bi-diagram-2-fill::before { content: "\f2eb"; } -.bi-diagram-2::before { content: "\f2ec"; } -.bi-diagram-3-fill::before { content: "\f2ed"; } -.bi-diagram-3::before { content: "\f2ee"; } -.bi-diamond-fill::before { content: "\f2ef"; } -.bi-diamond-half::before { content: "\f2f0"; } -.bi-diamond::before { content: "\f2f1"; } -.bi-dice-1-fill::before { content: "\f2f2"; } -.bi-dice-1::before { content: "\f2f3"; } -.bi-dice-2-fill::before { content: "\f2f4"; } -.bi-dice-2::before { content: "\f2f5"; } -.bi-dice-3-fill::before { content: "\f2f6"; } -.bi-dice-3::before { content: "\f2f7"; } -.bi-dice-4-fill::before { content: "\f2f8"; } -.bi-dice-4::before { content: "\f2f9"; } -.bi-dice-5-fill::before { content: "\f2fa"; } -.bi-dice-5::before { content: "\f2fb"; } -.bi-dice-6-fill::before { content: "\f2fc"; } -.bi-dice-6::before { content: "\f2fd"; } -.bi-disc-fill::before { content: "\f2fe"; } -.bi-disc::before { content: "\f2ff"; } -.bi-discord::before { content: "\f300"; } -.bi-display-fill::before { content: "\f301"; } -.bi-display::before { content: "\f302"; } -.bi-distribute-horizontal::before { content: "\f303"; } -.bi-distribute-vertical::before { content: "\f304"; } -.bi-door-closed-fill::before { content: "\f305"; } -.bi-door-closed::before { content: "\f306"; } -.bi-door-open-fill::before { content: "\f307"; } -.bi-door-open::before { content: "\f308"; } -.bi-dot::before { content: "\f309"; } -.bi-download::before { content: "\f30a"; } -.bi-droplet-fill::before { content: "\f30b"; } -.bi-droplet-half::before { content: "\f30c"; } -.bi-droplet::before { content: "\f30d"; } -.bi-earbuds::before { content: "\f30e"; } -.bi-easel-fill::before { content: "\f30f"; } -.bi-easel::before { content: "\f310"; } -.bi-egg-fill::before { content: "\f311"; } -.bi-egg-fried::before { content: "\f312"; } -.bi-egg::before { content: "\f313"; } -.bi-eject-fill::before { content: "\f314"; } -.bi-eject::before { content: "\f315"; } -.bi-emoji-angry-fill::before { content: "\f316"; } -.bi-emoji-angry::before { content: "\f317"; } -.bi-emoji-dizzy-fill::before { content: "\f318"; } -.bi-emoji-dizzy::before { content: "\f319"; } -.bi-emoji-expressionless-fill::before { content: "\f31a"; } -.bi-emoji-expressionless::before { content: "\f31b"; } -.bi-emoji-frown-fill::before { content: "\f31c"; } -.bi-emoji-frown::before { content: "\f31d"; } -.bi-emoji-heart-eyes-fill::before { content: "\f31e"; } -.bi-emoji-heart-eyes::before { content: "\f31f"; } -.bi-emoji-laughing-fill::before { content: "\f320"; } -.bi-emoji-laughing::before { content: "\f321"; } -.bi-emoji-neutral-fill::before { content: "\f322"; } -.bi-emoji-neutral::before { content: "\f323"; } -.bi-emoji-smile-fill::before { content: "\f324"; } -.bi-emoji-smile-upside-down-fill::before { content: "\f325"; } -.bi-emoji-smile-upside-down::before { content: "\f326"; } -.bi-emoji-smile::before { content: "\f327"; } -.bi-emoji-sunglasses-fill::before { content: "\f328"; } -.bi-emoji-sunglasses::before { content: "\f329"; } -.bi-emoji-wink-fill::before { content: "\f32a"; } -.bi-emoji-wink::before { content: "\f32b"; } -.bi-envelope-fill::before { content: "\f32c"; } -.bi-envelope-open-fill::before { content: "\f32d"; } -.bi-envelope-open::before { content: "\f32e"; } -.bi-envelope::before { content: "\f32f"; } -.bi-eraser-fill::before { content: "\f330"; } -.bi-eraser::before { content: "\f331"; } -.bi-exclamation-circle-fill::before { content: "\f332"; } -.bi-exclamation-circle::before { content: "\f333"; } -.bi-exclamation-diamond-fill::before { content: "\f334"; } -.bi-exclamation-diamond::before { content: "\f335"; } -.bi-exclamation-octagon-fill::before { content: "\f336"; } -.bi-exclamation-octagon::before { content: "\f337"; } -.bi-exclamation-square-fill::before { content: "\f338"; } -.bi-exclamation-square::before { content: "\f339"; } -.bi-exclamation-triangle-fill::before { content: "\f33a"; } -.bi-exclamation-triangle::before { content: "\f33b"; } -.bi-exclamation::before { content: "\f33c"; } -.bi-exclude::before { content: "\f33d"; } -.bi-eye-fill::before { content: "\f33e"; } -.bi-eye-slash-fill::before { content: "\f33f"; } -.bi-eye-slash::before { content: "\f340"; } -.bi-eye::before { content: "\f341"; } -.bi-eyedropper::before { content: "\f342"; } -.bi-eyeglasses::before { content: "\f343"; } -.bi-facebook::before { content: "\f344"; } -.bi-file-arrow-down-fill::before { content: "\f345"; } -.bi-file-arrow-down::before { content: "\f346"; } -.bi-file-arrow-up-fill::before { content: "\f347"; } -.bi-file-arrow-up::before { content: "\f348"; } -.bi-file-bar-graph-fill::before { content: "\f349"; } -.bi-file-bar-graph::before { content: "\f34a"; } -.bi-file-binary-fill::before { content: "\f34b"; } -.bi-file-binary::before { content: "\f34c"; } -.bi-file-break-fill::before { content: "\f34d"; } -.bi-file-break::before { content: "\f34e"; } -.bi-file-check-fill::before { content: "\f34f"; } -.bi-file-check::before { content: "\f350"; } -.bi-file-code-fill::before { content: "\f351"; } -.bi-file-code::before { content: "\f352"; } -.bi-file-diff-fill::before { content: "\f353"; } -.bi-file-diff::before { content: "\f354"; } -.bi-file-earmark-arrow-down-fill::before { content: "\f355"; } -.bi-file-earmark-arrow-down::before { content: "\f356"; } -.bi-file-earmark-arrow-up-fill::before { content: "\f357"; } -.bi-file-earmark-arrow-up::before { content: "\f358"; } -.bi-file-earmark-bar-graph-fill::before { content: "\f359"; } -.bi-file-earmark-bar-graph::before { content: "\f35a"; } -.bi-file-earmark-binary-fill::before { content: "\f35b"; } -.bi-file-earmark-binary::before { content: "\f35c"; } -.bi-file-earmark-break-fill::before { content: "\f35d"; } -.bi-file-earmark-break::before { content: "\f35e"; } -.bi-file-earmark-check-fill::before { content: "\f35f"; } -.bi-file-earmark-check::before { content: "\f360"; } -.bi-file-earmark-code-fill::before { content: "\f361"; } -.bi-file-earmark-code::before { content: "\f362"; } -.bi-file-earmark-diff-fill::before { content: "\f363"; } -.bi-file-earmark-diff::before { content: "\f364"; } -.bi-file-earmark-easel-fill::before { content: "\f365"; } -.bi-file-earmark-easel::before { content: "\f366"; } -.bi-file-earmark-excel-fill::before { content: "\f367"; } -.bi-file-earmark-excel::before { content: "\f368"; } -.bi-file-earmark-fill::before { content: "\f369"; } -.bi-file-earmark-font-fill::before { content: "\f36a"; } -.bi-file-earmark-font::before { content: "\f36b"; } -.bi-file-earmark-image-fill::before { content: "\f36c"; } -.bi-file-earmark-image::before { content: "\f36d"; } -.bi-file-earmark-lock-fill::before { content: "\f36e"; } -.bi-file-earmark-lock::before { content: "\f36f"; } -.bi-file-earmark-lock2-fill::before { content: "\f370"; } -.bi-file-earmark-lock2::before { content: "\f371"; } -.bi-file-earmark-medical-fill::before { content: "\f372"; } -.bi-file-earmark-medical::before { content: "\f373"; } -.bi-file-earmark-minus-fill::before { content: "\f374"; } -.bi-file-earmark-minus::before { content: "\f375"; } -.bi-file-earmark-music-fill::before { content: "\f376"; } -.bi-file-earmark-music::before { content: "\f377"; } -.bi-file-earmark-person-fill::before { content: "\f378"; } -.bi-file-earmark-person::before { content: "\f379"; } -.bi-file-earmark-play-fill::before { content: "\f37a"; } -.bi-file-earmark-play::before { content: "\f37b"; } -.bi-file-earmark-plus-fill::before { content: "\f37c"; } -.bi-file-earmark-plus::before { content: "\f37d"; } -.bi-file-earmark-post-fill::before { content: "\f37e"; } -.bi-file-earmark-post::before { content: "\f37f"; } -.bi-file-earmark-ppt-fill::before { content: "\f380"; } -.bi-file-earmark-ppt::before { content: "\f381"; } -.bi-file-earmark-richtext-fill::before { content: "\f382"; } -.bi-file-earmark-richtext::before { content: "\f383"; } -.bi-file-earmark-ruled-fill::before { content: "\f384"; } -.bi-file-earmark-ruled::before { content: "\f385"; } -.bi-file-earmark-slides-fill::before { content: "\f386"; } -.bi-file-earmark-slides::before { content: "\f387"; } -.bi-file-earmark-spreadsheet-fill::before { content: "\f388"; } -.bi-file-earmark-spreadsheet::before { content: "\f389"; } -.bi-file-earmark-text-fill::before { content: "\f38a"; } -.bi-file-earmark-text::before { content: "\f38b"; } -.bi-file-earmark-word-fill::before { content: "\f38c"; } -.bi-file-earmark-word::before { content: "\f38d"; } -.bi-file-earmark-x-fill::before { content: "\f38e"; } -.bi-file-earmark-x::before { content: "\f38f"; } -.bi-file-earmark-zip-fill::before { content: "\f390"; } -.bi-file-earmark-zip::before { content: "\f391"; } -.bi-file-earmark::before { content: "\f392"; } -.bi-file-easel-fill::before { content: "\f393"; } -.bi-file-easel::before { content: "\f394"; } -.bi-file-excel-fill::before { content: "\f395"; } -.bi-file-excel::before { content: "\f396"; } -.bi-file-fill::before { content: "\f397"; } -.bi-file-font-fill::before { content: "\f398"; } -.bi-file-font::before { content: "\f399"; } -.bi-file-image-fill::before { content: "\f39a"; } -.bi-file-image::before { content: "\f39b"; } -.bi-file-lock-fill::before { content: "\f39c"; } -.bi-file-lock::before { content: "\f39d"; } -.bi-file-lock2-fill::before { content: "\f39e"; } -.bi-file-lock2::before { content: "\f39f"; } -.bi-file-medical-fill::before { content: "\f3a0"; } -.bi-file-medical::before { content: "\f3a1"; } -.bi-file-minus-fill::before { content: "\f3a2"; } -.bi-file-minus::before { content: "\f3a3"; } -.bi-file-music-fill::before { content: "\f3a4"; } -.bi-file-music::before { content: "\f3a5"; } -.bi-file-person-fill::before { content: "\f3a6"; } -.bi-file-person::before { content: "\f3a7"; } -.bi-file-play-fill::before { content: "\f3a8"; } -.bi-file-play::before { content: "\f3a9"; } -.bi-file-plus-fill::before { content: "\f3aa"; } -.bi-file-plus::before { content: "\f3ab"; } -.bi-file-post-fill::before { content: "\f3ac"; } -.bi-file-post::before { content: "\f3ad"; } -.bi-file-ppt-fill::before { content: "\f3ae"; } -.bi-file-ppt::before { content: "\f3af"; } -.bi-file-richtext-fill::before { content: "\f3b0"; } -.bi-file-richtext::before { content: "\f3b1"; } -.bi-file-ruled-fill::before { content: "\f3b2"; } -.bi-file-ruled::before { content: "\f3b3"; } -.bi-file-slides-fill::before { content: "\f3b4"; } -.bi-file-slides::before { content: "\f3b5"; } -.bi-file-spreadsheet-fill::before { content: "\f3b6"; } -.bi-file-spreadsheet::before { content: "\f3b7"; } -.bi-file-text-fill::before { content: "\f3b8"; } -.bi-file-text::before { content: "\f3b9"; } -.bi-file-word-fill::before { content: "\f3ba"; } -.bi-file-word::before { content: "\f3bb"; } -.bi-file-x-fill::before { content: "\f3bc"; } -.bi-file-x::before { content: "\f3bd"; } -.bi-file-zip-fill::before { content: "\f3be"; } -.bi-file-zip::before { content: "\f3bf"; } -.bi-file::before { content: "\f3c0"; } -.bi-files-alt::before { content: "\f3c1"; } -.bi-files::before { content: "\f3c2"; } -.bi-film::before { content: "\f3c3"; } -.bi-filter-circle-fill::before { content: "\f3c4"; } -.bi-filter-circle::before { content: "\f3c5"; } -.bi-filter-left::before { content: "\f3c6"; } -.bi-filter-right::before { content: "\f3c7"; } -.bi-filter-square-fill::before { content: "\f3c8"; } -.bi-filter-square::before { content: "\f3c9"; } -.bi-filter::before { content: "\f3ca"; } -.bi-flag-fill::before { content: "\f3cb"; } -.bi-flag::before { content: "\f3cc"; } -.bi-flower1::before { content: "\f3cd"; } -.bi-flower2::before { content: "\f3ce"; } -.bi-flower3::before { content: "\f3cf"; } -.bi-folder-check::before { content: "\f3d0"; } -.bi-folder-fill::before { content: "\f3d1"; } -.bi-folder-minus::before { content: "\f3d2"; } -.bi-folder-plus::before { content: "\f3d3"; } -.bi-folder-symlink-fill::before { content: "\f3d4"; } -.bi-folder-symlink::before { content: "\f3d5"; } -.bi-folder-x::before { content: "\f3d6"; } -.bi-folder::before { content: "\f3d7"; } -.bi-folder2-open::before { content: "\f3d8"; } -.bi-folder2::before { content: "\f3d9"; } -.bi-fonts::before { content: "\f3da"; } -.bi-forward-fill::before { content: "\f3db"; } -.bi-forward::before { content: "\f3dc"; } -.bi-front::before { content: "\f3dd"; } -.bi-fullscreen-exit::before { content: "\f3de"; } -.bi-fullscreen::before { content: "\f3df"; } -.bi-funnel-fill::before { content: "\f3e0"; } -.bi-funnel::before { content: "\f3e1"; } -.bi-gear-fill::before { content: "\f3e2"; } -.bi-gear-wide-connected::before { content: "\f3e3"; } -.bi-gear-wide::before { content: "\f3e4"; } -.bi-gear::before { content: "\f3e5"; } -.bi-gem::before { content: "\f3e6"; } -.bi-geo-alt-fill::before { content: "\f3e7"; } -.bi-geo-alt::before { content: "\f3e8"; } -.bi-geo-fill::before { content: "\f3e9"; } -.bi-geo::before { content: "\f3ea"; } -.bi-gift-fill::before { content: "\f3eb"; } -.bi-gift::before { content: "\f3ec"; } -.bi-github::before { content: "\f3ed"; } -.bi-globe::before { content: "\f3ee"; } -.bi-globe2::before { content: "\f3ef"; } -.bi-google::before { content: "\f3f0"; } -.bi-graph-down::before { content: "\f3f1"; } -.bi-graph-up::before { content: "\f3f2"; } -.bi-grid-1x2-fill::before { content: "\f3f3"; } -.bi-grid-1x2::before { content: "\f3f4"; } -.bi-grid-3x2-gap-fill::before { content: "\f3f5"; } -.bi-grid-3x2-gap::before { content: "\f3f6"; } -.bi-grid-3x2::before { content: "\f3f7"; } -.bi-grid-3x3-gap-fill::before { content: "\f3f8"; } -.bi-grid-3x3-gap::before { content: "\f3f9"; } -.bi-grid-3x3::before { content: "\f3fa"; } -.bi-grid-fill::before { content: "\f3fb"; } -.bi-grid::before { content: "\f3fc"; } -.bi-grip-horizontal::before { content: "\f3fd"; } -.bi-grip-vertical::before { content: "\f3fe"; } -.bi-hammer::before { content: "\f3ff"; } -.bi-hand-index-fill::before { content: "\f400"; } -.bi-hand-index-thumb-fill::before { content: "\f401"; } -.bi-hand-index-thumb::before { content: "\f402"; } -.bi-hand-index::before { content: "\f403"; } -.bi-hand-thumbs-down-fill::before { content: "\f404"; } -.bi-hand-thumbs-down::before { content: "\f405"; } -.bi-hand-thumbs-up-fill::before { content: "\f406"; } -.bi-hand-thumbs-up::before { content: "\f407"; } -.bi-handbag-fill::before { content: "\f408"; } -.bi-handbag::before { content: "\f409"; } -.bi-hash::before { content: "\f40a"; } -.bi-hdd-fill::before { content: "\f40b"; } -.bi-hdd-network-fill::before { content: "\f40c"; } -.bi-hdd-network::before { content: "\f40d"; } -.bi-hdd-rack-fill::before { content: "\f40e"; } -.bi-hdd-rack::before { content: "\f40f"; } -.bi-hdd-stack-fill::before { content: "\f410"; } -.bi-hdd-stack::before { content: "\f411"; } -.bi-hdd::before { content: "\f412"; } -.bi-headphones::before { content: "\f413"; } -.bi-headset::before { content: "\f414"; } -.bi-heart-fill::before { content: "\f415"; } -.bi-heart-half::before { content: "\f416"; } -.bi-heart::before { content: "\f417"; } -.bi-heptagon-fill::before { content: "\f418"; } -.bi-heptagon-half::before { content: "\f419"; } -.bi-heptagon::before { content: "\f41a"; } -.bi-hexagon-fill::before { content: "\f41b"; } -.bi-hexagon-half::before { content: "\f41c"; } -.bi-hexagon::before { content: "\f41d"; } -.bi-hourglass-bottom::before { content: "\f41e"; } -.bi-hourglass-split::before { content: "\f41f"; } -.bi-hourglass-top::before { content: "\f420"; } -.bi-hourglass::before { content: "\f421"; } -.bi-house-door-fill::before { content: "\f422"; } -.bi-house-door::before { content: "\f423"; } -.bi-house-fill::before { content: "\f424"; } -.bi-house::before { content: "\f425"; } -.bi-hr::before { content: "\f426"; } -.bi-hurricane::before { content: "\f427"; } -.bi-image-alt::before { content: "\f428"; } -.bi-image-fill::before { content: "\f429"; } -.bi-image::before { content: "\f42a"; } -.bi-images::before { content: "\f42b"; } -.bi-inbox-fill::before { content: "\f42c"; } -.bi-inbox::before { content: "\f42d"; } -.bi-inboxes-fill::before { content: "\f42e"; } -.bi-inboxes::before { content: "\f42f"; } -.bi-info-circle-fill::before { content: "\f430"; } -.bi-info-circle::before { content: "\f431"; } -.bi-info-square-fill::before { content: "\f432"; } -.bi-info-square::before { content: "\f433"; } -.bi-info::before { content: "\f434"; } -.bi-input-cursor-text::before { content: "\f435"; } -.bi-input-cursor::before { content: "\f436"; } -.bi-instagram::before { content: "\f437"; } -.bi-intersect::before { content: "\f438"; } -.bi-journal-album::before { content: "\f439"; } -.bi-journal-arrow-down::before { content: "\f43a"; } -.bi-journal-arrow-up::before { content: "\f43b"; } -.bi-journal-bookmark-fill::before { content: "\f43c"; } -.bi-journal-bookmark::before { content: "\f43d"; } -.bi-journal-check::before { content: "\f43e"; } -.bi-journal-code::before { content: "\f43f"; } -.bi-journal-medical::before { content: "\f440"; } -.bi-journal-minus::before { content: "\f441"; } -.bi-journal-plus::before { content: "\f442"; } -.bi-journal-richtext::before { content: "\f443"; } -.bi-journal-text::before { content: "\f444"; } -.bi-journal-x::before { content: "\f445"; } -.bi-journal::before { content: "\f446"; } -.bi-journals::before { content: "\f447"; } -.bi-joystick::before { content: "\f448"; } -.bi-justify-left::before { content: "\f449"; } -.bi-justify-right::before { content: "\f44a"; } -.bi-justify::before { content: "\f44b"; } -.bi-kanban-fill::before { content: "\f44c"; } -.bi-kanban::before { content: "\f44d"; } -.bi-key-fill::before { content: "\f44e"; } -.bi-key::before { content: "\f44f"; } -.bi-keyboard-fill::before { content: "\f450"; } -.bi-keyboard::before { content: "\f451"; } -.bi-ladder::before { content: "\f452"; } -.bi-lamp-fill::before { content: "\f453"; } -.bi-lamp::before { content: "\f454"; } -.bi-laptop-fill::before { content: "\f455"; } -.bi-laptop::before { content: "\f456"; } -.bi-layer-backward::before { content: "\f457"; } -.bi-layer-forward::before { content: "\f458"; } -.bi-layers-fill::before { content: "\f459"; } -.bi-layers-half::before { content: "\f45a"; } -.bi-layers::before { content: "\f45b"; } -.bi-layout-sidebar-inset-reverse::before { content: "\f45c"; } -.bi-layout-sidebar-inset::before { content: "\f45d"; } -.bi-layout-sidebar-reverse::before { content: "\f45e"; } -.bi-layout-sidebar::before { content: "\f45f"; } -.bi-layout-split::before { content: "\f460"; } -.bi-layout-text-sidebar-reverse::before { content: "\f461"; } -.bi-layout-text-sidebar::before { content: "\f462"; } -.bi-layout-text-window-reverse::before { content: "\f463"; } -.bi-layout-text-window::before { content: "\f464"; } -.bi-layout-three-columns::before { content: "\f465"; } -.bi-layout-wtf::before { content: "\f466"; } -.bi-life-preserver::before { content: "\f467"; } -.bi-lightbulb-fill::before { content: "\f468"; } -.bi-lightbulb-off-fill::before { content: "\f469"; } -.bi-lightbulb-off::before { content: "\f46a"; } -.bi-lightbulb::before { content: "\f46b"; } -.bi-lightning-charge-fill::before { content: "\f46c"; } -.bi-lightning-charge::before { content: "\f46d"; } -.bi-lightning-fill::before { content: "\f46e"; } -.bi-lightning::before { content: "\f46f"; } -.bi-link-45deg::before { content: "\f470"; } -.bi-link::before { content: "\f471"; } -.bi-linkedin::before { content: "\f472"; } -.bi-list-check::before { content: "\f473"; } -.bi-list-nested::before { content: "\f474"; } -.bi-list-ol::before { content: "\f475"; } -.bi-list-stars::before { content: "\f476"; } -.bi-list-task::before { content: "\f477"; } -.bi-list-ul::before { content: "\f478"; } -.bi-list::before { content: "\f479"; } -.bi-lock-fill::before { content: "\f47a"; } -.bi-lock::before { content: "\f47b"; } -.bi-mailbox::before { content: "\f47c"; } -.bi-mailbox2::before { content: "\f47d"; } -.bi-map-fill::before { content: "\f47e"; } -.bi-map::before { content: "\f47f"; } -.bi-markdown-fill::before { content: "\f480"; } -.bi-markdown::before { content: "\f481"; } -.bi-mask::before { content: "\f482"; } -.bi-megaphone-fill::before { content: "\f483"; } -.bi-megaphone::before { content: "\f484"; } -.bi-menu-app-fill::before { content: "\f485"; } -.bi-menu-app::before { content: "\f486"; } -.bi-menu-button-fill::before { content: "\f487"; } -.bi-menu-button-wide-fill::before { content: "\f488"; } -.bi-menu-button-wide::before { content: "\f489"; } -.bi-menu-button::before { content: "\f48a"; } -.bi-menu-down::before { content: "\f48b"; } -.bi-menu-up::before { content: "\f48c"; } -.bi-mic-fill::before { content: "\f48d"; } -.bi-mic-mute-fill::before { content: "\f48e"; } -.bi-mic-mute::before { content: "\f48f"; } -.bi-mic::before { content: "\f490"; } -.bi-minecart-loaded::before { content: "\f491"; } -.bi-minecart::before { content: "\f492"; } -.bi-moisture::before { content: "\f493"; } -.bi-moon-fill::before { content: "\f494"; } -.bi-moon-stars-fill::before { content: "\f495"; } -.bi-moon-stars::before { content: "\f496"; } -.bi-moon::before { content: "\f497"; } -.bi-mouse-fill::before { content: "\f498"; } -.bi-mouse::before { content: "\f499"; } -.bi-mouse2-fill::before { content: "\f49a"; } -.bi-mouse2::before { content: "\f49b"; } -.bi-mouse3-fill::before { content: "\f49c"; } -.bi-mouse3::before { content: "\f49d"; } -.bi-music-note-beamed::before { content: "\f49e"; } -.bi-music-note-list::before { content: "\f49f"; } -.bi-music-note::before { content: "\f4a0"; } -.bi-music-player-fill::before { content: "\f4a1"; } -.bi-music-player::before { content: "\f4a2"; } -.bi-newspaper::before { content: "\f4a3"; } -.bi-node-minus-fill::before { content: "\f4a4"; } -.bi-node-minus::before { content: "\f4a5"; } -.bi-node-plus-fill::before { content: "\f4a6"; } -.bi-node-plus::before { content: "\f4a7"; } -.bi-nut-fill::before { content: "\f4a8"; } -.bi-nut::before { content: "\f4a9"; } -.bi-octagon-fill::before { content: "\f4aa"; } -.bi-octagon-half::before { content: "\f4ab"; } -.bi-octagon::before { content: "\f4ac"; } -.bi-option::before { content: "\f4ad"; } -.bi-outlet::before { content: "\f4ae"; } -.bi-paint-bucket::before { content: "\f4af"; } -.bi-palette-fill::before { content: "\f4b0"; } -.bi-palette::before { content: "\f4b1"; } -.bi-palette2::before { content: "\f4b2"; } -.bi-paperclip::before { content: "\f4b3"; } -.bi-paragraph::before { content: "\f4b4"; } -.bi-patch-check-fill::before { content: "\f4b5"; } -.bi-patch-check::before { content: "\f4b6"; } -.bi-patch-exclamation-fill::before { content: "\f4b7"; } -.bi-patch-exclamation::before { content: "\f4b8"; } -.bi-patch-minus-fill::before { content: "\f4b9"; } -.bi-patch-minus::before { content: "\f4ba"; } -.bi-patch-plus-fill::before { content: "\f4bb"; } -.bi-patch-plus::before { content: "\f4bc"; } -.bi-patch-question-fill::before { content: "\f4bd"; } -.bi-patch-question::before { content: "\f4be"; } -.bi-pause-btn-fill::before { content: "\f4bf"; } -.bi-pause-btn::before { content: "\f4c0"; } -.bi-pause-circle-fill::before { content: "\f4c1"; } -.bi-pause-circle::before { content: "\f4c2"; } -.bi-pause-fill::before { content: "\f4c3"; } -.bi-pause::before { content: "\f4c4"; } -.bi-peace-fill::before { content: "\f4c5"; } -.bi-peace::before { content: "\f4c6"; } -.bi-pen-fill::before { content: "\f4c7"; } -.bi-pen::before { content: "\f4c8"; } -.bi-pencil-fill::before { content: "\f4c9"; } -.bi-pencil-square::before { content: "\f4ca"; } -.bi-pencil::before { content: "\f4cb"; } -.bi-pentagon-fill::before { content: "\f4cc"; } -.bi-pentagon-half::before { content: "\f4cd"; } -.bi-pentagon::before { content: "\f4ce"; } -.bi-people-fill::before { content: "\f4cf"; } -.bi-people::before { content: "\f4d0"; } -.bi-percent::before { content: "\f4d1"; } -.bi-person-badge-fill::before { content: "\f4d2"; } -.bi-person-badge::before { content: "\f4d3"; } -.bi-person-bounding-box::before { content: "\f4d4"; } -.bi-person-check-fill::before { content: "\f4d5"; } -.bi-person-check::before { content: "\f4d6"; } -.bi-person-circle::before { content: "\f4d7"; } -.bi-person-dash-fill::before { content: "\f4d8"; } -.bi-person-dash::before { content: "\f4d9"; } -.bi-person-fill::before { content: "\f4da"; } -.bi-person-lines-fill::before { content: "\f4db"; } -.bi-person-plus-fill::before { content: "\f4dc"; } -.bi-person-plus::before { content: "\f4dd"; } -.bi-person-square::before { content: "\f4de"; } -.bi-person-x-fill::before { content: "\f4df"; } -.bi-person-x::before { content: "\f4e0"; } -.bi-person::before { content: "\f4e1"; } -.bi-phone-fill::before { content: "\f4e2"; } -.bi-phone-landscape-fill::before { content: "\f4e3"; } -.bi-phone-landscape::before { content: "\f4e4"; } -.bi-phone-vibrate-fill::before { content: "\f4e5"; } -.bi-phone-vibrate::before { content: "\f4e6"; } -.bi-phone::before { content: "\f4e7"; } -.bi-pie-chart-fill::before { content: "\f4e8"; } -.bi-pie-chart::before { content: "\f4e9"; } -.bi-pin-angle-fill::before { content: "\f4ea"; } -.bi-pin-angle::before { content: "\f4eb"; } -.bi-pin-fill::before { content: "\f4ec"; } -.bi-pin::before { content: "\f4ed"; } -.bi-pip-fill::before { content: "\f4ee"; } -.bi-pip::before { content: "\f4ef"; } -.bi-play-btn-fill::before { content: "\f4f0"; } -.bi-play-btn::before { content: "\f4f1"; } -.bi-play-circle-fill::before { content: "\f4f2"; } -.bi-play-circle::before { content: "\f4f3"; } -.bi-play-fill::before { content: "\f4f4"; } -.bi-play::before { content: "\f4f5"; } -.bi-plug-fill::before { content: "\f4f6"; } -.bi-plug::before { content: "\f4f7"; } -.bi-plus-circle-dotted::before { content: "\f4f8"; } -.bi-plus-circle-fill::before { content: "\f4f9"; } -.bi-plus-circle::before { content: "\f4fa"; } -.bi-plus-square-dotted::before { content: "\f4fb"; } -.bi-plus-square-fill::before { content: "\f4fc"; } -.bi-plus-square::before { content: "\f4fd"; } -.bi-plus::before { content: "\f4fe"; } -.bi-power::before { content: "\f4ff"; } -.bi-printer-fill::before { content: "\f500"; } -.bi-printer::before { content: "\f501"; } -.bi-puzzle-fill::before { content: "\f502"; } -.bi-puzzle::before { content: "\f503"; } -.bi-question-circle-fill::before { content: "\f504"; } -.bi-question-circle::before { content: "\f505"; } -.bi-question-diamond-fill::before { content: "\f506"; } -.bi-question-diamond::before { content: "\f507"; } -.bi-question-octagon-fill::before { content: "\f508"; } -.bi-question-octagon::before { content: "\f509"; } -.bi-question-square-fill::before { content: "\f50a"; } -.bi-question-square::before { content: "\f50b"; } -.bi-question::before { content: "\f50c"; } -.bi-rainbow::before { content: "\f50d"; } -.bi-receipt-cutoff::before { content: "\f50e"; } -.bi-receipt::before { content: "\f50f"; } -.bi-reception-0::before { content: "\f510"; } -.bi-reception-1::before { content: "\f511"; } -.bi-reception-2::before { content: "\f512"; } -.bi-reception-3::before { content: "\f513"; } -.bi-reception-4::before { content: "\f514"; } -.bi-record-btn-fill::before { content: "\f515"; } -.bi-record-btn::before { content: "\f516"; } -.bi-record-circle-fill::before { content: "\f517"; } -.bi-record-circle::before { content: "\f518"; } -.bi-record-fill::before { content: "\f519"; } -.bi-record::before { content: "\f51a"; } -.bi-record2-fill::before { content: "\f51b"; } -.bi-record2::before { content: "\f51c"; } -.bi-reply-all-fill::before { content: "\f51d"; } -.bi-reply-all::before { content: "\f51e"; } -.bi-reply-fill::before { content: "\f51f"; } -.bi-reply::before { content: "\f520"; } -.bi-rss-fill::before { content: "\f521"; } -.bi-rss::before { content: "\f522"; } -.bi-rulers::before { content: "\f523"; } -.bi-save-fill::before { content: "\f524"; } -.bi-save::before { content: "\f525"; } -.bi-save2-fill::before { content: "\f526"; } -.bi-save2::before { content: "\f527"; } -.bi-scissors::before { content: "\f528"; } -.bi-screwdriver::before { content: "\f529"; } -.bi-search::before { content: "\f52a"; } -.bi-segmented-nav::before { content: "\f52b"; } -.bi-server::before { content: "\f52c"; } -.bi-share-fill::before { content: "\f52d"; } -.bi-share::before { content: "\f52e"; } -.bi-shield-check::before { content: "\f52f"; } -.bi-shield-exclamation::before { content: "\f530"; } -.bi-shield-fill-check::before { content: "\f531"; } -.bi-shield-fill-exclamation::before { content: "\f532"; } -.bi-shield-fill-minus::before { content: "\f533"; } -.bi-shield-fill-plus::before { content: "\f534"; } -.bi-shield-fill-x::before { content: "\f535"; } -.bi-shield-fill::before { content: "\f536"; } -.bi-shield-lock-fill::before { content: "\f537"; } -.bi-shield-lock::before { content: "\f538"; } -.bi-shield-minus::before { content: "\f539"; } -.bi-shield-plus::before { content: "\f53a"; } -.bi-shield-shaded::before { content: "\f53b"; } -.bi-shield-slash-fill::before { content: "\f53c"; } -.bi-shield-slash::before { content: "\f53d"; } -.bi-shield-x::before { content: "\f53e"; } -.bi-shield::before { content: "\f53f"; } -.bi-shift-fill::before { content: "\f540"; } -.bi-shift::before { content: "\f541"; } -.bi-shop-window::before { content: "\f542"; } -.bi-shop::before { content: "\f543"; } -.bi-shuffle::before { content: "\f544"; } -.bi-signpost-2-fill::before { content: "\f545"; } -.bi-signpost-2::before { content: "\f546"; } -.bi-signpost-fill::before { content: "\f547"; } -.bi-signpost-split-fill::before { content: "\f548"; } -.bi-signpost-split::before { content: "\f549"; } -.bi-signpost::before { content: "\f54a"; } -.bi-sim-fill::before { content: "\f54b"; } -.bi-sim::before { content: "\f54c"; } -.bi-skip-backward-btn-fill::before { content: "\f54d"; } -.bi-skip-backward-btn::before { content: "\f54e"; } -.bi-skip-backward-circle-fill::before { content: "\f54f"; } -.bi-skip-backward-circle::before { content: "\f550"; } -.bi-skip-backward-fill::before { content: "\f551"; } -.bi-skip-backward::before { content: "\f552"; } -.bi-skip-end-btn-fill::before { content: "\f553"; } -.bi-skip-end-btn::before { content: "\f554"; } -.bi-skip-end-circle-fill::before { content: "\f555"; } -.bi-skip-end-circle::before { content: "\f556"; } -.bi-skip-end-fill::before { content: "\f557"; } -.bi-skip-end::before { content: "\f558"; } -.bi-skip-forward-btn-fill::before { content: "\f559"; } -.bi-skip-forward-btn::before { content: "\f55a"; } -.bi-skip-forward-circle-fill::before { content: "\f55b"; } -.bi-skip-forward-circle::before { content: "\f55c"; } -.bi-skip-forward-fill::before { content: "\f55d"; } -.bi-skip-forward::before { content: "\f55e"; } -.bi-skip-start-btn-fill::before { content: "\f55f"; } -.bi-skip-start-btn::before { content: "\f560"; } -.bi-skip-start-circle-fill::before { content: "\f561"; } -.bi-skip-start-circle::before { content: "\f562"; } -.bi-skip-start-fill::before { content: "\f563"; } -.bi-skip-start::before { content: "\f564"; } -.bi-slack::before { content: "\f565"; } -.bi-slash-circle-fill::before { content: "\f566"; } -.bi-slash-circle::before { content: "\f567"; } -.bi-slash-square-fill::before { content: "\f568"; } -.bi-slash-square::before { content: "\f569"; } -.bi-slash::before { content: "\f56a"; } -.bi-sliders::before { content: "\f56b"; } -.bi-smartwatch::before { content: "\f56c"; } -.bi-snow::before { content: "\f56d"; } -.bi-snow2::before { content: "\f56e"; } -.bi-snow3::before { content: "\f56f"; } -.bi-sort-alpha-down-alt::before { content: "\f570"; } -.bi-sort-alpha-down::before { content: "\f571"; } -.bi-sort-alpha-up-alt::before { content: "\f572"; } -.bi-sort-alpha-up::before { content: "\f573"; } -.bi-sort-down-alt::before { content: "\f574"; } -.bi-sort-down::before { content: "\f575"; } -.bi-sort-numeric-down-alt::before { content: "\f576"; } -.bi-sort-numeric-down::before { content: "\f577"; } -.bi-sort-numeric-up-alt::before { content: "\f578"; } -.bi-sort-numeric-up::before { content: "\f579"; } -.bi-sort-up-alt::before { content: "\f57a"; } -.bi-sort-up::before { content: "\f57b"; } -.bi-soundwave::before { content: "\f57c"; } -.bi-speaker-fill::before { content: "\f57d"; } -.bi-speaker::before { content: "\f57e"; } -.bi-speedometer::before { content: "\f57f"; } -.bi-speedometer2::before { content: "\f580"; } -.bi-spellcheck::before { content: "\f581"; } -.bi-square-fill::before { content: "\f582"; } -.bi-square-half::before { content: "\f583"; } -.bi-square::before { content: "\f584"; } -.bi-stack::before { content: "\f585"; } -.bi-star-fill::before { content: "\f586"; } -.bi-star-half::before { content: "\f587"; } -.bi-star::before { content: "\f588"; } -.bi-stars::before { content: "\f589"; } -.bi-stickies-fill::before { content: "\f58a"; } -.bi-stickies::before { content: "\f58b"; } -.bi-sticky-fill::before { content: "\f58c"; } -.bi-sticky::before { content: "\f58d"; } -.bi-stop-btn-fill::before { content: "\f58e"; } -.bi-stop-btn::before { content: "\f58f"; } -.bi-stop-circle-fill::before { content: "\f590"; } -.bi-stop-circle::before { content: "\f591"; } -.bi-stop-fill::before { content: "\f592"; } -.bi-stop::before { content: "\f593"; } -.bi-stoplights-fill::before { content: "\f594"; } -.bi-stoplights::before { content: "\f595"; } -.bi-stopwatch-fill::before { content: "\f596"; } -.bi-stopwatch::before { content: "\f597"; } -.bi-subtract::before { content: "\f598"; } -.bi-suit-club-fill::before { content: "\f599"; } -.bi-suit-club::before { content: "\f59a"; } -.bi-suit-diamond-fill::before { content: "\f59b"; } -.bi-suit-diamond::before { content: "\f59c"; } -.bi-suit-heart-fill::before { content: "\f59d"; } -.bi-suit-heart::before { content: "\f59e"; } -.bi-suit-spade-fill::before { content: "\f59f"; } -.bi-suit-spade::before { content: "\f5a0"; } -.bi-sun-fill::before { content: "\f5a1"; } -.bi-sun::before { content: "\f5a2"; } -.bi-sunglasses::before { content: "\f5a3"; } -.bi-sunrise-fill::before { content: "\f5a4"; } -.bi-sunrise::before { content: "\f5a5"; } -.bi-sunset-fill::before { content: "\f5a6"; } -.bi-sunset::before { content: "\f5a7"; } -.bi-symmetry-horizontal::before { content: "\f5a8"; } -.bi-symmetry-vertical::before { content: "\f5a9"; } -.bi-table::before { content: "\f5aa"; } -.bi-tablet-fill::before { content: "\f5ab"; } -.bi-tablet-landscape-fill::before { content: "\f5ac"; } -.bi-tablet-landscape::before { content: "\f5ad"; } -.bi-tablet::before { content: "\f5ae"; } -.bi-tag-fill::before { content: "\f5af"; } -.bi-tag::before { content: "\f5b0"; } -.bi-tags-fill::before { content: "\f5b1"; } -.bi-tags::before { content: "\f5b2"; } -.bi-telegram::before { content: "\f5b3"; } -.bi-telephone-fill::before { content: "\f5b4"; } -.bi-telephone-forward-fill::before { content: "\f5b5"; } -.bi-telephone-forward::before { content: "\f5b6"; } -.bi-telephone-inbound-fill::before { content: "\f5b7"; } -.bi-telephone-inbound::before { content: "\f5b8"; } -.bi-telephone-minus-fill::before { content: "\f5b9"; } -.bi-telephone-minus::before { content: "\f5ba"; } -.bi-telephone-outbound-fill::before { content: "\f5bb"; } -.bi-telephone-outbound::before { content: "\f5bc"; } -.bi-telephone-plus-fill::before { content: "\f5bd"; } -.bi-telephone-plus::before { content: "\f5be"; } -.bi-telephone-x-fill::before { content: "\f5bf"; } -.bi-telephone-x::before { content: "\f5c0"; } -.bi-telephone::before { content: "\f5c1"; } -.bi-terminal-fill::before { content: "\f5c2"; } -.bi-terminal::before { content: "\f5c3"; } -.bi-text-center::before { content: "\f5c4"; } -.bi-text-indent-left::before { content: "\f5c5"; } -.bi-text-indent-right::before { content: "\f5c6"; } -.bi-text-left::before { content: "\f5c7"; } -.bi-text-paragraph::before { content: "\f5c8"; } -.bi-text-right::before { content: "\f5c9"; } -.bi-textarea-resize::before { content: "\f5ca"; } -.bi-textarea-t::before { content: "\f5cb"; } -.bi-textarea::before { content: "\f5cc"; } -.bi-thermometer-half::before { content: "\f5cd"; } -.bi-thermometer-high::before { content: "\f5ce"; } -.bi-thermometer-low::before { content: "\f5cf"; } -.bi-thermometer-snow::before { content: "\f5d0"; } -.bi-thermometer-sun::before { content: "\f5d1"; } -.bi-thermometer::before { content: "\f5d2"; } -.bi-three-dots-vertical::before { content: "\f5d3"; } -.bi-three-dots::before { content: "\f5d4"; } -.bi-toggle-off::before { content: "\f5d5"; } -.bi-toggle-on::before { content: "\f5d6"; } -.bi-toggle2-off::before { content: "\f5d7"; } -.bi-toggle2-on::before { content: "\f5d8"; } -.bi-toggles::before { content: "\f5d9"; } -.bi-toggles2::before { content: "\f5da"; } -.bi-tools::before { content: "\f5db"; } -.bi-tornado::before { content: "\f5dc"; } -.bi-trash-fill::before { content: "\f5dd"; } -.bi-trash::before { content: "\f5de"; } -.bi-trash2-fill::before { content: "\f5df"; } -.bi-trash2::before { content: "\f5e0"; } -.bi-tree-fill::before { content: "\f5e1"; } -.bi-tree::before { content: "\f5e2"; } -.bi-triangle-fill::before { content: "\f5e3"; } -.bi-triangle-half::before { content: "\f5e4"; } -.bi-triangle::before { content: "\f5e5"; } -.bi-trophy-fill::before { content: "\f5e6"; } -.bi-trophy::before { content: "\f5e7"; } -.bi-tropical-storm::before { content: "\f5e8"; } -.bi-truck-flatbed::before { content: "\f5e9"; } -.bi-truck::before { content: "\f5ea"; } -.bi-tsunami::before { content: "\f5eb"; } -.bi-tv-fill::before { content: "\f5ec"; } -.bi-tv::before { content: "\f5ed"; } -.bi-twitch::before { content: "\f5ee"; } -.bi-twitter::before { content: "\f5ef"; } -.bi-type-bold::before { content: "\f5f0"; } -.bi-type-h1::before { content: "\f5f1"; } -.bi-type-h2::before { content: "\f5f2"; } -.bi-type-h3::before { content: "\f5f3"; } -.bi-type-italic::before { content: "\f5f4"; } -.bi-type-strikethrough::before { content: "\f5f5"; } -.bi-type-underline::before { content: "\f5f6"; } -.bi-type::before { content: "\f5f7"; } -.bi-ui-checks-grid::before { content: "\f5f8"; } -.bi-ui-checks::before { content: "\f5f9"; } -.bi-ui-radios-grid::before { content: "\f5fa"; } -.bi-ui-radios::before { content: "\f5fb"; } -.bi-umbrella-fill::before { content: "\f5fc"; } -.bi-umbrella::before { content: "\f5fd"; } -.bi-union::before { content: "\f5fe"; } -.bi-unlock-fill::before { content: "\f5ff"; } -.bi-unlock::before { content: "\f600"; } -.bi-upc-scan::before { content: "\f601"; } -.bi-upc::before { content: "\f602"; } -.bi-upload::before { content: "\f603"; } -.bi-vector-pen::before { content: "\f604"; } -.bi-view-list::before { content: "\f605"; } -.bi-view-stacked::before { content: "\f606"; } -.bi-vinyl-fill::before { content: "\f607"; } -.bi-vinyl::before { content: "\f608"; } -.bi-voicemail::before { content: "\f609"; } -.bi-volume-down-fill::before { content: "\f60a"; } -.bi-volume-down::before { content: "\f60b"; } -.bi-volume-mute-fill::before { content: "\f60c"; } -.bi-volume-mute::before { content: "\f60d"; } -.bi-volume-off-fill::before { content: "\f60e"; } -.bi-volume-off::before { content: "\f60f"; } -.bi-volume-up-fill::before { content: "\f610"; } -.bi-volume-up::before { content: "\f611"; } -.bi-vr::before { content: "\f612"; } -.bi-wallet-fill::before { content: "\f613"; } -.bi-wallet::before { content: "\f614"; } -.bi-wallet2::before { content: "\f615"; } -.bi-watch::before { content: "\f616"; } -.bi-water::before { content: "\f617"; } -.bi-whatsapp::before { content: "\f618"; } -.bi-wifi-1::before { content: "\f619"; } -.bi-wifi-2::before { content: "\f61a"; } -.bi-wifi-off::before { content: "\f61b"; } -.bi-wifi::before { content: "\f61c"; } -.bi-wind::before { content: "\f61d"; } -.bi-window-dock::before { content: "\f61e"; } -.bi-window-sidebar::before { content: "\f61f"; } -.bi-window::before { content: "\f620"; } -.bi-wrench::before { content: "\f621"; } -.bi-x-circle-fill::before { content: "\f622"; } -.bi-x-circle::before { content: "\f623"; } -.bi-x-diamond-fill::before { content: "\f624"; } -.bi-x-diamond::before { content: "\f625"; } -.bi-x-octagon-fill::before { content: "\f626"; } -.bi-x-octagon::before { content: "\f627"; } -.bi-x-square-fill::before { content: "\f628"; } -.bi-x-square::before { content: "\f629"; } -.bi-x::before { content: "\f62a"; } -.bi-youtube::before { content: "\f62b"; } -.bi-zoom-in::before { content: "\f62c"; } -.bi-zoom-out::before { content: "\f62d"; } -.bi-bank::before { content: "\f62e"; } -.bi-bank2::before { content: "\f62f"; } -.bi-bell-slash-fill::before { content: "\f630"; } -.bi-bell-slash::before { content: "\f631"; } -.bi-cash-coin::before { content: "\f632"; } -.bi-check-lg::before { content: "\f633"; } -.bi-coin::before { content: "\f634"; } -.bi-currency-bitcoin::before { content: "\f635"; } -.bi-currency-dollar::before { content: "\f636"; } -.bi-currency-euro::before { content: "\f637"; } -.bi-currency-exchange::before { content: "\f638"; } -.bi-currency-pound::before { content: "\f639"; } -.bi-currency-yen::before { content: "\f63a"; } -.bi-dash-lg::before { content: "\f63b"; } -.bi-exclamation-lg::before { content: "\f63c"; } -.bi-file-earmark-pdf-fill::before { content: "\f63d"; } -.bi-file-earmark-pdf::before { content: "\f63e"; } -.bi-file-pdf-fill::before { content: "\f63f"; } -.bi-file-pdf::before { content: "\f640"; } -.bi-gender-ambiguous::before { content: "\f641"; } -.bi-gender-female::before { content: "\f642"; } -.bi-gender-male::before { content: "\f643"; } -.bi-gender-trans::before { content: "\f644"; } -.bi-headset-vr::before { content: "\f645"; } -.bi-info-lg::before { content: "\f646"; } -.bi-mastodon::before { content: "\f647"; } -.bi-messenger::before { content: "\f648"; } -.bi-piggy-bank-fill::before { content: "\f649"; } -.bi-piggy-bank::before { content: "\f64a"; } -.bi-pin-map-fill::before { content: "\f64b"; } -.bi-pin-map::before { content: "\f64c"; } -.bi-plus-lg::before { content: "\f64d"; } -.bi-question-lg::before { content: "\f64e"; } -.bi-recycle::before { content: "\f64f"; } -.bi-reddit::before { content: "\f650"; } -.bi-safe-fill::before { content: "\f651"; } -.bi-safe2-fill::before { content: "\f652"; } -.bi-safe2::before { content: "\f653"; } -.bi-sd-card-fill::before { content: "\f654"; } -.bi-sd-card::before { content: "\f655"; } -.bi-skype::before { content: "\f656"; } -.bi-slash-lg::before { content: "\f657"; } -.bi-translate::before { content: "\f658"; } -.bi-x-lg::before { content: "\f659"; } -.bi-safe::before { content: "\f65a"; } -.bi-apple::before { content: "\f65b"; } -.bi-microsoft::before { content: "\f65d"; } -.bi-windows::before { content: "\f65e"; } -.bi-behance::before { content: "\f65c"; } -.bi-dribbble::before { content: "\f65f"; } -.bi-line::before { content: "\f660"; } -.bi-medium::before { content: "\f661"; } -.bi-paypal::before { content: "\f662"; } -.bi-pinterest::before { content: "\f663"; } -.bi-signal::before { content: "\f664"; } -.bi-snapchat::before { content: "\f665"; } -.bi-spotify::before { content: "\f666"; } -.bi-stack-overflow::before { content: "\f667"; } -.bi-strava::before { content: "\f668"; } -.bi-wordpress::before { content: "\f669"; } -.bi-vimeo::before { content: "\f66a"; } -.bi-activity::before { content: "\f66b"; } -.bi-easel2-fill::before { content: "\f66c"; } -.bi-easel2::before { content: "\f66d"; } -.bi-easel3-fill::before { content: "\f66e"; } -.bi-easel3::before { content: "\f66f"; } -.bi-fan::before { content: "\f670"; } -.bi-fingerprint::before { content: "\f671"; } -.bi-graph-down-arrow::before { content: "\f672"; } -.bi-graph-up-arrow::before { content: "\f673"; } -.bi-hypnotize::before { content: "\f674"; } -.bi-magic::before { content: "\f675"; } -.bi-person-rolodex::before { content: "\f676"; } -.bi-person-video::before { content: "\f677"; } -.bi-person-video2::before { content: "\f678"; } -.bi-person-video3::before { content: "\f679"; } -.bi-person-workspace::before { content: "\f67a"; } -.bi-radioactive::before { content: "\f67b"; } -.bi-webcam-fill::before { content: "\f67c"; } -.bi-webcam::before { content: "\f67d"; } -.bi-yin-yang::before { content: "\f67e"; } -.bi-bandaid-fill::before { content: "\f680"; } -.bi-bandaid::before { content: "\f681"; } -.bi-bluetooth::before { content: "\f682"; } -.bi-body-text::before { content: "\f683"; } -.bi-boombox::before { content: "\f684"; } -.bi-boxes::before { content: "\f685"; } -.bi-dpad-fill::before { content: "\f686"; } -.bi-dpad::before { content: "\f687"; } -.bi-ear-fill::before { content: "\f688"; } -.bi-ear::before { content: "\f689"; } -.bi-envelope-check-fill::before { content: "\f68b"; } -.bi-envelope-check::before { content: "\f68c"; } -.bi-envelope-dash-fill::before { content: "\f68e"; } -.bi-envelope-dash::before { content: "\f68f"; } -.bi-envelope-exclamation-fill::before { content: "\f691"; } -.bi-envelope-exclamation::before { content: "\f692"; } -.bi-envelope-plus-fill::before { content: "\f693"; } -.bi-envelope-plus::before { content: "\f694"; } -.bi-envelope-slash-fill::before { content: "\f696"; } -.bi-envelope-slash::before { content: "\f697"; } -.bi-envelope-x-fill::before { content: "\f699"; } -.bi-envelope-x::before { content: "\f69a"; } -.bi-explicit-fill::before { content: "\f69b"; } -.bi-explicit::before { content: "\f69c"; } -.bi-git::before { content: "\f69d"; } -.bi-infinity::before { content: "\f69e"; } -.bi-list-columns-reverse::before { content: "\f69f"; } -.bi-list-columns::before { content: "\f6a0"; } -.bi-meta::before { content: "\f6a1"; } -.bi-nintendo-switch::before { content: "\f6a4"; } -.bi-pc-display-horizontal::before { content: "\f6a5"; } -.bi-pc-display::before { content: "\f6a6"; } -.bi-pc-horizontal::before { content: "\f6a7"; } -.bi-pc::before { content: "\f6a8"; } -.bi-playstation::before { content: "\f6a9"; } -.bi-plus-slash-minus::before { content: "\f6aa"; } -.bi-projector-fill::before { content: "\f6ab"; } -.bi-projector::before { content: "\f6ac"; } -.bi-qr-code-scan::before { content: "\f6ad"; } -.bi-qr-code::before { content: "\f6ae"; } -.bi-quora::before { content: "\f6af"; } -.bi-quote::before { content: "\f6b0"; } -.bi-robot::before { content: "\f6b1"; } -.bi-send-check-fill::before { content: "\f6b2"; } -.bi-send-check::before { content: "\f6b3"; } -.bi-send-dash-fill::before { content: "\f6b4"; } -.bi-send-dash::before { content: "\f6b5"; } -.bi-send-exclamation-fill::before { content: "\f6b7"; } -.bi-send-exclamation::before { content: "\f6b8"; } -.bi-send-fill::before { content: "\f6b9"; } -.bi-send-plus-fill::before { content: "\f6ba"; } -.bi-send-plus::before { content: "\f6bb"; } -.bi-send-slash-fill::before { content: "\f6bc"; } -.bi-send-slash::before { content: "\f6bd"; } -.bi-send-x-fill::before { content: "\f6be"; } -.bi-send-x::before { content: "\f6bf"; } -.bi-send::before { content: "\f6c0"; } -.bi-steam::before { content: "\f6c1"; } -.bi-terminal-dash::before { content: "\f6c3"; } -.bi-terminal-plus::before { content: "\f6c4"; } -.bi-terminal-split::before { content: "\f6c5"; } -.bi-ticket-detailed-fill::before { content: "\f6c6"; } -.bi-ticket-detailed::before { content: "\f6c7"; } -.bi-ticket-fill::before { content: "\f6c8"; } -.bi-ticket-perforated-fill::before { content: "\f6c9"; } -.bi-ticket-perforated::before { content: "\f6ca"; } -.bi-ticket::before { content: "\f6cb"; } -.bi-tiktok::before { content: "\f6cc"; } -.bi-window-dash::before { content: "\f6cd"; } -.bi-window-desktop::before { content: "\f6ce"; } -.bi-window-fullscreen::before { content: "\f6cf"; } -.bi-window-plus::before { content: "\f6d0"; } -.bi-window-split::before { content: "\f6d1"; } -.bi-window-stack::before { content: "\f6d2"; } -.bi-window-x::before { content: "\f6d3"; } -.bi-xbox::before { content: "\f6d4"; } -.bi-ethernet::before { content: "\f6d5"; } -.bi-hdmi-fill::before { content: "\f6d6"; } -.bi-hdmi::before { content: "\f6d7"; } -.bi-usb-c-fill::before { content: "\f6d8"; } -.bi-usb-c::before { content: "\f6d9"; } -.bi-usb-fill::before { content: "\f6da"; } -.bi-usb-plug-fill::before { content: "\f6db"; } -.bi-usb-plug::before { content: "\f6dc"; } -.bi-usb-symbol::before { content: "\f6dd"; } -.bi-usb::before { content: "\f6de"; } -.bi-boombox-fill::before { content: "\f6df"; } -.bi-displayport::before { content: "\f6e1"; } -.bi-gpu-card::before { content: "\f6e2"; } -.bi-memory::before { content: "\f6e3"; } -.bi-modem-fill::before { content: "\f6e4"; } -.bi-modem::before { content: "\f6e5"; } -.bi-motherboard-fill::before { content: "\f6e6"; } -.bi-motherboard::before { content: "\f6e7"; } -.bi-optical-audio-fill::before { content: "\f6e8"; } -.bi-optical-audio::before { content: "\f6e9"; } -.bi-pci-card::before { content: "\f6ea"; } -.bi-router-fill::before { content: "\f6eb"; } -.bi-router::before { content: "\f6ec"; } -.bi-thunderbolt-fill::before { content: "\f6ef"; } -.bi-thunderbolt::before { content: "\f6f0"; } -.bi-usb-drive-fill::before { content: "\f6f1"; } -.bi-usb-drive::before { content: "\f6f2"; } -.bi-usb-micro-fill::before { content: "\f6f3"; } -.bi-usb-micro::before { content: "\f6f4"; } -.bi-usb-mini-fill::before { content: "\f6f5"; } -.bi-usb-mini::before { content: "\f6f6"; } -.bi-cloud-haze2::before { content: "\f6f7"; } -.bi-device-hdd-fill::before { content: "\f6f8"; } -.bi-device-hdd::before { content: "\f6f9"; } -.bi-device-ssd-fill::before { content: "\f6fa"; } -.bi-device-ssd::before { content: "\f6fb"; } -.bi-displayport-fill::before { content: "\f6fc"; } -.bi-mortarboard-fill::before { content: "\f6fd"; } -.bi-mortarboard::before { content: "\f6fe"; } -.bi-terminal-x::before { content: "\f6ff"; } -.bi-arrow-through-heart-fill::before { content: "\f700"; } -.bi-arrow-through-heart::before { content: "\f701"; } -.bi-badge-sd-fill::before { content: "\f702"; } -.bi-badge-sd::before { content: "\f703"; } -.bi-bag-heart-fill::before { content: "\f704"; } -.bi-bag-heart::before { content: "\f705"; } -.bi-balloon-fill::before { content: "\f706"; } -.bi-balloon-heart-fill::before { content: "\f707"; } -.bi-balloon-heart::before { content: "\f708"; } -.bi-balloon::before { content: "\f709"; } -.bi-box2-fill::before { content: "\f70a"; } -.bi-box2-heart-fill::before { content: "\f70b"; } -.bi-box2-heart::before { content: "\f70c"; } -.bi-box2::before { content: "\f70d"; } -.bi-braces-asterisk::before { content: "\f70e"; } -.bi-calendar-heart-fill::before { content: "\f70f"; } -.bi-calendar-heart::before { content: "\f710"; } -.bi-calendar2-heart-fill::before { content: "\f711"; } -.bi-calendar2-heart::before { content: "\f712"; } -.bi-chat-heart-fill::before { content: "\f713"; } -.bi-chat-heart::before { content: "\f714"; } -.bi-chat-left-heart-fill::before { content: "\f715"; } -.bi-chat-left-heart::before { content: "\f716"; } -.bi-chat-right-heart-fill::before { content: "\f717"; } -.bi-chat-right-heart::before { content: "\f718"; } -.bi-chat-square-heart-fill::before { content: "\f719"; } -.bi-chat-square-heart::before { content: "\f71a"; } -.bi-clipboard-check-fill::before { content: "\f71b"; } -.bi-clipboard-data-fill::before { content: "\f71c"; } -.bi-clipboard-fill::before { content: "\f71d"; } -.bi-clipboard-heart-fill::before { content: "\f71e"; } -.bi-clipboard-heart::before { content: "\f71f"; } -.bi-clipboard-minus-fill::before { content: "\f720"; } -.bi-clipboard-plus-fill::before { content: "\f721"; } -.bi-clipboard-pulse::before { content: "\f722"; } -.bi-clipboard-x-fill::before { content: "\f723"; } -.bi-clipboard2-check-fill::before { content: "\f724"; } -.bi-clipboard2-check::before { content: "\f725"; } -.bi-clipboard2-data-fill::before { content: "\f726"; } -.bi-clipboard2-data::before { content: "\f727"; } -.bi-clipboard2-fill::before { content: "\f728"; } -.bi-clipboard2-heart-fill::before { content: "\f729"; } -.bi-clipboard2-heart::before { content: "\f72a"; } -.bi-clipboard2-minus-fill::before { content: "\f72b"; } -.bi-clipboard2-minus::before { content: "\f72c"; } -.bi-clipboard2-plus-fill::before { content: "\f72d"; } -.bi-clipboard2-plus::before { content: "\f72e"; } -.bi-clipboard2-pulse-fill::before { content: "\f72f"; } -.bi-clipboard2-pulse::before { content: "\f730"; } -.bi-clipboard2-x-fill::before { content: "\f731"; } -.bi-clipboard2-x::before { content: "\f732"; } -.bi-clipboard2::before { content: "\f733"; } -.bi-emoji-kiss-fill::before { content: "\f734"; } -.bi-emoji-kiss::before { content: "\f735"; } -.bi-envelope-heart-fill::before { content: "\f736"; } -.bi-envelope-heart::before { content: "\f737"; } -.bi-envelope-open-heart-fill::before { content: "\f738"; } -.bi-envelope-open-heart::before { content: "\f739"; } -.bi-envelope-paper-fill::before { content: "\f73a"; } -.bi-envelope-paper-heart-fill::before { content: "\f73b"; } -.bi-envelope-paper-heart::before { content: "\f73c"; } -.bi-envelope-paper::before { content: "\f73d"; } -.bi-filetype-aac::before { content: "\f73e"; } -.bi-filetype-ai::before { content: "\f73f"; } -.bi-filetype-bmp::before { content: "\f740"; } -.bi-filetype-cs::before { content: "\f741"; } -.bi-filetype-css::before { content: "\f742"; } -.bi-filetype-csv::before { content: "\f743"; } -.bi-filetype-doc::before { content: "\f744"; } -.bi-filetype-docx::before { content: "\f745"; } -.bi-filetype-exe::before { content: "\f746"; } -.bi-filetype-gif::before { content: "\f747"; } -.bi-filetype-heic::before { content: "\f748"; } -.bi-filetype-html::before { content: "\f749"; } -.bi-filetype-java::before { content: "\f74a"; } -.bi-filetype-jpg::before { content: "\f74b"; } -.bi-filetype-js::before { content: "\f74c"; } -.bi-filetype-jsx::before { content: "\f74d"; } -.bi-filetype-key::before { content: "\f74e"; } -.bi-filetype-m4p::before { content: "\f74f"; } -.bi-filetype-md::before { content: "\f750"; } -.bi-filetype-mdx::before { content: "\f751"; } -.bi-filetype-mov::before { content: "\f752"; } -.bi-filetype-mp3::before { content: "\f753"; } -.bi-filetype-mp4::before { content: "\f754"; } -.bi-filetype-otf::before { content: "\f755"; } -.bi-filetype-pdf::before { content: "\f756"; } -.bi-filetype-php::before { content: "\f757"; } -.bi-filetype-png::before { content: "\f758"; } -.bi-filetype-ppt::before { content: "\f75a"; } -.bi-filetype-psd::before { content: "\f75b"; } -.bi-filetype-py::before { content: "\f75c"; } -.bi-filetype-raw::before { content: "\f75d"; } -.bi-filetype-rb::before { content: "\f75e"; } -.bi-filetype-sass::before { content: "\f75f"; } -.bi-filetype-scss::before { content: "\f760"; } -.bi-filetype-sh::before { content: "\f761"; } -.bi-filetype-svg::before { content: "\f762"; } -.bi-filetype-tiff::before { content: "\f763"; } -.bi-filetype-tsx::before { content: "\f764"; } -.bi-filetype-ttf::before { content: "\f765"; } -.bi-filetype-txt::before { content: "\f766"; } -.bi-filetype-wav::before { content: "\f767"; } -.bi-filetype-woff::before { content: "\f768"; } -.bi-filetype-xls::before { content: "\f76a"; } -.bi-filetype-xml::before { content: "\f76b"; } -.bi-filetype-yml::before { content: "\f76c"; } -.bi-heart-arrow::before { content: "\f76d"; } -.bi-heart-pulse-fill::before { content: "\f76e"; } -.bi-heart-pulse::before { content: "\f76f"; } -.bi-heartbreak-fill::before { content: "\f770"; } -.bi-heartbreak::before { content: "\f771"; } -.bi-hearts::before { content: "\f772"; } -.bi-hospital-fill::before { content: "\f773"; } -.bi-hospital::before { content: "\f774"; } -.bi-house-heart-fill::before { content: "\f775"; } -.bi-house-heart::before { content: "\f776"; } -.bi-incognito::before { content: "\f777"; } -.bi-magnet-fill::before { content: "\f778"; } -.bi-magnet::before { content: "\f779"; } -.bi-person-heart::before { content: "\f77a"; } -.bi-person-hearts::before { content: "\f77b"; } -.bi-phone-flip::before { content: "\f77c"; } -.bi-plugin::before { content: "\f77d"; } -.bi-postage-fill::before { content: "\f77e"; } -.bi-postage-heart-fill::before { content: "\f77f"; } -.bi-postage-heart::before { content: "\f780"; } -.bi-postage::before { content: "\f781"; } -.bi-postcard-fill::before { content: "\f782"; } -.bi-postcard-heart-fill::before { content: "\f783"; } -.bi-postcard-heart::before { content: "\f784"; } -.bi-postcard::before { content: "\f785"; } -.bi-search-heart-fill::before { content: "\f786"; } -.bi-search-heart::before { content: "\f787"; } -.bi-sliders2-vertical::before { content: "\f788"; } -.bi-sliders2::before { content: "\f789"; } -.bi-trash3-fill::before { content: "\f78a"; } -.bi-trash3::before { content: "\f78b"; } -.bi-valentine::before { content: "\f78c"; } -.bi-valentine2::before { content: "\f78d"; } -.bi-wrench-adjustable-circle-fill::before { content: "\f78e"; } -.bi-wrench-adjustable-circle::before { content: "\f78f"; } -.bi-wrench-adjustable::before { content: "\f790"; } -.bi-filetype-json::before { content: "\f791"; } -.bi-filetype-pptx::before { content: "\f792"; } -.bi-filetype-xlsx::before { content: "\f793"; } -.bi-1-circle-fill::before { content: "\f796"; } -.bi-1-circle::before { content: "\f797"; } -.bi-1-square-fill::before { content: "\f798"; } -.bi-1-square::before { content: "\f799"; } -.bi-2-circle-fill::before { content: "\f79c"; } -.bi-2-circle::before { content: "\f79d"; } -.bi-2-square-fill::before { content: "\f79e"; } -.bi-2-square::before { content: "\f79f"; } -.bi-3-circle-fill::before { content: "\f7a2"; } -.bi-3-circle::before { content: "\f7a3"; } -.bi-3-square-fill::before { content: "\f7a4"; } -.bi-3-square::before { content: "\f7a5"; } -.bi-4-circle-fill::before { content: "\f7a8"; } -.bi-4-circle::before { content: "\f7a9"; } -.bi-4-square-fill::before { content: "\f7aa"; } -.bi-4-square::before { content: "\f7ab"; } -.bi-5-circle-fill::before { content: "\f7ae"; } -.bi-5-circle::before { content: "\f7af"; } -.bi-5-square-fill::before { content: "\f7b0"; } -.bi-5-square::before { content: "\f7b1"; } -.bi-6-circle-fill::before { content: "\f7b4"; } -.bi-6-circle::before { content: "\f7b5"; } -.bi-6-square-fill::before { content: "\f7b6"; } -.bi-6-square::before { content: "\f7b7"; } -.bi-7-circle-fill::before { content: "\f7ba"; } -.bi-7-circle::before { content: "\f7bb"; } -.bi-7-square-fill::before { content: "\f7bc"; } -.bi-7-square::before { content: "\f7bd"; } -.bi-8-circle-fill::before { content: "\f7c0"; } -.bi-8-circle::before { content: "\f7c1"; } -.bi-8-square-fill::before { content: "\f7c2"; } -.bi-8-square::before { content: "\f7c3"; } -.bi-9-circle-fill::before { content: "\f7c6"; } -.bi-9-circle::before { content: "\f7c7"; } -.bi-9-square-fill::before { content: "\f7c8"; } -.bi-9-square::before { content: "\f7c9"; } -.bi-airplane-engines-fill::before { content: "\f7ca"; } -.bi-airplane-engines::before { content: "\f7cb"; } -.bi-airplane-fill::before { content: "\f7cc"; } -.bi-airplane::before { content: "\f7cd"; } -.bi-alexa::before { content: "\f7ce"; } -.bi-alipay::before { content: "\f7cf"; } -.bi-android::before { content: "\f7d0"; } -.bi-android2::before { content: "\f7d1"; } -.bi-box-fill::before { content: "\f7d2"; } -.bi-box-seam-fill::before { content: "\f7d3"; } -.bi-browser-chrome::before { content: "\f7d4"; } -.bi-browser-edge::before { content: "\f7d5"; } -.bi-browser-firefox::before { content: "\f7d6"; } -.bi-browser-safari::before { content: "\f7d7"; } -.bi-c-circle-fill::before { content: "\f7da"; } -.bi-c-circle::before { content: "\f7db"; } -.bi-c-square-fill::before { content: "\f7dc"; } -.bi-c-square::before { content: "\f7dd"; } -.bi-capsule-pill::before { content: "\f7de"; } -.bi-capsule::before { content: "\f7df"; } -.bi-car-front-fill::before { content: "\f7e0"; } -.bi-car-front::before { content: "\f7e1"; } -.bi-cassette-fill::before { content: "\f7e2"; } -.bi-cassette::before { content: "\f7e3"; } -.bi-cc-circle-fill::before { content: "\f7e6"; } -.bi-cc-circle::before { content: "\f7e7"; } -.bi-cc-square-fill::before { content: "\f7e8"; } -.bi-cc-square::before { content: "\f7e9"; } -.bi-cup-hot-fill::before { content: "\f7ea"; } -.bi-cup-hot::before { content: "\f7eb"; } -.bi-currency-rupee::before { content: "\f7ec"; } -.bi-dropbox::before { content: "\f7ed"; } -.bi-escape::before { content: "\f7ee"; } -.bi-fast-forward-btn-fill::before { content: "\f7ef"; } -.bi-fast-forward-btn::before { content: "\f7f0"; } -.bi-fast-forward-circle-fill::before { content: "\f7f1"; } -.bi-fast-forward-circle::before { content: "\f7f2"; } -.bi-fast-forward-fill::before { content: "\f7f3"; } -.bi-fast-forward::before { content: "\f7f4"; } -.bi-filetype-sql::before { content: "\f7f5"; } -.bi-fire::before { content: "\f7f6"; } -.bi-google-play::before { content: "\f7f7"; } -.bi-h-circle-fill::before { content: "\f7fa"; } -.bi-h-circle::before { content: "\f7fb"; } -.bi-h-square-fill::before { content: "\f7fc"; } -.bi-h-square::before { content: "\f7fd"; } -.bi-indent::before { content: "\f7fe"; } -.bi-lungs-fill::before { content: "\f7ff"; } -.bi-lungs::before { content: "\f800"; } -.bi-microsoft-teams::before { content: "\f801"; } -.bi-p-circle-fill::before { content: "\f804"; } -.bi-p-circle::before { content: "\f805"; } -.bi-p-square-fill::before { content: "\f806"; } -.bi-p-square::before { content: "\f807"; } -.bi-pass-fill::before { content: "\f808"; } -.bi-pass::before { content: "\f809"; } -.bi-prescription::before { content: "\f80a"; } -.bi-prescription2::before { content: "\f80b"; } -.bi-r-circle-fill::before { content: "\f80e"; } -.bi-r-circle::before { content: "\f80f"; } -.bi-r-square-fill::before { content: "\f810"; } -.bi-r-square::before { content: "\f811"; } -.bi-repeat-1::before { content: "\f812"; } -.bi-repeat::before { content: "\f813"; } -.bi-rewind-btn-fill::before { content: "\f814"; } -.bi-rewind-btn::before { content: "\f815"; } -.bi-rewind-circle-fill::before { content: "\f816"; } -.bi-rewind-circle::before { content: "\f817"; } -.bi-rewind-fill::before { content: "\f818"; } -.bi-rewind::before { content: "\f819"; } -.bi-train-freight-front-fill::before { content: "\f81a"; } -.bi-train-freight-front::before { content: "\f81b"; } -.bi-train-front-fill::before { content: "\f81c"; } -.bi-train-front::before { content: "\f81d"; } -.bi-train-lightrail-front-fill::before { content: "\f81e"; } -.bi-train-lightrail-front::before { content: "\f81f"; } -.bi-truck-front-fill::before { content: "\f820"; } -.bi-truck-front::before { content: "\f821"; } -.bi-ubuntu::before { content: "\f822"; } -.bi-unindent::before { content: "\f823"; } -.bi-unity::before { content: "\f824"; } -.bi-universal-access-circle::before { content: "\f825"; } -.bi-universal-access::before { content: "\f826"; } -.bi-virus::before { content: "\f827"; } -.bi-virus2::before { content: "\f828"; } -.bi-wechat::before { content: "\f829"; } -.bi-yelp::before { content: "\f82a"; } -.bi-sign-stop-fill::before { content: "\f82b"; } -.bi-sign-stop-lights-fill::before { content: "\f82c"; } -.bi-sign-stop-lights::before { content: "\f82d"; } -.bi-sign-stop::before { content: "\f82e"; } -.bi-sign-turn-left-fill::before { content: "\f82f"; } -.bi-sign-turn-left::before { content: "\f830"; } -.bi-sign-turn-right-fill::before { content: "\f831"; } -.bi-sign-turn-right::before { content: "\f832"; } -.bi-sign-turn-slight-left-fill::before { content: "\f833"; } -.bi-sign-turn-slight-left::before { content: "\f834"; } -.bi-sign-turn-slight-right-fill::before { content: "\f835"; } -.bi-sign-turn-slight-right::before { content: "\f836"; } -.bi-sign-yield-fill::before { content: "\f837"; } -.bi-sign-yield::before { content: "\f838"; } -.bi-ev-station-fill::before { content: "\f839"; } -.bi-ev-station::before { content: "\f83a"; } -.bi-fuel-pump-diesel-fill::before { content: "\f83b"; } -.bi-fuel-pump-diesel::before { content: "\f83c"; } -.bi-fuel-pump-fill::before { content: "\f83d"; } -.bi-fuel-pump::before { content: "\f83e"; } -.bi-0-circle-fill::before { content: "\f83f"; } -.bi-0-circle::before { content: "\f840"; } -.bi-0-square-fill::before { content: "\f841"; } -.bi-0-square::before { content: "\f842"; } -.bi-rocket-fill::before { content: "\f843"; } -.bi-rocket-takeoff-fill::before { content: "\f844"; } -.bi-rocket-takeoff::before { content: "\f845"; } -.bi-rocket::before { content: "\f846"; } -.bi-stripe::before { content: "\f847"; } -.bi-subscript::before { content: "\f848"; } -.bi-superscript::before { content: "\f849"; } -.bi-trello::before { content: "\f84a"; } -.bi-envelope-at-fill::before { content: "\f84b"; } -.bi-envelope-at::before { content: "\f84c"; } -.bi-regex::before { content: "\f84d"; } -.bi-text-wrap::before { content: "\f84e"; } -.bi-sign-dead-end-fill::before { content: "\f84f"; } -.bi-sign-dead-end::before { content: "\f850"; } -.bi-sign-do-not-enter-fill::before { content: "\f851"; } -.bi-sign-do-not-enter::before { content: "\f852"; } -.bi-sign-intersection-fill::before { content: "\f853"; } -.bi-sign-intersection-side-fill::before { content: "\f854"; } -.bi-sign-intersection-side::before { content: "\f855"; } -.bi-sign-intersection-t-fill::before { content: "\f856"; } -.bi-sign-intersection-t::before { content: "\f857"; } -.bi-sign-intersection-y-fill::before { content: "\f858"; } -.bi-sign-intersection-y::before { content: "\f859"; } -.bi-sign-intersection::before { content: "\f85a"; } -.bi-sign-merge-left-fill::before { content: "\f85b"; } -.bi-sign-merge-left::before { content: "\f85c"; } -.bi-sign-merge-right-fill::before { content: "\f85d"; } -.bi-sign-merge-right::before { content: "\f85e"; } -.bi-sign-no-left-turn-fill::before { content: "\f85f"; } -.bi-sign-no-left-turn::before { content: "\f860"; } -.bi-sign-no-parking-fill::before { content: "\f861"; } -.bi-sign-no-parking::before { content: "\f862"; } -.bi-sign-no-right-turn-fill::before { content: "\f863"; } -.bi-sign-no-right-turn::before { content: "\f864"; } -.bi-sign-railroad-fill::before { content: "\f865"; } -.bi-sign-railroad::before { content: "\f866"; } -.bi-building-add::before { content: "\f867"; } -.bi-building-check::before { content: "\f868"; } -.bi-building-dash::before { content: "\f869"; } -.bi-building-down::before { content: "\f86a"; } -.bi-building-exclamation::before { content: "\f86b"; } -.bi-building-fill-add::before { content: "\f86c"; } -.bi-building-fill-check::before { content: "\f86d"; } -.bi-building-fill-dash::before { content: "\f86e"; } -.bi-building-fill-down::before { content: "\f86f"; } -.bi-building-fill-exclamation::before { content: "\f870"; } -.bi-building-fill-gear::before { content: "\f871"; } -.bi-building-fill-lock::before { content: "\f872"; } -.bi-building-fill-slash::before { content: "\f873"; } -.bi-building-fill-up::before { content: "\f874"; } -.bi-building-fill-x::before { content: "\f875"; } -.bi-building-fill::before { content: "\f876"; } -.bi-building-gear::before { content: "\f877"; } -.bi-building-lock::before { content: "\f878"; } -.bi-building-slash::before { content: "\f879"; } -.bi-building-up::before { content: "\f87a"; } -.bi-building-x::before { content: "\f87b"; } -.bi-buildings-fill::before { content: "\f87c"; } -.bi-buildings::before { content: "\f87d"; } -.bi-bus-front-fill::before { content: "\f87e"; } -.bi-bus-front::before { content: "\f87f"; } -.bi-ev-front-fill::before { content: "\f880"; } -.bi-ev-front::before { content: "\f881"; } -.bi-globe-americas::before { content: "\f882"; } -.bi-globe-asia-australia::before { content: "\f883"; } -.bi-globe-central-south-asia::before { content: "\f884"; } -.bi-globe-europe-africa::before { content: "\f885"; } -.bi-house-add-fill::before { content: "\f886"; } -.bi-house-add::before { content: "\f887"; } -.bi-house-check-fill::before { content: "\f888"; } -.bi-house-check::before { content: "\f889"; } -.bi-house-dash-fill::before { content: "\f88a"; } -.bi-house-dash::before { content: "\f88b"; } -.bi-house-down-fill::before { content: "\f88c"; } -.bi-house-down::before { content: "\f88d"; } -.bi-house-exclamation-fill::before { content: "\f88e"; } -.bi-house-exclamation::before { content: "\f88f"; } -.bi-house-gear-fill::before { content: "\f890"; } -.bi-house-gear::before { content: "\f891"; } -.bi-house-lock-fill::before { content: "\f892"; } -.bi-house-lock::before { content: "\f893"; } -.bi-house-slash-fill::before { content: "\f894"; } -.bi-house-slash::before { content: "\f895"; } -.bi-house-up-fill::before { content: "\f896"; } -.bi-house-up::before { content: "\f897"; } -.bi-house-x-fill::before { content: "\f898"; } -.bi-house-x::before { content: "\f899"; } -.bi-person-add::before { content: "\f89a"; } -.bi-person-down::before { content: "\f89b"; } -.bi-person-exclamation::before { content: "\f89c"; } -.bi-person-fill-add::before { content: "\f89d"; } -.bi-person-fill-check::before { content: "\f89e"; } -.bi-person-fill-dash::before { content: "\f89f"; } -.bi-person-fill-down::before { content: "\f8a0"; } -.bi-person-fill-exclamation::before { content: "\f8a1"; } -.bi-person-fill-gear::before { content: "\f8a2"; } -.bi-person-fill-lock::before { content: "\f8a3"; } -.bi-person-fill-slash::before { content: "\f8a4"; } -.bi-person-fill-up::before { content: "\f8a5"; } -.bi-person-fill-x::before { content: "\f8a6"; } -.bi-person-gear::before { content: "\f8a7"; } -.bi-person-lock::before { content: "\f8a8"; } -.bi-person-slash::before { content: "\f8a9"; } -.bi-person-up::before { content: "\f8aa"; } -.bi-scooter::before { content: "\f8ab"; } -.bi-taxi-front-fill::before { content: "\f8ac"; } -.bi-taxi-front::before { content: "\f8ad"; } -.bi-amd::before { content: "\f8ae"; } -.bi-database-add::before { content: "\f8af"; } -.bi-database-check::before { content: "\f8b0"; } -.bi-database-dash::before { content: "\f8b1"; } -.bi-database-down::before { content: "\f8b2"; } -.bi-database-exclamation::before { content: "\f8b3"; } -.bi-database-fill-add::before { content: "\f8b4"; } -.bi-database-fill-check::before { content: "\f8b5"; } -.bi-database-fill-dash::before { content: "\f8b6"; } -.bi-database-fill-down::before { content: "\f8b7"; } -.bi-database-fill-exclamation::before { content: "\f8b8"; } -.bi-database-fill-gear::before { content: "\f8b9"; } -.bi-database-fill-lock::before { content: "\f8ba"; } -.bi-database-fill-slash::before { content: "\f8bb"; } -.bi-database-fill-up::before { content: "\f8bc"; } -.bi-database-fill-x::before { content: "\f8bd"; } -.bi-database-fill::before { content: "\f8be"; } -.bi-database-gear::before { content: "\f8bf"; } -.bi-database-lock::before { content: "\f8c0"; } -.bi-database-slash::before { content: "\f8c1"; } -.bi-database-up::before { content: "\f8c2"; } -.bi-database-x::before { content: "\f8c3"; } -.bi-database::before { content: "\f8c4"; } -.bi-houses-fill::before { content: "\f8c5"; } -.bi-houses::before { content: "\f8c6"; } -.bi-nvidia::before { content: "\f8c7"; } -.bi-person-vcard-fill::before { content: "\f8c8"; } -.bi-person-vcard::before { content: "\f8c9"; } -.bi-sina-weibo::before { content: "\f8ca"; } -.bi-tencent-qq::before { content: "\f8cb"; } -.bi-wikipedia::before { content: "\f8cc"; } -.bi-alphabet-uppercase::before { content: "\f2a5"; } -.bi-alphabet::before { content: "\f68a"; } -.bi-amazon::before { content: "\f68d"; } -.bi-arrows-collapse-vertical::before { content: "\f690"; } -.bi-arrows-expand-vertical::before { content: "\f695"; } -.bi-arrows-vertical::before { content: "\f698"; } -.bi-arrows::before { content: "\f6a2"; } -.bi-ban-fill::before { content: "\f6a3"; } -.bi-ban::before { content: "\f6b6"; } -.bi-bing::before { content: "\f6c2"; } -.bi-cake::before { content: "\f6e0"; } -.bi-cake2::before { content: "\f6ed"; } -.bi-cookie::before { content: "\f6ee"; } -.bi-copy::before { content: "\f759"; } -.bi-crosshair::before { content: "\f769"; } -.bi-crosshair2::before { content: "\f794"; } -.bi-emoji-astonished-fill::before { content: "\f795"; } -.bi-emoji-astonished::before { content: "\f79a"; } -.bi-emoji-grimace-fill::before { content: "\f79b"; } -.bi-emoji-grimace::before { content: "\f7a0"; } -.bi-emoji-grin-fill::before { content: "\f7a1"; } -.bi-emoji-grin::before { content: "\f7a6"; } -.bi-emoji-surprise-fill::before { content: "\f7a7"; } -.bi-emoji-surprise::before { content: "\f7ac"; } -.bi-emoji-tear-fill::before { content: "\f7ad"; } -.bi-emoji-tear::before { content: "\f7b2"; } -.bi-envelope-arrow-down-fill::before { content: "\f7b3"; } -.bi-envelope-arrow-down::before { content: "\f7b8"; } -.bi-envelope-arrow-up-fill::before { content: "\f7b9"; } -.bi-envelope-arrow-up::before { content: "\f7be"; } -.bi-feather::before { content: "\f7bf"; } -.bi-feather2::before { content: "\f7c4"; } -.bi-floppy-fill::before { content: "\f7c5"; } -.bi-floppy::before { content: "\f7d8"; } -.bi-floppy2-fill::before { content: "\f7d9"; } -.bi-floppy2::before { content: "\f7e4"; } -.bi-gitlab::before { content: "\f7e5"; } -.bi-highlighter::before { content: "\f7f8"; } -.bi-marker-tip::before { content: "\f802"; } -.bi-nvme-fill::before { content: "\f803"; } -.bi-nvme::before { content: "\f80c"; } -.bi-opencollective::before { content: "\f80d"; } -.bi-pci-card-network::before { content: "\f8cd"; } -.bi-pci-card-sound::before { content: "\f8ce"; } -.bi-radar::before { content: "\f8cf"; } -.bi-send-arrow-down-fill::before { content: "\f8d0"; } -.bi-send-arrow-down::before { content: "\f8d1"; } -.bi-send-arrow-up-fill::before { content: "\f8d2"; } -.bi-send-arrow-up::before { content: "\f8d3"; } -.bi-sim-slash-fill::before { content: "\f8d4"; } -.bi-sim-slash::before { content: "\f8d5"; } -.bi-sourceforge::before { content: "\f8d6"; } -.bi-substack::before { content: "\f8d7"; } -.bi-threads-fill::before { content: "\f8d8"; } -.bi-threads::before { content: "\f8d9"; } -.bi-transparency::before { content: "\f8da"; } -.bi-twitter-x::before { content: "\f8db"; } -.bi-type-h4::before { content: "\f8dc"; } -.bi-type-h5::before { content: "\f8dd"; } -.bi-type-h6::before { content: "\f8de"; } -.bi-backpack-fill::before { content: "\f8df"; } -.bi-backpack::before { content: "\f8e0"; } -.bi-backpack2-fill::before { content: "\f8e1"; } -.bi-backpack2::before { content: "\f8e2"; } -.bi-backpack3-fill::before { content: "\f8e3"; } -.bi-backpack3::before { content: "\f8e4"; } -.bi-backpack4-fill::before { content: "\f8e5"; } -.bi-backpack4::before { content: "\f8e6"; } -.bi-brilliance::before { content: "\f8e7"; } -.bi-cake-fill::before { content: "\f8e8"; } -.bi-cake2-fill::before { content: "\f8e9"; } -.bi-duffle-fill::before { content: "\f8ea"; } -.bi-duffle::before { content: "\f8eb"; } -.bi-exposure::before { content: "\f8ec"; } -.bi-gender-neuter::before { content: "\f8ed"; } -.bi-highlights::before { content: "\f8ee"; } -.bi-luggage-fill::before { content: "\f8ef"; } -.bi-luggage::before { content: "\f8f0"; } -.bi-mailbox-flag::before { content: "\f8f1"; } -.bi-mailbox2-flag::before { content: "\f8f2"; } -.bi-noise-reduction::before { content: "\f8f3"; } -.bi-passport-fill::before { content: "\f8f4"; } -.bi-passport::before { content: "\f8f5"; } -.bi-person-arms-up::before { content: "\f8f6"; } -.bi-person-raised-hand::before { content: "\f8f7"; } -.bi-person-standing-dress::before { content: "\f8f8"; } -.bi-person-standing::before { content: "\f8f9"; } -.bi-person-walking::before { content: "\f8fa"; } -.bi-person-wheelchair::before { content: "\f8fb"; } -.bi-shadows::before { content: "\f8fc"; } -.bi-suitcase-fill::before { content: "\f8fd"; } -.bi-suitcase-lg-fill::before { content: "\f8fe"; } -.bi-suitcase-lg::before { content: "\f8ff"; } -.bi-suitcase::before { content: "\f900"; } -.bi-suitcase2-fill::before { content: "\f901"; } -.bi-suitcase2::before { content: "\f902"; } -.bi-vignette::before { content: "\f903"; } diff --git a/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/run_pecan_files/libs/bootstrap/bootstrap-icons.woff b/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/run_pecan_files/libs/bootstrap/bootstrap-icons.woff deleted file mode 100644 index dbeeb0556..000000000 Binary files a/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/run_pecan_files/libs/bootstrap/bootstrap-icons.woff and /dev/null differ diff --git a/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/run_pecan_files/libs/bootstrap/bootstrap.min.css b/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/run_pecan_files/libs/bootstrap/bootstrap.min.css deleted file mode 100644 index d6947f2ce..000000000 --- a/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/run_pecan_files/libs/bootstrap/bootstrap.min.css +++ /dev/null @@ -1,12 +0,0 @@ -/*! - * Bootstrap v5.3.1 (https://getbootstrap.com/) - * Copyright 2011-2023 The Bootstrap Authors - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) - */:root,[data-bs-theme=light]{--bs-blue: #0d6efd;--bs-indigo: #6610f2;--bs-purple: #6f42c1;--bs-pink: #d63384;--bs-red: #dc3545;--bs-orange: #fd7e14;--bs-yellow: #ffc107;--bs-green: #198754;--bs-teal: #20c997;--bs-cyan: #0dcaf0;--bs-black: #000;--bs-white: #ffffff;--bs-gray: #6c757d;--bs-gray-dark: #343a40;--bs-gray-100: #f8f9fa;--bs-gray-200: #e9ecef;--bs-gray-300: #dee2e6;--bs-gray-400: #ced4da;--bs-gray-500: #adb5bd;--bs-gray-600: #6c757d;--bs-gray-700: #495057;--bs-gray-800: #343a40;--bs-gray-900: #212529;--bs-default: #dee2e6;--bs-primary: #0d6efd;--bs-secondary: #6c757d;--bs-success: #198754;--bs-info: #0dcaf0;--bs-warning: #ffc107;--bs-danger: #dc3545;--bs-light: #f8f9fa;--bs-dark: #212529;--bs-default-rgb: 222, 226, 230;--bs-primary-rgb: 13, 110, 253;--bs-secondary-rgb: 108, 117, 125;--bs-success-rgb: 25, 135, 84;--bs-info-rgb: 13, 202, 240;--bs-warning-rgb: 255, 193, 7;--bs-danger-rgb: 220, 53, 69;--bs-light-rgb: 248, 249, 250;--bs-dark-rgb: 33, 37, 41;--bs-primary-text-emphasis: #052c65;--bs-secondary-text-emphasis: #2b2f32;--bs-success-text-emphasis: #0a3622;--bs-info-text-emphasis: #055160;--bs-warning-text-emphasis: #664d03;--bs-danger-text-emphasis: #58151c;--bs-light-text-emphasis: #495057;--bs-dark-text-emphasis: #495057;--bs-primary-bg-subtle: #cfe2ff;--bs-secondary-bg-subtle: #e2e3e5;--bs-success-bg-subtle: #d1e7dd;--bs-info-bg-subtle: #cff4fc;--bs-warning-bg-subtle: #fff3cd;--bs-danger-bg-subtle: #f8d7da;--bs-light-bg-subtle: #fcfcfd;--bs-dark-bg-subtle: #ced4da;--bs-primary-border-subtle: #9ec5fe;--bs-secondary-border-subtle: #c4c8cb;--bs-success-border-subtle: #a3cfbb;--bs-info-border-subtle: #9eeaf9;--bs-warning-border-subtle: #ffe69c;--bs-danger-border-subtle: #f1aeb5;--bs-light-border-subtle: #e9ecef;--bs-dark-border-subtle: #adb5bd;--bs-white-rgb: 255, 255, 255;--bs-black-rgb: 0, 0, 0;--bs-font-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));--bs-root-font-size: 17px;--bs-body-font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--bs-body-font-size:1rem;--bs-body-font-weight: 400;--bs-body-line-height: 1.5;--bs-body-color: #212529;--bs-body-color-rgb: 33, 37, 41;--bs-body-bg: #ffffff;--bs-body-bg-rgb: 255, 255, 255;--bs-emphasis-color: #000;--bs-emphasis-color-rgb: 0, 0, 0;--bs-secondary-color: rgba(33, 37, 41, 0.75);--bs-secondary-color-rgb: 33, 37, 41;--bs-secondary-bg: #e9ecef;--bs-secondary-bg-rgb: 233, 236, 239;--bs-tertiary-color: rgba(33, 37, 41, 0.5);--bs-tertiary-color-rgb: 33, 37, 41;--bs-tertiary-bg: #f8f9fa;--bs-tertiary-bg-rgb: 248, 249, 250;--bs-heading-color: inherit;--bs-link-color: #0d6efd;--bs-link-color-rgb: 13, 110, 253;--bs-link-decoration: underline;--bs-link-hover-color: #0a58ca;--bs-link-hover-color-rgb: 10, 88, 202;--bs-code-color: #7d12ba;--bs-highlight-bg: #fff3cd;--bs-border-width: 1px;--bs-border-style: solid;--bs-border-color: #dee2e6;--bs-border-color-translucent: rgba(0, 0, 0, 0.175);--bs-border-radius: 0.375rem;--bs-border-radius-sm: 0.25rem;--bs-border-radius-lg: 0.5rem;--bs-border-radius-xl: 1rem;--bs-border-radius-xxl: 2rem;--bs-border-radius-2xl: var(--bs-border-radius-xxl);--bs-border-radius-pill: 50rem;--bs-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);--bs-box-shadow-sm: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);--bs-box-shadow-lg: 0 1rem 3rem rgba(0, 0, 0, 0.175);--bs-box-shadow-inset: inset 0 1px 2px rgba(0, 0, 0, 0.075);--bs-focus-ring-width: 0.25rem;--bs-focus-ring-opacity: 0.25;--bs-focus-ring-color: rgba(13, 110, 253, 0.25);--bs-form-valid-color: #198754;--bs-form-valid-border-color: #198754;--bs-form-invalid-color: #dc3545;--bs-form-invalid-border-color: #dc3545}[data-bs-theme=dark]{color-scheme:dark;--bs-body-color: #dee2e6;--bs-body-color-rgb: 222, 226, 230;--bs-body-bg: #212529;--bs-body-bg-rgb: 33, 37, 41;--bs-emphasis-color: #ffffff;--bs-emphasis-color-rgb: 255, 255, 255;--bs-secondary-color: rgba(222, 226, 230, 0.75);--bs-secondary-color-rgb: 222, 226, 230;--bs-secondary-bg: #343a40;--bs-secondary-bg-rgb: 52, 58, 64;--bs-tertiary-color: rgba(222, 226, 230, 0.5);--bs-tertiary-color-rgb: 222, 226, 230;--bs-tertiary-bg: #2b3035;--bs-tertiary-bg-rgb: 43, 48, 53;--bs-primary-text-emphasis: #6ea8fe;--bs-secondary-text-emphasis: #a7acb1;--bs-success-text-emphasis: #75b798;--bs-info-text-emphasis: #6edff6;--bs-warning-text-emphasis: #ffda6a;--bs-danger-text-emphasis: #ea868f;--bs-light-text-emphasis: #f8f9fa;--bs-dark-text-emphasis: #dee2e6;--bs-primary-bg-subtle: #031633;--bs-secondary-bg-subtle: #161719;--bs-success-bg-subtle: #051b11;--bs-info-bg-subtle: #032830;--bs-warning-bg-subtle: #332701;--bs-danger-bg-subtle: #2c0b0e;--bs-light-bg-subtle: #343a40;--bs-dark-bg-subtle: #1a1d20;--bs-primary-border-subtle: #084298;--bs-secondary-border-subtle: #41464b;--bs-success-border-subtle: #0f5132;--bs-info-border-subtle: #087990;--bs-warning-border-subtle: #997404;--bs-danger-border-subtle: #842029;--bs-light-border-subtle: #495057;--bs-dark-border-subtle: #343a40;--bs-heading-color: inherit;--bs-link-color: #6ea8fe;--bs-link-hover-color: #8bb9fe;--bs-link-color-rgb: 110, 168, 254;--bs-link-hover-color-rgb: 139, 185, 254;--bs-code-color: white;--bs-border-color: #495057;--bs-border-color-translucent: rgba(255, 255, 255, 0.15);--bs-form-valid-color: #75b798;--bs-form-valid-border-color: #75b798;--bs-form-invalid-color: #ea868f;--bs-form-invalid-border-color: #ea868f}*,*::before,*::after{box-sizing:border-box}:root{font-size:var(--bs-root-font-size)}body{margin:0;font-family:var(--bs-body-font-family);font-size:var(--bs-body-font-size);font-weight:var(--bs-body-font-weight);line-height:var(--bs-body-line-height);color:var(--bs-body-color);text-align:var(--bs-body-text-align);background-color:var(--bs-body-bg);-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:rgba(0,0,0,0)}hr{margin:1rem 0;color:inherit;border:0;border-top:1px solid;opacity:.25}h6,.h6,h5,.h5,h4,.h4,h3,.h3,h2,.h2,h1,.h1{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2;color:var(--bs-heading-color)}h1,.h1{font-size:calc(1.325rem + 0.9vw)}@media(min-width: 1200px){h1,.h1{font-size:2rem}}h2,.h2{font-size:calc(1.29rem + 0.48vw)}@media(min-width: 1200px){h2,.h2{font-size:1.65rem}}h3,.h3{font-size:calc(1.27rem + 0.24vw)}@media(min-width: 1200px){h3,.h3{font-size:1.45rem}}h4,.h4{font-size:1.25rem}h5,.h5{font-size:1.1rem}h6,.h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[title]{text-decoration:underline dotted;-webkit-text-decoration:underline dotted;-moz-text-decoration:underline dotted;-ms-text-decoration:underline dotted;-o-text-decoration:underline dotted;cursor:help;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}ol,ul,dl{margin-top:0;margin-bottom:1rem}ol ol,ul ul,ol ul,ul ol{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem;padding:.625rem 1.25rem;border-left:.25rem solid #e9ecef}blockquote p:last-child,blockquote ul:last-child,blockquote ol:last-child{margin-bottom:0}b,strong{font-weight:bolder}small,.small{font-size:0.875em}mark,.mark{padding:.1875em;background-color:var(--bs-highlight-bg)}sub,sup{position:relative;font-size:0.75em;line-height:0;vertical-align:baseline}sub{bottom:-0.25em}sup{top:-0.5em}a{color:rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 1));text-decoration:underline;-webkit-text-decoration:underline;-moz-text-decoration:underline;-ms-text-decoration:underline;-o-text-decoration:underline}a:hover{--bs-link-color-rgb: var(--bs-link-hover-color-rgb)}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}pre,code,kbd,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:0.875em;color:#000;background-color:#f8f9fa;padding:.5rem;border:1px solid var(--bs-border-color, #dee2e6);border-radius:.375rem}pre code{background-color:rgba(0,0,0,0);font-size:inherit;color:inherit;word-break:normal}code{font-size:0.875em;color:var(--bs-code-color);background-color:#f8f9fa;border-radius:.375rem;padding:.125rem .25rem;word-wrap:break-word}a>code{color:inherit}kbd{padding:.4rem .4rem;font-size:0.875em;color:#fff;background-color:#212529;border-radius:.25rem}kbd kbd{padding:0;font-size:1em}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:rgba(33,37,41,.75);text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}thead,tbody,tfoot,tr,td,th{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}input,button,select,optgroup,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]:not([type=date]):not([type=datetime-local]):not([type=month]):not([type=week]):not([type=time])::-webkit-calendar-picker-indicator{display:none !important}button,[type=button],[type=reset],[type=submit]{-webkit-appearance:button}button:not(:disabled),[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:left;width:100%;padding:0;margin-bottom:.5rem;font-size:calc(1.275rem + 0.3vw);line-height:inherit}@media(min-width: 1200px){legend{font-size:1.5rem}}legend+*{clear:left}::-webkit-datetime-edit-fields-wrapper,::-webkit-datetime-edit-text,::-webkit-datetime-edit-minute,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-year-field{padding:0}::-webkit-inner-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::file-selector-button{font:inherit;-webkit-appearance:button}output{display:inline-block}iframe{border:0}summary{display:list-item;cursor:pointer}progress{vertical-align:baseline}[hidden]{display:none !important}.lead{font-size:1.25rem;font-weight:300}.display-1{font-size:calc(1.625rem + 4.5vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-1{font-size:5rem}}.display-2{font-size:calc(1.575rem + 3.9vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-2{font-size:4.5rem}}.display-3{font-size:calc(1.525rem + 3.3vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-3{font-size:4rem}}.display-4{font-size:calc(1.475rem + 2.7vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-4{font-size:3.5rem}}.display-5{font-size:calc(1.425rem + 2.1vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-5{font-size:3rem}}.display-6{font-size:calc(1.375rem + 1.5vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-6{font-size:2.5rem}}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:.5rem}.initialism{font-size:0.875em;text-transform:uppercase}.blockquote{margin-bottom:1rem;font-size:1.25rem}.blockquote>:last-child{margin-bottom:0}.blockquote-footer{margin-top:-1rem;margin-bottom:1rem;font-size:0.875em;color:#6c757d}.blockquote-footer::before{content:"— "}.img-fluid{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:#fff;border:1px solid #dee2e6;border-radius:.375rem;max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:0.875em;color:rgba(33,37,41,.75)}.container,.container-fluid,.container-xxl,.container-xl,.container-lg,.container-md,.container-sm{--bs-gutter-x: 1.5rem;--bs-gutter-y: 0;width:100%;padding-right:calc(var(--bs-gutter-x)*.5);padding-left:calc(var(--bs-gutter-x)*.5);margin-right:auto;margin-left:auto}@media(min-width: 576px){.container-sm,.container{max-width:540px}}@media(min-width: 768px){.container-md,.container-sm,.container{max-width:720px}}@media(min-width: 992px){.container-lg,.container-md,.container-sm,.container{max-width:960px}}@media(min-width: 1200px){.container-xl,.container-lg,.container-md,.container-sm,.container{max-width:1140px}}@media(min-width: 1400px){.container-xxl,.container-xl,.container-lg,.container-md,.container-sm,.container{max-width:1320px}}:root{--bs-breakpoint-xs: 0;--bs-breakpoint-sm: 576px;--bs-breakpoint-md: 768px;--bs-breakpoint-lg: 992px;--bs-breakpoint-xl: 1200px;--bs-breakpoint-xxl: 1400px}.grid{display:grid;grid-template-rows:repeat(var(--bs-rows, 1), 1fr);grid-template-columns:repeat(var(--bs-columns, 12), 1fr);gap:var(--bs-gap, 1.5rem)}.grid .g-col-1{grid-column:auto/span 1}.grid .g-col-2{grid-column:auto/span 2}.grid .g-col-3{grid-column:auto/span 3}.grid .g-col-4{grid-column:auto/span 4}.grid .g-col-5{grid-column:auto/span 5}.grid .g-col-6{grid-column:auto/span 6}.grid .g-col-7{grid-column:auto/span 7}.grid .g-col-8{grid-column:auto/span 8}.grid .g-col-9{grid-column:auto/span 9}.grid .g-col-10{grid-column:auto/span 10}.grid .g-col-11{grid-column:auto/span 11}.grid .g-col-12{grid-column:auto/span 12}.grid .g-start-1{grid-column-start:1}.grid .g-start-2{grid-column-start:2}.grid .g-start-3{grid-column-start:3}.grid .g-start-4{grid-column-start:4}.grid .g-start-5{grid-column-start:5}.grid .g-start-6{grid-column-start:6}.grid .g-start-7{grid-column-start:7}.grid .g-start-8{grid-column-start:8}.grid .g-start-9{grid-column-start:9}.grid .g-start-10{grid-column-start:10}.grid .g-start-11{grid-column-start:11}@media(min-width: 576px){.grid .g-col-sm-1{grid-column:auto/span 1}.grid .g-col-sm-2{grid-column:auto/span 2}.grid .g-col-sm-3{grid-column:auto/span 3}.grid .g-col-sm-4{grid-column:auto/span 4}.grid .g-col-sm-5{grid-column:auto/span 5}.grid .g-col-sm-6{grid-column:auto/span 6}.grid .g-col-sm-7{grid-column:auto/span 7}.grid .g-col-sm-8{grid-column:auto/span 8}.grid .g-col-sm-9{grid-column:auto/span 9}.grid .g-col-sm-10{grid-column:auto/span 10}.grid .g-col-sm-11{grid-column:auto/span 11}.grid .g-col-sm-12{grid-column:auto/span 12}.grid .g-start-sm-1{grid-column-start:1}.grid .g-start-sm-2{grid-column-start:2}.grid .g-start-sm-3{grid-column-start:3}.grid .g-start-sm-4{grid-column-start:4}.grid .g-start-sm-5{grid-column-start:5}.grid .g-start-sm-6{grid-column-start:6}.grid .g-start-sm-7{grid-column-start:7}.grid .g-start-sm-8{grid-column-start:8}.grid .g-start-sm-9{grid-column-start:9}.grid .g-start-sm-10{grid-column-start:10}.grid .g-start-sm-11{grid-column-start:11}}@media(min-width: 768px){.grid .g-col-md-1{grid-column:auto/span 1}.grid .g-col-md-2{grid-column:auto/span 2}.grid .g-col-md-3{grid-column:auto/span 3}.grid .g-col-md-4{grid-column:auto/span 4}.grid .g-col-md-5{grid-column:auto/span 5}.grid .g-col-md-6{grid-column:auto/span 6}.grid .g-col-md-7{grid-column:auto/span 7}.grid .g-col-md-8{grid-column:auto/span 8}.grid .g-col-md-9{grid-column:auto/span 9}.grid .g-col-md-10{grid-column:auto/span 10}.grid .g-col-md-11{grid-column:auto/span 11}.grid .g-col-md-12{grid-column:auto/span 12}.grid .g-start-md-1{grid-column-start:1}.grid .g-start-md-2{grid-column-start:2}.grid .g-start-md-3{grid-column-start:3}.grid .g-start-md-4{grid-column-start:4}.grid .g-start-md-5{grid-column-start:5}.grid .g-start-md-6{grid-column-start:6}.grid .g-start-md-7{grid-column-start:7}.grid .g-start-md-8{grid-column-start:8}.grid .g-start-md-9{grid-column-start:9}.grid .g-start-md-10{grid-column-start:10}.grid .g-start-md-11{grid-column-start:11}}@media(min-width: 992px){.grid .g-col-lg-1{grid-column:auto/span 1}.grid .g-col-lg-2{grid-column:auto/span 2}.grid .g-col-lg-3{grid-column:auto/span 3}.grid .g-col-lg-4{grid-column:auto/span 4}.grid .g-col-lg-5{grid-column:auto/span 5}.grid .g-col-lg-6{grid-column:auto/span 6}.grid .g-col-lg-7{grid-column:auto/span 7}.grid .g-col-lg-8{grid-column:auto/span 8}.grid .g-col-lg-9{grid-column:auto/span 9}.grid .g-col-lg-10{grid-column:auto/span 10}.grid .g-col-lg-11{grid-column:auto/span 11}.grid .g-col-lg-12{grid-column:auto/span 12}.grid .g-start-lg-1{grid-column-start:1}.grid .g-start-lg-2{grid-column-start:2}.grid .g-start-lg-3{grid-column-start:3}.grid .g-start-lg-4{grid-column-start:4}.grid .g-start-lg-5{grid-column-start:5}.grid .g-start-lg-6{grid-column-start:6}.grid .g-start-lg-7{grid-column-start:7}.grid .g-start-lg-8{grid-column-start:8}.grid .g-start-lg-9{grid-column-start:9}.grid .g-start-lg-10{grid-column-start:10}.grid .g-start-lg-11{grid-column-start:11}}@media(min-width: 1200px){.grid .g-col-xl-1{grid-column:auto/span 1}.grid .g-col-xl-2{grid-column:auto/span 2}.grid .g-col-xl-3{grid-column:auto/span 3}.grid .g-col-xl-4{grid-column:auto/span 4}.grid .g-col-xl-5{grid-column:auto/span 5}.grid .g-col-xl-6{grid-column:auto/span 6}.grid .g-col-xl-7{grid-column:auto/span 7}.grid .g-col-xl-8{grid-column:auto/span 8}.grid .g-col-xl-9{grid-column:auto/span 9}.grid .g-col-xl-10{grid-column:auto/span 10}.grid .g-col-xl-11{grid-column:auto/span 11}.grid .g-col-xl-12{grid-column:auto/span 12}.grid .g-start-xl-1{grid-column-start:1}.grid .g-start-xl-2{grid-column-start:2}.grid .g-start-xl-3{grid-column-start:3}.grid .g-start-xl-4{grid-column-start:4}.grid .g-start-xl-5{grid-column-start:5}.grid .g-start-xl-6{grid-column-start:6}.grid .g-start-xl-7{grid-column-start:7}.grid .g-start-xl-8{grid-column-start:8}.grid .g-start-xl-9{grid-column-start:9}.grid .g-start-xl-10{grid-column-start:10}.grid .g-start-xl-11{grid-column-start:11}}@media(min-width: 1400px){.grid .g-col-xxl-1{grid-column:auto/span 1}.grid .g-col-xxl-2{grid-column:auto/span 2}.grid .g-col-xxl-3{grid-column:auto/span 3}.grid .g-col-xxl-4{grid-column:auto/span 4}.grid .g-col-xxl-5{grid-column:auto/span 5}.grid .g-col-xxl-6{grid-column:auto/span 6}.grid .g-col-xxl-7{grid-column:auto/span 7}.grid .g-col-xxl-8{grid-column:auto/span 8}.grid .g-col-xxl-9{grid-column:auto/span 9}.grid .g-col-xxl-10{grid-column:auto/span 10}.grid .g-col-xxl-11{grid-column:auto/span 11}.grid .g-col-xxl-12{grid-column:auto/span 12}.grid .g-start-xxl-1{grid-column-start:1}.grid .g-start-xxl-2{grid-column-start:2}.grid .g-start-xxl-3{grid-column-start:3}.grid .g-start-xxl-4{grid-column-start:4}.grid .g-start-xxl-5{grid-column-start:5}.grid .g-start-xxl-6{grid-column-start:6}.grid .g-start-xxl-7{grid-column-start:7}.grid .g-start-xxl-8{grid-column-start:8}.grid .g-start-xxl-9{grid-column-start:9}.grid .g-start-xxl-10{grid-column-start:10}.grid .g-start-xxl-11{grid-column-start:11}}.table{--bs-table-color-type: initial;--bs-table-bg-type: initial;--bs-table-color-state: initial;--bs-table-bg-state: initial;--bs-table-color: #212529;--bs-table-bg: #ffffff;--bs-table-border-color: #dee2e6;--bs-table-accent-bg: transparent;--bs-table-striped-color: #212529;--bs-table-striped-bg: rgba(0, 0, 0, 0.05);--bs-table-active-color: #212529;--bs-table-active-bg: rgba(0, 0, 0, 0.1);--bs-table-hover-color: #212529;--bs-table-hover-bg: rgba(0, 0, 0, 0.075);width:100%;margin-bottom:1rem;vertical-align:top;border-color:var(--bs-table-border-color)}.table>:not(caption)>*>*{padding:.5rem .5rem;color:var(--bs-table-color-state, var(--bs-table-color-type, var(--bs-table-color)));background-color:var(--bs-table-bg);border-bottom-width:1px;box-shadow:inset 0 0 0 9999px var(--bs-table-bg-state, var(--bs-table-bg-type, var(--bs-table-accent-bg)))}.table>tbody{vertical-align:inherit}.table>thead{vertical-align:bottom}.table-group-divider{border-top:calc(1px*2) solid #9ba5ae}.caption-top{caption-side:top}.table-sm>:not(caption)>*>*{padding:.25rem .25rem}.table-bordered>:not(caption)>*{border-width:1px 0}.table-bordered>:not(caption)>*>*{border-width:0 1px}.table-borderless>:not(caption)>*>*{border-bottom-width:0}.table-borderless>:not(:first-child){border-top-width:0}.table-striped>tbody>tr:nth-of-type(odd)>*{--bs-table-color-type: var(--bs-table-striped-color);--bs-table-bg-type: var(--bs-table-striped-bg)}.table-striped-columns>:not(caption)>tr>:nth-child(even){--bs-table-color-type: var(--bs-table-striped-color);--bs-table-bg-type: var(--bs-table-striped-bg)}.table-active{--bs-table-color-state: var(--bs-table-active-color);--bs-table-bg-state: var(--bs-table-active-bg)}.table-hover>tbody>tr:hover>*{--bs-table-color-state: var(--bs-table-hover-color);--bs-table-bg-state: var(--bs-table-hover-bg)}.table-primary{--bs-table-color: #000;--bs-table-bg: #cfe2ff;--bs-table-border-color: #bacbe6;--bs-table-striped-bg: #c5d7f2;--bs-table-striped-color: #000;--bs-table-active-bg: #bacbe6;--bs-table-active-color: #000;--bs-table-hover-bg: #bfd1ec;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-secondary{--bs-table-color: #000;--bs-table-bg: #e2e3e5;--bs-table-border-color: #cbccce;--bs-table-striped-bg: #d7d8da;--bs-table-striped-color: #000;--bs-table-active-bg: #cbccce;--bs-table-active-color: #000;--bs-table-hover-bg: #d1d2d4;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-success{--bs-table-color: #000;--bs-table-bg: #d1e7dd;--bs-table-border-color: #bcd0c7;--bs-table-striped-bg: #c7dbd2;--bs-table-striped-color: #000;--bs-table-active-bg: #bcd0c7;--bs-table-active-color: #000;--bs-table-hover-bg: #c1d6cc;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-info{--bs-table-color: #000;--bs-table-bg: #cff4fc;--bs-table-border-color: #badce3;--bs-table-striped-bg: #c5e8ef;--bs-table-striped-color: #000;--bs-table-active-bg: #badce3;--bs-table-active-color: #000;--bs-table-hover-bg: #bfe2e9;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-warning{--bs-table-color: #000;--bs-table-bg: #fff3cd;--bs-table-border-color: #e6dbb9;--bs-table-striped-bg: #f2e7c3;--bs-table-striped-color: #000;--bs-table-active-bg: #e6dbb9;--bs-table-active-color: #000;--bs-table-hover-bg: #ece1be;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-danger{--bs-table-color: #000;--bs-table-bg: #f8d7da;--bs-table-border-color: #dfc2c4;--bs-table-striped-bg: #eccccf;--bs-table-striped-color: #000;--bs-table-active-bg: #dfc2c4;--bs-table-active-color: #000;--bs-table-hover-bg: #e5c7ca;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-light{--bs-table-color: #000;--bs-table-bg: #f8f9fa;--bs-table-border-color: #dfe0e1;--bs-table-striped-bg: #ecedee;--bs-table-striped-color: #000;--bs-table-active-bg: #dfe0e1;--bs-table-active-color: #000;--bs-table-hover-bg: #e5e6e7;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-dark{--bs-table-color: #ffffff;--bs-table-bg: #212529;--bs-table-border-color: #373b3e;--bs-table-striped-bg: #2c3034;--bs-table-striped-color: #ffffff;--bs-table-active-bg: #373b3e;--bs-table-active-color: #ffffff;--bs-table-hover-bg: #323539;--bs-table-hover-color: #ffffff;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-responsive{overflow-x:auto;-webkit-overflow-scrolling:touch}@media(max-width: 575.98px){.table-responsive-sm{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media(max-width: 767.98px){.table-responsive-md{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media(max-width: 991.98px){.table-responsive-lg{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media(max-width: 1199.98px){.table-responsive-xl{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media(max-width: 1399.98px){.table-responsive-xxl{overflow-x:auto;-webkit-overflow-scrolling:touch}}.form-label,.shiny-input-container .control-label{margin-bottom:.5rem}.col-form-label{padding-top:calc(0.375rem + 1px);padding-bottom:calc(0.375rem + 1px);margin-bottom:0;font-size:inherit;line-height:1.5}.col-form-label-lg{padding-top:calc(0.5rem + 1px);padding-bottom:calc(0.5rem + 1px);font-size:1.25rem}.col-form-label-sm{padding-top:calc(0.25rem + 1px);padding-bottom:calc(0.25rem + 1px);font-size:0.875rem}.form-text{margin-top:.25rem;font-size:0.875em;color:rgba(33,37,41,.75)}.form-control{display:block;width:100%;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#212529;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none;background-color:#fff;background-clip:padding-box;border:1px solid #dee2e6;border-radius:.375rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.form-control{transition:none}}.form-control[type=file]{overflow:hidden}.form-control[type=file]:not(:disabled):not([readonly]){cursor:pointer}.form-control:focus{color:#212529;background-color:#fff;border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-control::-webkit-date-and-time-value{min-width:85px;height:1.5em;margin:0}.form-control::-webkit-datetime-edit{display:block;padding:0}.form-control::placeholder{color:rgba(33,37,41,.75);opacity:1}.form-control:disabled{background-color:#e9ecef;opacity:1}.form-control::file-selector-button{padding:.375rem .75rem;margin:-0.375rem -0.75rem;margin-inline-end:.75rem;color:#212529;background-color:#f8f9fa;pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:1px;border-radius:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.form-control::file-selector-button{transition:none}}.form-control:hover:not(:disabled):not([readonly])::file-selector-button{background-color:#e9ecef}.form-control-plaintext{display:block;width:100%;padding:.375rem 0;margin-bottom:0;line-height:1.5;color:#212529;background-color:rgba(0,0,0,0);border:solid rgba(0,0,0,0);border-width:1px 0}.form-control-plaintext:focus{outline:0}.form-control-plaintext.form-control-sm,.form-control-plaintext.form-control-lg{padding-right:0;padding-left:0}.form-control-sm{min-height:calc(1.5em + 0.5rem + calc(1px * 2));padding:.25rem .5rem;font-size:0.875rem;border-radius:.25rem}.form-control-sm::file-selector-button{padding:.25rem .5rem;margin:-0.25rem -0.5rem;margin-inline-end:.5rem}.form-control-lg{min-height:calc(1.5em + 1rem + calc(1px * 2));padding:.5rem 1rem;font-size:1.25rem;border-radius:.5rem}.form-control-lg::file-selector-button{padding:.5rem 1rem;margin:-0.5rem -1rem;margin-inline-end:1rem}textarea.form-control{min-height:calc(1.5em + 0.75rem + calc(1px * 2))}textarea.form-control-sm{min-height:calc(1.5em + 0.5rem + calc(1px * 2))}textarea.form-control-lg{min-height:calc(1.5em + 1rem + calc(1px * 2))}.form-control-color{width:3rem;height:calc(1.5em + 0.75rem + calc(1px * 2));padding:.375rem}.form-control-color:not(:disabled):not([readonly]){cursor:pointer}.form-control-color::-moz-color-swatch{border:0 !important;border-radius:.375rem}.form-control-color::-webkit-color-swatch{border:0 !important;border-radius:.375rem}.form-control-color.form-control-sm{height:calc(1.5em + 0.5rem + calc(1px * 2))}.form-control-color.form-control-lg{height:calc(1.5em + 1rem + calc(1px * 2))}.form-select{--bs-form-select-bg-img: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e");display:block;width:100%;padding:.375rem 2.25rem .375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#212529;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none;background-color:#fff;background-image:var(--bs-form-select-bg-img),var(--bs-form-select-bg-icon, none);background-repeat:no-repeat;background-position:right .75rem center;background-size:16px 12px;border:1px solid #dee2e6;border-radius:.375rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.form-select{transition:none}}.form-select:focus{border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-select[multiple],.form-select[size]:not([size="1"]){padding-right:.75rem;background-image:none}.form-select:disabled{background-color:#e9ecef}.form-select:-moz-focusring{color:rgba(0,0,0,0);text-shadow:0 0 0 #212529}.form-select-sm{padding-top:.25rem;padding-bottom:.25rem;padding-left:.5rem;font-size:0.875rem;border-radius:.25rem}.form-select-lg{padding-top:.5rem;padding-bottom:.5rem;padding-left:1rem;font-size:1.25rem;border-radius:.5rem}[data-bs-theme=dark] .form-select{--bs-form-select-bg-img: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23dee2e6' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e")}.form-check,.shiny-input-container .checkbox,.shiny-input-container .radio{display:block;min-height:1.5rem;padding-left:0;margin-bottom:.125rem}.form-check .form-check-input,.form-check .shiny-input-container .checkbox input,.form-check .shiny-input-container .radio input,.shiny-input-container .checkbox .form-check-input,.shiny-input-container .checkbox .shiny-input-container .checkbox input,.shiny-input-container .checkbox .shiny-input-container .radio input,.shiny-input-container .radio .form-check-input,.shiny-input-container .radio .shiny-input-container .checkbox input,.shiny-input-container .radio .shiny-input-container .radio input{float:left;margin-left:0}.form-check-reverse{padding-right:0;padding-left:0;text-align:right}.form-check-reverse .form-check-input{float:right;margin-right:0;margin-left:0}.form-check-input,.shiny-input-container .checkbox input,.shiny-input-container .checkbox-inline input,.shiny-input-container .radio input,.shiny-input-container .radio-inline input{--bs-form-check-bg: #ffffff;width:1em;height:1em;margin-top:.25em;vertical-align:top;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none;background-color:var(--bs-form-check-bg);background-image:var(--bs-form-check-bg-image);background-repeat:no-repeat;background-position:center;background-size:contain;border:1px solid #dee2e6;print-color-adjust:exact}.form-check-input[type=checkbox],.shiny-input-container .checkbox input[type=checkbox],.shiny-input-container .checkbox-inline input[type=checkbox],.shiny-input-container .radio input[type=checkbox],.shiny-input-container .radio-inline input[type=checkbox]{border-radius:.25em}.form-check-input[type=radio],.shiny-input-container .checkbox input[type=radio],.shiny-input-container .checkbox-inline input[type=radio],.shiny-input-container .radio input[type=radio],.shiny-input-container .radio-inline input[type=radio]{border-radius:50%}.form-check-input:active,.shiny-input-container .checkbox input:active,.shiny-input-container .checkbox-inline input:active,.shiny-input-container .radio input:active,.shiny-input-container .radio-inline input:active{filter:brightness(90%)}.form-check-input:focus,.shiny-input-container .checkbox input:focus,.shiny-input-container .checkbox-inline input:focus,.shiny-input-container .radio input:focus,.shiny-input-container .radio-inline input:focus{border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-check-input:checked,.shiny-input-container .checkbox input:checked,.shiny-input-container .checkbox-inline input:checked,.shiny-input-container .radio input:checked,.shiny-input-container .radio-inline input:checked{background-color:#0d6efd;border-color:#0d6efd}.form-check-input:checked[type=checkbox],.shiny-input-container .checkbox input:checked[type=checkbox],.shiny-input-container .checkbox-inline input:checked[type=checkbox],.shiny-input-container .radio input:checked[type=checkbox],.shiny-input-container .radio-inline input:checked[type=checkbox]{--bs-form-check-bg-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23ffffff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='m6 10 3 3 6-6'/%3e%3c/svg%3e")}.form-check-input:checked[type=radio],.shiny-input-container .checkbox input:checked[type=radio],.shiny-input-container .checkbox-inline input:checked[type=radio],.shiny-input-container .radio input:checked[type=radio],.shiny-input-container .radio-inline input:checked[type=radio]{--bs-form-check-bg-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='2' fill='%23ffffff'/%3e%3c/svg%3e")}.form-check-input[type=checkbox]:indeterminate,.shiny-input-container .checkbox input[type=checkbox]:indeterminate,.shiny-input-container .checkbox-inline input[type=checkbox]:indeterminate,.shiny-input-container .radio input[type=checkbox]:indeterminate,.shiny-input-container .radio-inline input[type=checkbox]:indeterminate{background-color:#0d6efd;border-color:#0d6efd;--bs-form-check-bg-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23ffffff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10h8'/%3e%3c/svg%3e")}.form-check-input:disabled,.shiny-input-container .checkbox input:disabled,.shiny-input-container .checkbox-inline input:disabled,.shiny-input-container .radio input:disabled,.shiny-input-container .radio-inline input:disabled{pointer-events:none;filter:none;opacity:.5}.form-check-input[disabled]~.form-check-label,.form-check-input[disabled]~span,.form-check-input:disabled~.form-check-label,.form-check-input:disabled~span,.shiny-input-container .checkbox input[disabled]~.form-check-label,.shiny-input-container .checkbox input[disabled]~span,.shiny-input-container .checkbox input:disabled~.form-check-label,.shiny-input-container .checkbox input:disabled~span,.shiny-input-container .checkbox-inline input[disabled]~.form-check-label,.shiny-input-container .checkbox-inline input[disabled]~span,.shiny-input-container .checkbox-inline input:disabled~.form-check-label,.shiny-input-container .checkbox-inline input:disabled~span,.shiny-input-container .radio input[disabled]~.form-check-label,.shiny-input-container .radio input[disabled]~span,.shiny-input-container .radio input:disabled~.form-check-label,.shiny-input-container .radio input:disabled~span,.shiny-input-container .radio-inline input[disabled]~.form-check-label,.shiny-input-container .radio-inline input[disabled]~span,.shiny-input-container .radio-inline input:disabled~.form-check-label,.shiny-input-container .radio-inline input:disabled~span{cursor:default;opacity:.5}.form-check-label,.shiny-input-container .checkbox label,.shiny-input-container .checkbox-inline label,.shiny-input-container .radio label,.shiny-input-container .radio-inline label{cursor:pointer}.form-switch{padding-left:2.5em}.form-switch .form-check-input{--bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%280, 0, 0, 0.25%29'/%3e%3c/svg%3e");width:2em;margin-left:-2.5em;background-image:var(--bs-form-switch-bg);background-position:left center;border-radius:2em;transition:background-position .15s ease-in-out}@media(prefers-reduced-motion: reduce){.form-switch .form-check-input{transition:none}}.form-switch .form-check-input:focus{--bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%2386b7fe'/%3e%3c/svg%3e")}.form-switch .form-check-input:checked{background-position:right center;--bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23ffffff'/%3e%3c/svg%3e")}.form-switch.form-check-reverse{padding-right:2.5em;padding-left:0}.form-switch.form-check-reverse .form-check-input{margin-right:-2.5em;margin-left:0}.form-check-inline{display:inline-block;margin-right:1rem}.btn-check{position:absolute;clip:rect(0, 0, 0, 0);pointer-events:none}.btn-check[disabled]+.btn,.btn-check:disabled+.btn{pointer-events:none;filter:none;opacity:.65}[data-bs-theme=dark] .form-switch .form-check-input:not(:checked):not(:focus){--bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%28255, 255, 255, 0.25%29'/%3e%3c/svg%3e")}.form-range{width:100%;height:1.5rem;padding:0;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none;background-color:rgba(0,0,0,0)}.form-range:focus{outline:0}.form-range:focus::-webkit-slider-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(13,110,253,.25)}.form-range:focus::-moz-range-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(13,110,253,.25)}.form-range::-moz-focus-outer{border:0}.form-range::-webkit-slider-thumb{width:1rem;height:1rem;margin-top:-0.25rem;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none;background-color:#0d6efd;border:0;border-radius:1rem;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.form-range::-webkit-slider-thumb{transition:none}}.form-range::-webkit-slider-thumb:active{background-color:#b6d4fe}.form-range::-webkit-slider-runnable-track{width:100%;height:.5rem;color:rgba(0,0,0,0);cursor:pointer;background-color:#f8f9fa;border-color:rgba(0,0,0,0);border-radius:1rem}.form-range::-moz-range-thumb{width:1rem;height:1rem;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none;background-color:#0d6efd;border:0;border-radius:1rem;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.form-range::-moz-range-thumb{transition:none}}.form-range::-moz-range-thumb:active{background-color:#b6d4fe}.form-range::-moz-range-track{width:100%;height:.5rem;color:rgba(0,0,0,0);cursor:pointer;background-color:#f8f9fa;border-color:rgba(0,0,0,0);border-radius:1rem}.form-range:disabled{pointer-events:none}.form-range:disabled::-webkit-slider-thumb{background-color:rgba(33,37,41,.75)}.form-range:disabled::-moz-range-thumb{background-color:rgba(33,37,41,.75)}.form-floating{position:relative}.form-floating>.form-control,.form-floating>.form-control-plaintext,.form-floating>.form-select{height:calc(3.5rem + calc(1px * 2));min-height:calc(3.5rem + calc(1px * 2));line-height:1.25}.form-floating>label{position:absolute;top:0;left:0;z-index:2;height:100%;padding:1rem .75rem;overflow:hidden;text-align:start;text-overflow:ellipsis;white-space:nowrap;pointer-events:none;border:1px solid rgba(0,0,0,0);transform-origin:0 0;transition:opacity .1s ease-in-out,transform .1s ease-in-out}@media(prefers-reduced-motion: reduce){.form-floating>label{transition:none}}.form-floating>.form-control,.form-floating>.form-control-plaintext{padding:1rem .75rem}.form-floating>.form-control::placeholder,.form-floating>.form-control-plaintext::placeholder{color:rgba(0,0,0,0)}.form-floating>.form-control:focus,.form-floating>.form-control:not(:placeholder-shown),.form-floating>.form-control-plaintext:focus,.form-floating>.form-control-plaintext:not(:placeholder-shown){padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:-webkit-autofill,.form-floating>.form-control-plaintext:-webkit-autofill{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-select{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:focus~label,.form-floating>.form-control:not(:placeholder-shown)~label,.form-floating>.form-control-plaintext~label,.form-floating>.form-select~label{color:rgba(var(--bs-body-color-rgb), 0.65);transform:scale(0.85) translateY(-0.5rem) translateX(0.15rem)}.form-floating>.form-control:focus~label::after,.form-floating>.form-control:not(:placeholder-shown)~label::after,.form-floating>.form-control-plaintext~label::after,.form-floating>.form-select~label::after{position:absolute;inset:1rem .375rem;z-index:-1;height:1.5em;content:"";background-color:#fff;border-radius:.375rem}.form-floating>.form-control:-webkit-autofill~label{color:rgba(var(--bs-body-color-rgb), 0.65);transform:scale(0.85) translateY(-0.5rem) translateX(0.15rem)}.form-floating>.form-control-plaintext~label{border-width:1px 0}.form-floating>:disabled~label,.form-floating>.form-control:disabled~label{color:#6c757d}.form-floating>:disabled~label::after,.form-floating>.form-control:disabled~label::after{background-color:#e9ecef}.input-group{position:relative;display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;align-items:stretch;-webkit-align-items:stretch;width:100%}.input-group>.form-control,.input-group>.form-select,.input-group>.form-floating{position:relative;flex:1 1 auto;-webkit-flex:1 1 auto;width:1%;min-width:0}.input-group>.form-control:focus,.input-group>.form-select:focus,.input-group>.form-floating:focus-within{z-index:5}.input-group .btn{position:relative;z-index:2}.input-group .btn:focus{z-index:5}.input-group-text{display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:center;white-space:nowrap;background-color:#f8f9fa;border:1px solid #dee2e6;border-radius:.375rem}.input-group-lg>.form-control,.input-group-lg>.form-select,.input-group-lg>.input-group-text,.input-group-lg>.btn{padding:.5rem 1rem;font-size:1.25rem;border-radius:.5rem}.input-group-sm>.form-control,.input-group-sm>.form-select,.input-group-sm>.input-group-text,.input-group-sm>.btn{padding:.25rem .5rem;font-size:0.875rem;border-radius:.25rem}.input-group-lg>.form-select,.input-group-sm>.form-select{padding-right:3rem}.input-group:not(.has-validation)>:not(:last-child):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating),.input-group:not(.has-validation)>.dropdown-toggle:nth-last-child(n+3),.input-group:not(.has-validation)>.form-floating:not(:last-child)>.form-control,.input-group:not(.has-validation)>.form-floating:not(:last-child)>.form-select{border-top-right-radius:0;border-bottom-right-radius:0}.input-group.has-validation>:nth-last-child(n+3):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating),.input-group.has-validation>.dropdown-toggle:nth-last-child(n+4),.input-group.has-validation>.form-floating:nth-last-child(n+3)>.form-control,.input-group.has-validation>.form-floating:nth-last-child(n+3)>.form-select{border-top-right-radius:0;border-bottom-right-radius:0}.input-group>:not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback){margin-left:calc(1px*-1);border-top-left-radius:0;border-bottom-left-radius:0}.input-group>.form-floating:not(:first-child)>.form-control,.input-group>.form-floating:not(:first-child)>.form-select{border-top-left-radius:0;border-bottom-left-radius:0}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:0.875em;color:#198754}.valid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:0.875rem;color:#fff;background-color:#198754;border-radius:.375rem}.was-validated :valid~.valid-feedback,.was-validated :valid~.valid-tooltip,.is-valid~.valid-feedback,.is-valid~.valid-tooltip{display:block}.was-validated .form-control:valid,.form-control.is-valid{border-color:#198754;padding-right:calc(1.5em + 0.75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(0.375em + 0.1875rem) center;background-size:calc(0.75em + 0.375rem) calc(0.75em + 0.375rem)}.was-validated .form-control:valid:focus,.form-control.is-valid:focus{border-color:#198754;box-shadow:0 0 0 .25rem rgba(25,135,84,.25)}.was-validated textarea.form-control:valid,textarea.form-control.is-valid{padding-right:calc(1.5em + 0.75rem);background-position:top calc(0.375em + 0.1875rem) right calc(0.375em + 0.1875rem)}.was-validated .form-select:valid,.form-select.is-valid{border-color:#198754}.was-validated .form-select:valid:not([multiple]):not([size]),.was-validated .form-select:valid:not([multiple])[size="1"],.form-select.is-valid:not([multiple]):not([size]),.form-select.is-valid:not([multiple])[size="1"]{--bs-form-select-bg-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");padding-right:4.125rem;background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(0.75em + 0.375rem) calc(0.75em + 0.375rem)}.was-validated .form-select:valid:focus,.form-select.is-valid:focus{border-color:#198754;box-shadow:0 0 0 .25rem rgba(25,135,84,.25)}.was-validated .form-control-color:valid,.form-control-color.is-valid{width:calc(3rem + calc(1.5em + 0.75rem))}.was-validated .form-check-input:valid,.form-check-input.is-valid{border-color:#198754}.was-validated .form-check-input:valid:checked,.form-check-input.is-valid:checked{background-color:#198754}.was-validated .form-check-input:valid:focus,.form-check-input.is-valid:focus{box-shadow:0 0 0 .25rem rgba(25,135,84,.25)}.was-validated .form-check-input:valid~.form-check-label,.form-check-input.is-valid~.form-check-label{color:#198754}.form-check-inline .form-check-input~.valid-feedback{margin-left:.5em}.was-validated .input-group>.form-control:not(:focus):valid,.input-group>.form-control:not(:focus).is-valid,.was-validated .input-group>.form-select:not(:focus):valid,.input-group>.form-select:not(:focus).is-valid,.was-validated .input-group>.form-floating:not(:focus-within):valid,.input-group>.form-floating:not(:focus-within).is-valid{z-index:3}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:0.875em;color:#dc3545}.invalid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:0.875rem;color:#fff;background-color:#dc3545;border-radius:.375rem}.was-validated :invalid~.invalid-feedback,.was-validated :invalid~.invalid-tooltip,.is-invalid~.invalid-feedback,.is-invalid~.invalid-tooltip{display:block}.was-validated .form-control:invalid,.form-control.is-invalid{border-color:#dc3545;padding-right:calc(1.5em + 0.75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(0.375em + 0.1875rem) center;background-size:calc(0.75em + 0.375rem) calc(0.75em + 0.375rem)}.was-validated .form-control:invalid:focus,.form-control.is-invalid:focus{border-color:#dc3545;box-shadow:0 0 0 .25rem rgba(220,53,69,.25)}.was-validated textarea.form-control:invalid,textarea.form-control.is-invalid{padding-right:calc(1.5em + 0.75rem);background-position:top calc(0.375em + 0.1875rem) right calc(0.375em + 0.1875rem)}.was-validated .form-select:invalid,.form-select.is-invalid{border-color:#dc3545}.was-validated .form-select:invalid:not([multiple]):not([size]),.was-validated .form-select:invalid:not([multiple])[size="1"],.form-select.is-invalid:not([multiple]):not([size]),.form-select.is-invalid:not([multiple])[size="1"]{--bs-form-select-bg-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");padding-right:4.125rem;background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(0.75em + 0.375rem) calc(0.75em + 0.375rem)}.was-validated .form-select:invalid:focus,.form-select.is-invalid:focus{border-color:#dc3545;box-shadow:0 0 0 .25rem rgba(220,53,69,.25)}.was-validated .form-control-color:invalid,.form-control-color.is-invalid{width:calc(3rem + calc(1.5em + 0.75rem))}.was-validated .form-check-input:invalid,.form-check-input.is-invalid{border-color:#dc3545}.was-validated .form-check-input:invalid:checked,.form-check-input.is-invalid:checked{background-color:#dc3545}.was-validated .form-check-input:invalid:focus,.form-check-input.is-invalid:focus{box-shadow:0 0 0 .25rem rgba(220,53,69,.25)}.was-validated .form-check-input:invalid~.form-check-label,.form-check-input.is-invalid~.form-check-label{color:#dc3545}.form-check-inline .form-check-input~.invalid-feedback{margin-left:.5em}.was-validated .input-group>.form-control:not(:focus):invalid,.input-group>.form-control:not(:focus).is-invalid,.was-validated .input-group>.form-select:not(:focus):invalid,.input-group>.form-select:not(:focus).is-invalid,.was-validated .input-group>.form-floating:not(:focus-within):invalid,.input-group>.form-floating:not(:focus-within).is-invalid{z-index:4}.btn{--bs-btn-padding-x: 0.75rem;--bs-btn-padding-y: 0.375rem;--bs-btn-font-family: ;--bs-btn-font-size:1rem;--bs-btn-font-weight: 400;--bs-btn-line-height: 1.5;--bs-btn-color: #212529;--bs-btn-bg: transparent;--bs-btn-border-width: 1px;--bs-btn-border-color: transparent;--bs-btn-border-radius: 0.375rem;--bs-btn-hover-border-color: transparent;--bs-btn-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075);--bs-btn-disabled-opacity: 0.65;--bs-btn-focus-box-shadow: 0 0 0 0.25rem rgba(var(--bs-btn-focus-shadow-rgb), .5);display:inline-block;padding:var(--bs-btn-padding-y) var(--bs-btn-padding-x);font-family:var(--bs-btn-font-family);font-size:var(--bs-btn-font-size);font-weight:var(--bs-btn-font-weight);line-height:var(--bs-btn-line-height);color:var(--bs-btn-color);text-align:center;text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;vertical-align:middle;cursor:pointer;user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;border:var(--bs-btn-border-width) solid var(--bs-btn-border-color);border-radius:var(--bs-btn-border-radius);background-color:var(--bs-btn-bg);transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.btn{transition:none}}.btn:hover{color:var(--bs-btn-hover-color);background-color:var(--bs-btn-hover-bg);border-color:var(--bs-btn-hover-border-color)}.btn-check+.btn:hover{color:var(--bs-btn-color);background-color:var(--bs-btn-bg);border-color:var(--bs-btn-border-color)}.btn:focus-visible{color:var(--bs-btn-hover-color);background-color:var(--bs-btn-hover-bg);border-color:var(--bs-btn-hover-border-color);outline:0;box-shadow:var(--bs-btn-focus-box-shadow)}.btn-check:focus-visible+.btn{border-color:var(--bs-btn-hover-border-color);outline:0;box-shadow:var(--bs-btn-focus-box-shadow)}.btn-check:checked+.btn,:not(.btn-check)+.btn:active,.btn:first-child:active,.btn.active,.btn.show{color:var(--bs-btn-active-color);background-color:var(--bs-btn-active-bg);border-color:var(--bs-btn-active-border-color)}.btn-check:checked+.btn:focus-visible,:not(.btn-check)+.btn:active:focus-visible,.btn:first-child:active:focus-visible,.btn.active:focus-visible,.btn.show:focus-visible{box-shadow:var(--bs-btn-focus-box-shadow)}.btn:disabled,.btn.disabled,fieldset:disabled .btn{color:var(--bs-btn-disabled-color);pointer-events:none;background-color:var(--bs-btn-disabled-bg);border-color:var(--bs-btn-disabled-border-color);opacity:var(--bs-btn-disabled-opacity)}.btn-default{--bs-btn-color: #000;--bs-btn-bg: #dee2e6;--bs-btn-border-color: #dee2e6;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #e3e6ea;--bs-btn-hover-border-color: #e1e5e9;--bs-btn-focus-shadow-rgb: 189, 192, 196;--bs-btn-active-color: #000;--bs-btn-active-bg: #e5e8eb;--bs-btn-active-border-color: #e1e5e9;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #000;--bs-btn-disabled-bg: #dee2e6;--bs-btn-disabled-border-color: #dee2e6}.btn-primary{--bs-btn-color: #ffffff;--bs-btn-bg: #0d6efd;--bs-btn-border-color: #0d6efd;--bs-btn-hover-color: #ffffff;--bs-btn-hover-bg: #0b5ed7;--bs-btn-hover-border-color: #0a58ca;--bs-btn-focus-shadow-rgb: 49, 132, 253;--bs-btn-active-color: #ffffff;--bs-btn-active-bg: #0a58ca;--bs-btn-active-border-color: #0a53be;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #ffffff;--bs-btn-disabled-bg: #0d6efd;--bs-btn-disabled-border-color: #0d6efd}.btn-secondary{--bs-btn-color: #ffffff;--bs-btn-bg: #6c757d;--bs-btn-border-color: #6c757d;--bs-btn-hover-color: #ffffff;--bs-btn-hover-bg: #5c636a;--bs-btn-hover-border-color: #565e64;--bs-btn-focus-shadow-rgb: 130, 138, 145;--bs-btn-active-color: #ffffff;--bs-btn-active-bg: #565e64;--bs-btn-active-border-color: #51585e;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #ffffff;--bs-btn-disabled-bg: #6c757d;--bs-btn-disabled-border-color: #6c757d}.btn-success{--bs-btn-color: #ffffff;--bs-btn-bg: #198754;--bs-btn-border-color: #198754;--bs-btn-hover-color: #ffffff;--bs-btn-hover-bg: #157347;--bs-btn-hover-border-color: #146c43;--bs-btn-focus-shadow-rgb: 60, 153, 110;--bs-btn-active-color: #ffffff;--bs-btn-active-bg: #146c43;--bs-btn-active-border-color: #13653f;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #ffffff;--bs-btn-disabled-bg: #198754;--bs-btn-disabled-border-color: #198754}.btn-info{--bs-btn-color: #000;--bs-btn-bg: #0dcaf0;--bs-btn-border-color: #0dcaf0;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #31d2f2;--bs-btn-hover-border-color: #25cff2;--bs-btn-focus-shadow-rgb: 11, 172, 204;--bs-btn-active-color: #000;--bs-btn-active-bg: #3dd5f3;--bs-btn-active-border-color: #25cff2;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #000;--bs-btn-disabled-bg: #0dcaf0;--bs-btn-disabled-border-color: #0dcaf0}.btn-warning{--bs-btn-color: #000;--bs-btn-bg: #ffc107;--bs-btn-border-color: #ffc107;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #ffca2c;--bs-btn-hover-border-color: #ffc720;--bs-btn-focus-shadow-rgb: 217, 164, 6;--bs-btn-active-color: #000;--bs-btn-active-bg: #ffcd39;--bs-btn-active-border-color: #ffc720;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #000;--bs-btn-disabled-bg: #ffc107;--bs-btn-disabled-border-color: #ffc107}.btn-danger{--bs-btn-color: #ffffff;--bs-btn-bg: #dc3545;--bs-btn-border-color: #dc3545;--bs-btn-hover-color: #ffffff;--bs-btn-hover-bg: #bb2d3b;--bs-btn-hover-border-color: #b02a37;--bs-btn-focus-shadow-rgb: 225, 83, 97;--bs-btn-active-color: #ffffff;--bs-btn-active-bg: #b02a37;--bs-btn-active-border-color: #a52834;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #ffffff;--bs-btn-disabled-bg: #dc3545;--bs-btn-disabled-border-color: #dc3545}.btn-light{--bs-btn-color: #000;--bs-btn-bg: #f8f9fa;--bs-btn-border-color: #f8f9fa;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #d3d4d5;--bs-btn-hover-border-color: #c6c7c8;--bs-btn-focus-shadow-rgb: 211, 212, 213;--bs-btn-active-color: #000;--bs-btn-active-bg: #c6c7c8;--bs-btn-active-border-color: #babbbc;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #000;--bs-btn-disabled-bg: #f8f9fa;--bs-btn-disabled-border-color: #f8f9fa}.btn-dark{--bs-btn-color: #ffffff;--bs-btn-bg: #212529;--bs-btn-border-color: #212529;--bs-btn-hover-color: #ffffff;--bs-btn-hover-bg: #424649;--bs-btn-hover-border-color: #373b3e;--bs-btn-focus-shadow-rgb: 66, 70, 73;--bs-btn-active-color: #ffffff;--bs-btn-active-bg: #4d5154;--bs-btn-active-border-color: #373b3e;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #ffffff;--bs-btn-disabled-bg: #212529;--bs-btn-disabled-border-color: #212529}.btn-outline-default{--bs-btn-color: #dee2e6;--bs-btn-border-color: #dee2e6;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #dee2e6;--bs-btn-hover-border-color: #dee2e6;--bs-btn-focus-shadow-rgb: 222, 226, 230;--bs-btn-active-color: #000;--bs-btn-active-bg: #dee2e6;--bs-btn-active-border-color: #dee2e6;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #dee2e6;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #dee2e6;--bs-btn-bg: transparent;--bs-gradient: none}.btn-outline-primary{--bs-btn-color: #0d6efd;--bs-btn-border-color: #0d6efd;--bs-btn-hover-color: #ffffff;--bs-btn-hover-bg: #0d6efd;--bs-btn-hover-border-color: #0d6efd;--bs-btn-focus-shadow-rgb: 13, 110, 253;--bs-btn-active-color: #ffffff;--bs-btn-active-bg: #0d6efd;--bs-btn-active-border-color: #0d6efd;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #0d6efd;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #0d6efd;--bs-btn-bg: transparent;--bs-gradient: none}.btn-outline-secondary{--bs-btn-color: #6c757d;--bs-btn-border-color: #6c757d;--bs-btn-hover-color: #ffffff;--bs-btn-hover-bg: #6c757d;--bs-btn-hover-border-color: #6c757d;--bs-btn-focus-shadow-rgb: 108, 117, 125;--bs-btn-active-color: #ffffff;--bs-btn-active-bg: #6c757d;--bs-btn-active-border-color: #6c757d;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #6c757d;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #6c757d;--bs-btn-bg: transparent;--bs-gradient: none}.btn-outline-success{--bs-btn-color: #198754;--bs-btn-border-color: #198754;--bs-btn-hover-color: #ffffff;--bs-btn-hover-bg: #198754;--bs-btn-hover-border-color: #198754;--bs-btn-focus-shadow-rgb: 25, 135, 84;--bs-btn-active-color: #ffffff;--bs-btn-active-bg: #198754;--bs-btn-active-border-color: #198754;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #198754;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #198754;--bs-btn-bg: transparent;--bs-gradient: none}.btn-outline-info{--bs-btn-color: #0dcaf0;--bs-btn-border-color: #0dcaf0;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #0dcaf0;--bs-btn-hover-border-color: #0dcaf0;--bs-btn-focus-shadow-rgb: 13, 202, 240;--bs-btn-active-color: #000;--bs-btn-active-bg: #0dcaf0;--bs-btn-active-border-color: #0dcaf0;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #0dcaf0;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #0dcaf0;--bs-btn-bg: transparent;--bs-gradient: none}.btn-outline-warning{--bs-btn-color: #ffc107;--bs-btn-border-color: #ffc107;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #ffc107;--bs-btn-hover-border-color: #ffc107;--bs-btn-focus-shadow-rgb: 255, 193, 7;--bs-btn-active-color: #000;--bs-btn-active-bg: #ffc107;--bs-btn-active-border-color: #ffc107;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #ffc107;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #ffc107;--bs-btn-bg: transparent;--bs-gradient: none}.btn-outline-danger{--bs-btn-color: #dc3545;--bs-btn-border-color: #dc3545;--bs-btn-hover-color: #ffffff;--bs-btn-hover-bg: #dc3545;--bs-btn-hover-border-color: #dc3545;--bs-btn-focus-shadow-rgb: 220, 53, 69;--bs-btn-active-color: #ffffff;--bs-btn-active-bg: #dc3545;--bs-btn-active-border-color: #dc3545;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #dc3545;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #dc3545;--bs-btn-bg: transparent;--bs-gradient: none}.btn-outline-light{--bs-btn-color: #f8f9fa;--bs-btn-border-color: #f8f9fa;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #f8f9fa;--bs-btn-hover-border-color: #f8f9fa;--bs-btn-focus-shadow-rgb: 248, 249, 250;--bs-btn-active-color: #000;--bs-btn-active-bg: #f8f9fa;--bs-btn-active-border-color: #f8f9fa;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #f8f9fa;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #f8f9fa;--bs-btn-bg: transparent;--bs-gradient: none}.btn-outline-dark{--bs-btn-color: #212529;--bs-btn-border-color: #212529;--bs-btn-hover-color: #ffffff;--bs-btn-hover-bg: #212529;--bs-btn-hover-border-color: #212529;--bs-btn-focus-shadow-rgb: 33, 37, 41;--bs-btn-active-color: #ffffff;--bs-btn-active-bg: #212529;--bs-btn-active-border-color: #212529;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #212529;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #212529;--bs-btn-bg: transparent;--bs-gradient: none}.btn-link{--bs-btn-font-weight: 400;--bs-btn-color: #0d6efd;--bs-btn-bg: transparent;--bs-btn-border-color: transparent;--bs-btn-hover-color: #0a58ca;--bs-btn-hover-border-color: transparent;--bs-btn-active-color: #0a58ca;--bs-btn-active-border-color: transparent;--bs-btn-disabled-color: #6c757d;--bs-btn-disabled-border-color: transparent;--bs-btn-box-shadow: 0 0 0 #000;--bs-btn-focus-shadow-rgb: 49, 132, 253;text-decoration:underline;-webkit-text-decoration:underline;-moz-text-decoration:underline;-ms-text-decoration:underline;-o-text-decoration:underline}.btn-link:focus-visible{color:var(--bs-btn-color)}.btn-link:hover{color:var(--bs-btn-hover-color)}.btn-lg,.btn-group-lg>.btn{--bs-btn-padding-y: 0.5rem;--bs-btn-padding-x: 1rem;--bs-btn-font-size:1.25rem;--bs-btn-border-radius: 0.5rem}.btn-sm,.btn-group-sm>.btn{--bs-btn-padding-y: 0.25rem;--bs-btn-padding-x: 0.5rem;--bs-btn-font-size:0.875rem;--bs-btn-border-radius: 0.25rem}.fade{transition:opacity .15s linear}@media(prefers-reduced-motion: reduce){.fade{transition:none}}.fade:not(.show){opacity:0}.collapse:not(.show){display:none}.collapsing{height:0;overflow:hidden;transition:height .2s ease}@media(prefers-reduced-motion: reduce){.collapsing{transition:none}}.collapsing.collapse-horizontal{width:0;height:auto;transition:width .35s ease}@media(prefers-reduced-motion: reduce){.collapsing.collapse-horizontal{transition:none}}.dropup,.dropend,.dropdown,.dropstart,.dropup-center,.dropdown-center{position:relative}.dropdown-toggle{white-space:nowrap}.dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid rgba(0,0,0,0);border-bottom:0;border-left:.3em solid rgba(0,0,0,0)}.dropdown-toggle:empty::after{margin-left:0}.dropdown-menu{--bs-dropdown-zindex: 1000;--bs-dropdown-min-width: 10rem;--bs-dropdown-padding-x: 0;--bs-dropdown-padding-y: 0.5rem;--bs-dropdown-spacer: 0.125rem;--bs-dropdown-font-size:1rem;--bs-dropdown-color: #212529;--bs-dropdown-bg: #ffffff;--bs-dropdown-border-color: rgba(0, 0, 0, 0.175);--bs-dropdown-border-radius: 0.375rem;--bs-dropdown-border-width: 1px;--bs-dropdown-inner-border-radius: calc(0.375rem - 1px);--bs-dropdown-divider-bg: rgba(0, 0, 0, 0.175);--bs-dropdown-divider-margin-y: 0.5rem;--bs-dropdown-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);--bs-dropdown-link-color: #212529;--bs-dropdown-link-hover-color: #212529;--bs-dropdown-link-hover-bg: #f8f9fa;--bs-dropdown-link-active-color: #ffffff;--bs-dropdown-link-active-bg: #0d6efd;--bs-dropdown-link-disabled-color: rgba(33, 37, 41, 0.5);--bs-dropdown-item-padding-x: 1rem;--bs-dropdown-item-padding-y: 0.25rem;--bs-dropdown-header-color: #6c757d;--bs-dropdown-header-padding-x: 1rem;--bs-dropdown-header-padding-y: 0.5rem;position:absolute;z-index:var(--bs-dropdown-zindex);display:none;min-width:var(--bs-dropdown-min-width);padding:var(--bs-dropdown-padding-y) var(--bs-dropdown-padding-x);margin:0;font-size:var(--bs-dropdown-font-size);color:var(--bs-dropdown-color);text-align:left;list-style:none;background-color:var(--bs-dropdown-bg);background-clip:padding-box;border:var(--bs-dropdown-border-width) solid var(--bs-dropdown-border-color);border-radius:var(--bs-dropdown-border-radius)}.dropdown-menu[data-bs-popper]{top:100%;left:0;margin-top:var(--bs-dropdown-spacer)}.dropdown-menu-start{--bs-position: start}.dropdown-menu-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-end{--bs-position: end}.dropdown-menu-end[data-bs-popper]{right:0;left:auto}@media(min-width: 576px){.dropdown-menu-sm-start{--bs-position: start}.dropdown-menu-sm-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-sm-end{--bs-position: end}.dropdown-menu-sm-end[data-bs-popper]{right:0;left:auto}}@media(min-width: 768px){.dropdown-menu-md-start{--bs-position: start}.dropdown-menu-md-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-md-end{--bs-position: end}.dropdown-menu-md-end[data-bs-popper]{right:0;left:auto}}@media(min-width: 992px){.dropdown-menu-lg-start{--bs-position: start}.dropdown-menu-lg-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-lg-end{--bs-position: end}.dropdown-menu-lg-end[data-bs-popper]{right:0;left:auto}}@media(min-width: 1200px){.dropdown-menu-xl-start{--bs-position: start}.dropdown-menu-xl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xl-end{--bs-position: end}.dropdown-menu-xl-end[data-bs-popper]{right:0;left:auto}}@media(min-width: 1400px){.dropdown-menu-xxl-start{--bs-position: start}.dropdown-menu-xxl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xxl-end{--bs-position: end}.dropdown-menu-xxl-end[data-bs-popper]{right:0;left:auto}}.dropup .dropdown-menu[data-bs-popper]{top:auto;bottom:100%;margin-top:0;margin-bottom:var(--bs-dropdown-spacer)}.dropup .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid rgba(0,0,0,0);border-bottom:.3em solid;border-left:.3em solid rgba(0,0,0,0)}.dropup .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-menu[data-bs-popper]{top:0;right:auto;left:100%;margin-top:0;margin-left:var(--bs-dropdown-spacer)}.dropend .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid rgba(0,0,0,0);border-right:0;border-bottom:.3em solid rgba(0,0,0,0);border-left:.3em solid}.dropend .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-toggle::after{vertical-align:0}.dropstart .dropdown-menu[data-bs-popper]{top:0;right:100%;left:auto;margin-top:0;margin-right:var(--bs-dropdown-spacer)}.dropstart .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:""}.dropstart .dropdown-toggle::after{display:none}.dropstart .dropdown-toggle::before{display:inline-block;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid rgba(0,0,0,0);border-right:.3em solid;border-bottom:.3em solid rgba(0,0,0,0)}.dropstart .dropdown-toggle:empty::after{margin-left:0}.dropstart .dropdown-toggle::before{vertical-align:0}.dropdown-divider{height:0;margin:var(--bs-dropdown-divider-margin-y) 0;overflow:hidden;border-top:1px solid var(--bs-dropdown-divider-bg);opacity:1}.dropdown-item{display:block;width:100%;padding:var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x);clear:both;font-weight:400;color:var(--bs-dropdown-link-color);text-align:inherit;text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;white-space:nowrap;background-color:rgba(0,0,0,0);border:0;border-radius:var(--bs-dropdown-item-border-radius, 0)}.dropdown-item:hover,.dropdown-item:focus{color:var(--bs-dropdown-link-hover-color);background-color:var(--bs-dropdown-link-hover-bg)}.dropdown-item.active,.dropdown-item:active{color:var(--bs-dropdown-link-active-color);text-decoration:none;background-color:var(--bs-dropdown-link-active-bg)}.dropdown-item.disabled,.dropdown-item:disabled{color:var(--bs-dropdown-link-disabled-color);pointer-events:none;background-color:rgba(0,0,0,0)}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:var(--bs-dropdown-header-padding-y) var(--bs-dropdown-header-padding-x);margin-bottom:0;font-size:0.875rem;color:var(--bs-dropdown-header-color);white-space:nowrap}.dropdown-item-text{display:block;padding:var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x);color:var(--bs-dropdown-link-color)}.dropdown-menu-dark{--bs-dropdown-color: #dee2e6;--bs-dropdown-bg: #343a40;--bs-dropdown-border-color: rgba(0, 0, 0, 0.175);--bs-dropdown-box-shadow: ;--bs-dropdown-link-color: #dee2e6;--bs-dropdown-link-hover-color: #ffffff;--bs-dropdown-divider-bg: rgba(0, 0, 0, 0.175);--bs-dropdown-link-hover-bg: rgba(255, 255, 255, 0.15);--bs-dropdown-link-active-color: #ffffff;--bs-dropdown-link-active-bg: #0d6efd;--bs-dropdown-link-disabled-color: #adb5bd;--bs-dropdown-header-color: #adb5bd}.btn-group,.btn-group-vertical{position:relative;display:inline-flex;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;flex:1 1 auto;-webkit-flex:1 1 auto}.btn-group>.btn-check:checked+.btn,.btn-group>.btn-check:focus+.btn,.btn-group>.btn:hover,.btn-group>.btn:focus,.btn-group>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn-check:checked+.btn,.btn-group-vertical>.btn-check:focus+.btn,.btn-group-vertical>.btn:hover,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn.active{z-index:1}.btn-toolbar{display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;justify-content:flex-start;-webkit-justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group{border-radius:.375rem}.btn-group>:not(.btn-check:first-child)+.btn,.btn-group>.btn-group:not(:first-child){margin-left:calc(1px*-1)}.btn-group>.btn:not(:last-child):not(.dropdown-toggle),.btn-group>.btn.dropdown-toggle-split:first-child,.btn-group>.btn-group:not(:last-child)>.btn{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:nth-child(n+3),.btn-group>:not(.btn-check)+.btn,.btn-group>.btn-group:not(:first-child)>.btn{border-top-left-radius:0;border-bottom-left-radius:0}.dropdown-toggle-split{padding-right:.5625rem;padding-left:.5625rem}.dropdown-toggle-split::after,.dropup .dropdown-toggle-split::after,.dropend .dropdown-toggle-split::after{margin-left:0}.dropstart .dropdown-toggle-split::before{margin-right:0}.btn-sm+.dropdown-toggle-split,.btn-group-sm>.btn+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-lg+.dropdown-toggle-split,.btn-group-lg>.btn+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.btn-group-vertical{flex-direction:column;-webkit-flex-direction:column;align-items:flex-start;-webkit-align-items:flex-start;justify-content:center;-webkit-justify-content:center}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group{width:100%}.btn-group-vertical>.btn:not(:first-child),.btn-group-vertical>.btn-group:not(:first-child){margin-top:calc(1px*-1)}.btn-group-vertical>.btn:not(:last-child):not(.dropdown-toggle),.btn-group-vertical>.btn-group:not(:last-child)>.btn{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn~.btn,.btn-group-vertical>.btn-group:not(:first-child)>.btn{border-top-left-radius:0;border-top-right-radius:0}.nav{--bs-nav-link-padding-x: 1rem;--bs-nav-link-padding-y: 0.5rem;--bs-nav-link-font-weight: ;--bs-nav-link-color: #0d6efd;--bs-nav-link-hover-color: #0a58ca;--bs-nav-link-disabled-color: rgba(33, 37, 41, 0.75);display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:var(--bs-nav-link-padding-y) var(--bs-nav-link-padding-x);font-size:var(--bs-nav-link-font-size);font-weight:var(--bs-nav-link-font-weight);color:var(--bs-nav-link-color);text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;background:none;border:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out}@media(prefers-reduced-motion: reduce){.nav-link{transition:none}}.nav-link:hover,.nav-link:focus{color:var(--bs-nav-link-hover-color)}.nav-link:focus-visible{outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.nav-link.disabled,.nav-link:disabled{color:var(--bs-nav-link-disabled-color);pointer-events:none;cursor:default}.nav-tabs{--bs-nav-tabs-border-width: 1px;--bs-nav-tabs-border-color: #dee2e6;--bs-nav-tabs-border-radius: 0.375rem;--bs-nav-tabs-link-hover-border-color: #e9ecef #e9ecef #dee2e6;--bs-nav-tabs-link-active-color: #000;--bs-nav-tabs-link-active-bg: #ffffff;--bs-nav-tabs-link-active-border-color: #dee2e6 #dee2e6 #ffffff;border-bottom:var(--bs-nav-tabs-border-width) solid var(--bs-nav-tabs-border-color)}.nav-tabs .nav-link{margin-bottom:calc(-1*var(--bs-nav-tabs-border-width));border:var(--bs-nav-tabs-border-width) solid rgba(0,0,0,0);border-top-left-radius:var(--bs-nav-tabs-border-radius);border-top-right-radius:var(--bs-nav-tabs-border-radius)}.nav-tabs .nav-link:hover,.nav-tabs .nav-link:focus{isolation:isolate;border-color:var(--bs-nav-tabs-link-hover-border-color)}.nav-tabs .nav-link.active,.nav-tabs .nav-item.show .nav-link{color:var(--bs-nav-tabs-link-active-color);background-color:var(--bs-nav-tabs-link-active-bg);border-color:var(--bs-nav-tabs-link-active-border-color)}.nav-tabs .dropdown-menu{margin-top:calc(-1*var(--bs-nav-tabs-border-width));border-top-left-radius:0;border-top-right-radius:0}.nav-pills{--bs-nav-pills-border-radius: 0.375rem;--bs-nav-pills-link-active-color: #ffffff;--bs-nav-pills-link-active-bg: #0d6efd}.nav-pills .nav-link{border-radius:var(--bs-nav-pills-border-radius)}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:var(--bs-nav-pills-link-active-color);background-color:var(--bs-nav-pills-link-active-bg)}.nav-underline{--bs-nav-underline-gap: 1rem;--bs-nav-underline-border-width: 0.125rem;--bs-nav-underline-link-active-color: #000;gap:var(--bs-nav-underline-gap)}.nav-underline .nav-link{padding-right:0;padding-left:0;border-bottom:var(--bs-nav-underline-border-width) solid rgba(0,0,0,0)}.nav-underline .nav-link:hover,.nav-underline .nav-link:focus{border-bottom-color:currentcolor}.nav-underline .nav-link.active,.nav-underline .show>.nav-link{font-weight:700;color:var(--bs-nav-underline-link-active-color);border-bottom-color:currentcolor}.nav-fill>.nav-link,.nav-fill .nav-item{flex:1 1 auto;-webkit-flex:1 1 auto;text-align:center}.nav-justified>.nav-link,.nav-justified .nav-item{flex-basis:0;-webkit-flex-basis:0;flex-grow:1;-webkit-flex-grow:1;text-align:center}.nav-fill .nav-item .nav-link,.nav-justified .nav-item .nav-link{width:100%}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{--bs-navbar-padding-x: 0;--bs-navbar-padding-y: 0.5rem;--bs-navbar-color: #fdfefe;--bs-navbar-hover-color: rgba(253, 254, 255, 0.8);--bs-navbar-disabled-color: rgba(253, 254, 254, 0.75);--bs-navbar-active-color: #fdfeff;--bs-navbar-brand-padding-y: 0.3125rem;--bs-navbar-brand-margin-end: 1rem;--bs-navbar-brand-font-size: 1.25rem;--bs-navbar-brand-color: #fdfefe;--bs-navbar-brand-hover-color: #fdfeff;--bs-navbar-nav-link-padding-x: 0.5rem;--bs-navbar-toggler-padding-y: 0.25;--bs-navbar-toggler-padding-x: 0;--bs-navbar-toggler-font-size: 1.25rem;--bs-navbar-toggler-icon-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='%23fdfefe' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e");--bs-navbar-toggler-border-color: rgba(253, 254, 254, 0);--bs-navbar-toggler-border-radius: 0.375rem;--bs-navbar-toggler-focus-width: 0.25rem;--bs-navbar-toggler-transition: box-shadow 0.15s ease-in-out;position:relative;display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;align-items:center;-webkit-align-items:center;justify-content:space-between;-webkit-justify-content:space-between;padding:var(--bs-navbar-padding-y) var(--bs-navbar-padding-x)}.navbar>.container,.navbar>.container-fluid,.navbar>.container-sm,.navbar>.container-md,.navbar>.container-lg,.navbar>.container-xl,.navbar>.container-xxl{display:flex;display:-webkit-flex;flex-wrap:inherit;-webkit-flex-wrap:inherit;align-items:center;-webkit-align-items:center;justify-content:space-between;-webkit-justify-content:space-between}.navbar-brand{padding-top:var(--bs-navbar-brand-padding-y);padding-bottom:var(--bs-navbar-brand-padding-y);margin-right:var(--bs-navbar-brand-margin-end);font-size:var(--bs-navbar-brand-font-size);color:var(--bs-navbar-brand-color);text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;white-space:nowrap}.navbar-brand:hover,.navbar-brand:focus{color:var(--bs-navbar-brand-hover-color)}.navbar-nav{--bs-nav-link-padding-x: 0;--bs-nav-link-padding-y: 0.5rem;--bs-nav-link-font-weight: ;--bs-nav-link-color: var(--bs-navbar-color);--bs-nav-link-hover-color: var(--bs-navbar-hover-color);--bs-nav-link-disabled-color: var(--bs-navbar-disabled-color);display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link.active,.navbar-nav .nav-link.show{color:var(--bs-navbar-active-color)}.navbar-nav .dropdown-menu{position:static}.navbar-text{padding-top:.5rem;padding-bottom:.5rem;color:var(--bs-navbar-color)}.navbar-text a,.navbar-text a:hover,.navbar-text a:focus{color:var(--bs-navbar-active-color)}.navbar-collapse{flex-basis:100%;-webkit-flex-basis:100%;flex-grow:1;-webkit-flex-grow:1;align-items:center;-webkit-align-items:center}.navbar-toggler{padding:var(--bs-navbar-toggler-padding-y) var(--bs-navbar-toggler-padding-x);font-size:var(--bs-navbar-toggler-font-size);line-height:1;color:var(--bs-navbar-color);background-color:rgba(0,0,0,0);border:var(--bs-border-width) solid var(--bs-navbar-toggler-border-color);border-radius:var(--bs-navbar-toggler-border-radius);transition:var(--bs-navbar-toggler-transition)}@media(prefers-reduced-motion: reduce){.navbar-toggler{transition:none}}.navbar-toggler:hover{text-decoration:none}.navbar-toggler:focus{text-decoration:none;outline:0;box-shadow:0 0 0 var(--bs-navbar-toggler-focus-width)}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;background-image:var(--bs-navbar-toggler-icon-bg);background-repeat:no-repeat;background-position:center;background-size:100%}.navbar-nav-scroll{max-height:var(--bs-scroll-height, 75vh);overflow-y:auto}@media(min-width: 576px){.navbar-expand-sm{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand-sm .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-sm .navbar-nav-scroll{overflow:visible}.navbar-expand-sm .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}.navbar-expand-sm .offcanvas{position:static;z-index:auto;flex-grow:1;-webkit-flex-grow:1;width:auto !important;height:auto !important;visibility:visible !important;background-color:rgba(0,0,0,0) !important;border:0 !important;transform:none !important;transition:none}.navbar-expand-sm .offcanvas .offcanvas-header{display:none}.navbar-expand-sm .offcanvas .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}}@media(min-width: 768px){.navbar-expand-md{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand-md .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-md .navbar-nav-scroll{overflow:visible}.navbar-expand-md .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}.navbar-expand-md .offcanvas{position:static;z-index:auto;flex-grow:1;-webkit-flex-grow:1;width:auto !important;height:auto !important;visibility:visible !important;background-color:rgba(0,0,0,0) !important;border:0 !important;transform:none !important;transition:none}.navbar-expand-md .offcanvas .offcanvas-header{display:none}.navbar-expand-md .offcanvas .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}}@media(min-width: 992px){.navbar-expand-lg{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand-lg .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-lg .navbar-nav-scroll{overflow:visible}.navbar-expand-lg .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}.navbar-expand-lg .offcanvas{position:static;z-index:auto;flex-grow:1;-webkit-flex-grow:1;width:auto !important;height:auto !important;visibility:visible !important;background-color:rgba(0,0,0,0) !important;border:0 !important;transform:none !important;transition:none}.navbar-expand-lg .offcanvas .offcanvas-header{display:none}.navbar-expand-lg .offcanvas .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}}@media(min-width: 1200px){.navbar-expand-xl{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand-xl .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-xl .navbar-nav-scroll{overflow:visible}.navbar-expand-xl .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}.navbar-expand-xl .offcanvas{position:static;z-index:auto;flex-grow:1;-webkit-flex-grow:1;width:auto !important;height:auto !important;visibility:visible !important;background-color:rgba(0,0,0,0) !important;border:0 !important;transform:none !important;transition:none}.navbar-expand-xl .offcanvas .offcanvas-header{display:none}.navbar-expand-xl .offcanvas .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}}@media(min-width: 1400px){.navbar-expand-xxl{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand-xxl .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand-xxl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xxl .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-xxl .navbar-nav-scroll{overflow:visible}.navbar-expand-xxl .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand-xxl .navbar-toggler{display:none}.navbar-expand-xxl .offcanvas{position:static;z-index:auto;flex-grow:1;-webkit-flex-grow:1;width:auto !important;height:auto !important;visibility:visible !important;background-color:rgba(0,0,0,0) !important;border:0 !important;transform:none !important;transition:none}.navbar-expand-xxl .offcanvas .offcanvas-header{display:none}.navbar-expand-xxl .offcanvas .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}}.navbar-expand{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand .navbar-nav-scroll{overflow:visible}.navbar-expand .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-expand .offcanvas{position:static;z-index:auto;flex-grow:1;-webkit-flex-grow:1;width:auto !important;height:auto !important;visibility:visible !important;background-color:rgba(0,0,0,0) !important;border:0 !important;transform:none !important;transition:none}.navbar-expand .offcanvas .offcanvas-header{display:none}.navbar-expand .offcanvas .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}.navbar-dark,.navbar[data-bs-theme=dark]{--bs-navbar-color: #fdfefe;--bs-navbar-hover-color: rgba(253, 254, 255, 0.8);--bs-navbar-disabled-color: rgba(253, 254, 254, 0.75);--bs-navbar-active-color: #fdfeff;--bs-navbar-brand-color: #fdfefe;--bs-navbar-brand-hover-color: #fdfeff;--bs-navbar-toggler-border-color: rgba(253, 254, 254, 0);--bs-navbar-toggler-icon-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='%23fdfefe' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}[data-bs-theme=dark] .navbar-toggler-icon{--bs-navbar-toggler-icon-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='%23fdfefe' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.card{--bs-card-spacer-y: 1rem;--bs-card-spacer-x: 1rem;--bs-card-title-spacer-y: 0.5rem;--bs-card-title-color: ;--bs-card-subtitle-color: ;--bs-card-border-width: 1px;--bs-card-border-color: rgba(0, 0, 0, 0.175);--bs-card-border-radius: 0.375rem;--bs-card-box-shadow: ;--bs-card-inner-border-radius: calc(0.375rem - 1px);--bs-card-cap-padding-y: 0.5rem;--bs-card-cap-padding-x: 1rem;--bs-card-cap-bg: rgba(33, 37, 41, 0.03);--bs-card-cap-color: ;--bs-card-height: ;--bs-card-color: ;--bs-card-bg: #ffffff;--bs-card-img-overlay-padding: 1rem;--bs-card-group-margin: 0.75rem;position:relative;display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;min-width:0;height:var(--bs-card-height);color:var(--bs-body-color);word-wrap:break-word;background-color:var(--bs-card-bg);background-clip:border-box;border:var(--bs-card-border-width) solid var(--bs-card-border-color);border-radius:var(--bs-card-border-radius)}.card>hr{margin-right:0;margin-left:0}.card>.list-group{border-top:inherit;border-bottom:inherit}.card>.list-group:first-child{border-top-width:0;border-top-left-radius:var(--bs-card-inner-border-radius);border-top-right-radius:var(--bs-card-inner-border-radius)}.card>.list-group:last-child{border-bottom-width:0;border-bottom-right-radius:var(--bs-card-inner-border-radius);border-bottom-left-radius:var(--bs-card-inner-border-radius)}.card>.card-header+.list-group,.card>.list-group+.card-footer{border-top:0}.card-body{flex:1 1 auto;-webkit-flex:1 1 auto;padding:var(--bs-card-spacer-y) var(--bs-card-spacer-x);color:var(--bs-card-color)}.card-title{margin-bottom:var(--bs-card-title-spacer-y);color:var(--bs-card-title-color)}.card-subtitle{margin-top:calc(-0.5*var(--bs-card-title-spacer-y));margin-bottom:0;color:var(--bs-card-subtitle-color)}.card-text:last-child{margin-bottom:0}.card-link+.card-link{margin-left:var(--bs-card-spacer-x)}.card-header{padding:var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x);margin-bottom:0;color:var(--bs-card-cap-color);background-color:var(--bs-card-cap-bg);border-bottom:var(--bs-card-border-width) solid var(--bs-card-border-color)}.card-header:first-child{border-radius:var(--bs-card-inner-border-radius) var(--bs-card-inner-border-radius) 0 0}.card-footer{padding:var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x);color:var(--bs-card-cap-color);background-color:var(--bs-card-cap-bg);border-top:var(--bs-card-border-width) solid var(--bs-card-border-color)}.card-footer:last-child{border-radius:0 0 var(--bs-card-inner-border-radius) var(--bs-card-inner-border-radius)}.card-header-tabs{margin-right:calc(-0.5*var(--bs-card-cap-padding-x));margin-bottom:calc(-1*var(--bs-card-cap-padding-y));margin-left:calc(-0.5*var(--bs-card-cap-padding-x));border-bottom:0}.card-header-tabs .nav-link.active{background-color:var(--bs-card-bg);border-bottom-color:var(--bs-card-bg)}.card-header-pills{margin-right:calc(-0.5*var(--bs-card-cap-padding-x));margin-left:calc(-0.5*var(--bs-card-cap-padding-x))}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:var(--bs-card-img-overlay-padding);border-radius:var(--bs-card-inner-border-radius)}.card-img,.card-img-top,.card-img-bottom{width:100%}.card-img,.card-img-top{border-top-left-radius:var(--bs-card-inner-border-radius);border-top-right-radius:var(--bs-card-inner-border-radius)}.card-img,.card-img-bottom{border-bottom-right-radius:var(--bs-card-inner-border-radius);border-bottom-left-radius:var(--bs-card-inner-border-radius)}.card-group>.card{margin-bottom:var(--bs-card-group-margin)}@media(min-width: 576px){.card-group{display:flex;display:-webkit-flex;flex-flow:row wrap;-webkit-flex-flow:row wrap}.card-group>.card{flex:1 0 0%;-webkit-flex:1 0 0%;margin-bottom:0}.card-group>.card+.card{margin-left:0;border-left:0}.card-group>.card:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.card-group>.card:not(:last-child) .card-img-top,.card-group>.card:not(:last-child) .card-header{border-top-right-radius:0}.card-group>.card:not(:last-child) .card-img-bottom,.card-group>.card:not(:last-child) .card-footer{border-bottom-right-radius:0}.card-group>.card:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.card-group>.card:not(:first-child) .card-img-top,.card-group>.card:not(:first-child) .card-header{border-top-left-radius:0}.card-group>.card:not(:first-child) .card-img-bottom,.card-group>.card:not(:first-child) .card-footer{border-bottom-left-radius:0}}.accordion{--bs-accordion-color: #212529;--bs-accordion-bg: #ffffff;--bs-accordion-transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out, border-radius 0.15s ease;--bs-accordion-border-color: #dee2e6;--bs-accordion-border-width: 1px;--bs-accordion-border-radius: 0.375rem;--bs-accordion-inner-border-radius: calc(0.375rem - 1px);--bs-accordion-btn-padding-x: 1.25rem;--bs-accordion-btn-padding-y: 1rem;--bs-accordion-btn-color: #212529;--bs-accordion-btn-bg: #ffffff;--bs-accordion-btn-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23212529'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");--bs-accordion-btn-icon-width: 1.25rem;--bs-accordion-btn-icon-transform: rotate(-180deg);--bs-accordion-btn-icon-transition: transform 0.2s ease-in-out;--bs-accordion-btn-active-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23052c65'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");--bs-accordion-btn-focus-border-color: #86b7fe;--bs-accordion-btn-focus-box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);--bs-accordion-body-padding-x: 1.25rem;--bs-accordion-body-padding-y: 1rem;--bs-accordion-active-color: #052c65;--bs-accordion-active-bg: #cfe2ff}.accordion-button{position:relative;display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;width:100%;padding:var(--bs-accordion-btn-padding-y) var(--bs-accordion-btn-padding-x);font-size:1rem;color:var(--bs-accordion-btn-color);text-align:left;background-color:var(--bs-accordion-btn-bg);border:0;border-radius:0;overflow-anchor:none;transition:var(--bs-accordion-transition)}@media(prefers-reduced-motion: reduce){.accordion-button{transition:none}}.accordion-button:not(.collapsed){color:var(--bs-accordion-active-color);background-color:var(--bs-accordion-active-bg);box-shadow:inset 0 calc(-1*var(--bs-accordion-border-width)) 0 var(--bs-accordion-border-color)}.accordion-button:not(.collapsed)::after{background-image:var(--bs-accordion-btn-active-icon);transform:var(--bs-accordion-btn-icon-transform)}.accordion-button::after{flex-shrink:0;-webkit-flex-shrink:0;width:var(--bs-accordion-btn-icon-width);height:var(--bs-accordion-btn-icon-width);margin-left:auto;content:"";background-image:var(--bs-accordion-btn-icon);background-repeat:no-repeat;background-size:var(--bs-accordion-btn-icon-width);transition:var(--bs-accordion-btn-icon-transition)}@media(prefers-reduced-motion: reduce){.accordion-button::after{transition:none}}.accordion-button:hover{z-index:2}.accordion-button:focus{z-index:3;border-color:var(--bs-accordion-btn-focus-border-color);outline:0;box-shadow:var(--bs-accordion-btn-focus-box-shadow)}.accordion-header{margin-bottom:0}.accordion-item{color:var(--bs-accordion-color);background-color:var(--bs-accordion-bg);border:var(--bs-accordion-border-width) solid var(--bs-accordion-border-color)}.accordion-item:first-of-type{border-top-left-radius:var(--bs-accordion-border-radius);border-top-right-radius:var(--bs-accordion-border-radius)}.accordion-item:first-of-type .accordion-button{border-top-left-radius:var(--bs-accordion-inner-border-radius);border-top-right-radius:var(--bs-accordion-inner-border-radius)}.accordion-item:not(:first-of-type){border-top:0}.accordion-item:last-of-type{border-bottom-right-radius:var(--bs-accordion-border-radius);border-bottom-left-radius:var(--bs-accordion-border-radius)}.accordion-item:last-of-type .accordion-button.collapsed{border-bottom-right-radius:var(--bs-accordion-inner-border-radius);border-bottom-left-radius:var(--bs-accordion-inner-border-radius)}.accordion-item:last-of-type .accordion-collapse{border-bottom-right-radius:var(--bs-accordion-border-radius);border-bottom-left-radius:var(--bs-accordion-border-radius)}.accordion-body{padding:var(--bs-accordion-body-padding-y) var(--bs-accordion-body-padding-x)}.accordion-flush .accordion-collapse{border-width:0}.accordion-flush .accordion-item{border-right:0;border-left:0;border-radius:0}.accordion-flush .accordion-item:first-child{border-top:0}.accordion-flush .accordion-item:last-child{border-bottom:0}.accordion-flush .accordion-item .accordion-button,.accordion-flush .accordion-item .accordion-button.collapsed{border-radius:0}[data-bs-theme=dark] .accordion-button::after{--bs-accordion-btn-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%236ea8fe'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");--bs-accordion-btn-active-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%236ea8fe'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e")}.breadcrumb{--bs-breadcrumb-padding-x: 0;--bs-breadcrumb-padding-y: 0;--bs-breadcrumb-margin-bottom: 1rem;--bs-breadcrumb-bg: ;--bs-breadcrumb-border-radius: ;--bs-breadcrumb-divider-color: rgba(33, 37, 41, 0.75);--bs-breadcrumb-item-padding-x: 0.5rem;--bs-breadcrumb-item-active-color: rgba(33, 37, 41, 0.75);display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;padding:var(--bs-breadcrumb-padding-y) var(--bs-breadcrumb-padding-x);margin-bottom:var(--bs-breadcrumb-margin-bottom);font-size:var(--bs-breadcrumb-font-size);list-style:none;background-color:var(--bs-breadcrumb-bg);border-radius:var(--bs-breadcrumb-border-radius)}.breadcrumb-item+.breadcrumb-item{padding-left:var(--bs-breadcrumb-item-padding-x)}.breadcrumb-item+.breadcrumb-item::before{float:left;padding-right:var(--bs-breadcrumb-item-padding-x);color:var(--bs-breadcrumb-divider-color);content:var(--bs-breadcrumb-divider, ">") /* rtl: var(--bs-breadcrumb-divider, ">") */}.breadcrumb-item.active{color:var(--bs-breadcrumb-item-active-color)}.pagination{--bs-pagination-padding-x: 0.75rem;--bs-pagination-padding-y: 0.375rem;--bs-pagination-font-size:1rem;--bs-pagination-color: #0d6efd;--bs-pagination-bg: #ffffff;--bs-pagination-border-width: 1px;--bs-pagination-border-color: #dee2e6;--bs-pagination-border-radius: 0.375rem;--bs-pagination-hover-color: #0a58ca;--bs-pagination-hover-bg: #f8f9fa;--bs-pagination-hover-border-color: #dee2e6;--bs-pagination-focus-color: #0a58ca;--bs-pagination-focus-bg: #e9ecef;--bs-pagination-focus-box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);--bs-pagination-active-color: #ffffff;--bs-pagination-active-bg: #0d6efd;--bs-pagination-active-border-color: #0d6efd;--bs-pagination-disabled-color: rgba(33, 37, 41, 0.75);--bs-pagination-disabled-bg: #e9ecef;--bs-pagination-disabled-border-color: #dee2e6;display:flex;display:-webkit-flex;padding-left:0;list-style:none}.page-link{position:relative;display:block;padding:var(--bs-pagination-padding-y) var(--bs-pagination-padding-x);font-size:var(--bs-pagination-font-size);color:var(--bs-pagination-color);text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;background-color:var(--bs-pagination-bg);border:var(--bs-pagination-border-width) solid var(--bs-pagination-border-color);transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.page-link{transition:none}}.page-link:hover{z-index:2;color:var(--bs-pagination-hover-color);background-color:var(--bs-pagination-hover-bg);border-color:var(--bs-pagination-hover-border-color)}.page-link:focus{z-index:3;color:var(--bs-pagination-focus-color);background-color:var(--bs-pagination-focus-bg);outline:0;box-shadow:var(--bs-pagination-focus-box-shadow)}.page-link.active,.active>.page-link{z-index:3;color:var(--bs-pagination-active-color);background-color:var(--bs-pagination-active-bg);border-color:var(--bs-pagination-active-border-color)}.page-link.disabled,.disabled>.page-link{color:var(--bs-pagination-disabled-color);pointer-events:none;background-color:var(--bs-pagination-disabled-bg);border-color:var(--bs-pagination-disabled-border-color)}.page-item:not(:first-child) .page-link{margin-left:calc(1px*-1)}.page-item:first-child .page-link{border-top-left-radius:var(--bs-pagination-border-radius);border-bottom-left-radius:var(--bs-pagination-border-radius)}.page-item:last-child .page-link{border-top-right-radius:var(--bs-pagination-border-radius);border-bottom-right-radius:var(--bs-pagination-border-radius)}.pagination-lg{--bs-pagination-padding-x: 1.5rem;--bs-pagination-padding-y: 0.75rem;--bs-pagination-font-size:1.25rem;--bs-pagination-border-radius: 0.5rem}.pagination-sm{--bs-pagination-padding-x: 0.5rem;--bs-pagination-padding-y: 0.25rem;--bs-pagination-font-size:0.875rem;--bs-pagination-border-radius: 0.25rem}.badge{--bs-badge-padding-x: 0.65em;--bs-badge-padding-y: 0.35em;--bs-badge-font-size:0.75em;--bs-badge-font-weight: 700;--bs-badge-color: #ffffff;--bs-badge-border-radius: 0.375rem;display:inline-block;padding:var(--bs-badge-padding-y) var(--bs-badge-padding-x);font-size:var(--bs-badge-font-size);font-weight:var(--bs-badge-font-weight);line-height:1;color:var(--bs-badge-color);text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:var(--bs-badge-border-radius)}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.alert{--bs-alert-bg: transparent;--bs-alert-padding-x: 1rem;--bs-alert-padding-y: 1rem;--bs-alert-margin-bottom: 1rem;--bs-alert-color: inherit;--bs-alert-border-color: transparent;--bs-alert-border: 1px solid var(--bs-alert-border-color);--bs-alert-border-radius: 0.375rem;--bs-alert-link-color: inherit;position:relative;padding:var(--bs-alert-padding-y) var(--bs-alert-padding-x);margin-bottom:var(--bs-alert-margin-bottom);color:var(--bs-alert-color);background-color:var(--bs-alert-bg);border:var(--bs-alert-border);border-radius:var(--bs-alert-border-radius)}.alert-heading{color:inherit}.alert-link{font-weight:700;color:var(--bs-alert-link-color)}.alert-dismissible{padding-right:3rem}.alert-dismissible .btn-close{position:absolute;top:0;right:0;z-index:2;padding:1.25rem 1rem}.alert-default{--bs-alert-color: var(--bs-default-text-emphasis);--bs-alert-bg: var(--bs-default-bg-subtle);--bs-alert-border-color: var(--bs-default-border-subtle);--bs-alert-link-color: var(--bs-default-text-emphasis)}.alert-primary{--bs-alert-color: var(--bs-primary-text-emphasis);--bs-alert-bg: var(--bs-primary-bg-subtle);--bs-alert-border-color: var(--bs-primary-border-subtle);--bs-alert-link-color: var(--bs-primary-text-emphasis)}.alert-secondary{--bs-alert-color: var(--bs-secondary-text-emphasis);--bs-alert-bg: var(--bs-secondary-bg-subtle);--bs-alert-border-color: var(--bs-secondary-border-subtle);--bs-alert-link-color: var(--bs-secondary-text-emphasis)}.alert-success{--bs-alert-color: var(--bs-success-text-emphasis);--bs-alert-bg: var(--bs-success-bg-subtle);--bs-alert-border-color: var(--bs-success-border-subtle);--bs-alert-link-color: var(--bs-success-text-emphasis)}.alert-info{--bs-alert-color: var(--bs-info-text-emphasis);--bs-alert-bg: var(--bs-info-bg-subtle);--bs-alert-border-color: var(--bs-info-border-subtle);--bs-alert-link-color: var(--bs-info-text-emphasis)}.alert-warning{--bs-alert-color: var(--bs-warning-text-emphasis);--bs-alert-bg: var(--bs-warning-bg-subtle);--bs-alert-border-color: var(--bs-warning-border-subtle);--bs-alert-link-color: var(--bs-warning-text-emphasis)}.alert-danger{--bs-alert-color: var(--bs-danger-text-emphasis);--bs-alert-bg: var(--bs-danger-bg-subtle);--bs-alert-border-color: var(--bs-danger-border-subtle);--bs-alert-link-color: var(--bs-danger-text-emphasis)}.alert-light{--bs-alert-color: var(--bs-light-text-emphasis);--bs-alert-bg: var(--bs-light-bg-subtle);--bs-alert-border-color: var(--bs-light-border-subtle);--bs-alert-link-color: var(--bs-light-text-emphasis)}.alert-dark{--bs-alert-color: var(--bs-dark-text-emphasis);--bs-alert-bg: var(--bs-dark-bg-subtle);--bs-alert-border-color: var(--bs-dark-border-subtle);--bs-alert-link-color: var(--bs-dark-text-emphasis)}@keyframes progress-bar-stripes{0%{background-position-x:1rem}}.progress,.progress-stacked{--bs-progress-height: 1rem;--bs-progress-font-size:0.75rem;--bs-progress-bg: #e9ecef;--bs-progress-border-radius: 0.375rem;--bs-progress-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.075);--bs-progress-bar-color: #ffffff;--bs-progress-bar-bg: #0d6efd;--bs-progress-bar-transition: width 0.6s ease;display:flex;display:-webkit-flex;height:var(--bs-progress-height);overflow:hidden;font-size:var(--bs-progress-font-size);background-color:var(--bs-progress-bg);border-radius:var(--bs-progress-border-radius)}.progress-bar{display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;justify-content:center;-webkit-justify-content:center;overflow:hidden;color:var(--bs-progress-bar-color);text-align:center;white-space:nowrap;background-color:var(--bs-progress-bar-bg);transition:var(--bs-progress-bar-transition)}@media(prefers-reduced-motion: reduce){.progress-bar{transition:none}}.progress-bar-striped{background-image:linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-size:var(--bs-progress-height) var(--bs-progress-height)}.progress-stacked>.progress{overflow:visible}.progress-stacked>.progress>.progress-bar{width:100%}.progress-bar-animated{animation:1s linear infinite progress-bar-stripes}@media(prefers-reduced-motion: reduce){.progress-bar-animated{animation:none}}.list-group{--bs-list-group-color: #212529;--bs-list-group-bg: #ffffff;--bs-list-group-border-color: #dee2e6;--bs-list-group-border-width: 1px;--bs-list-group-border-radius: 0.375rem;--bs-list-group-item-padding-x: 1rem;--bs-list-group-item-padding-y: 0.5rem;--bs-list-group-action-color: rgba(33, 37, 41, 0.75);--bs-list-group-action-hover-color: #000;--bs-list-group-action-hover-bg: #f8f9fa;--bs-list-group-action-active-color: #212529;--bs-list-group-action-active-bg: #e9ecef;--bs-list-group-disabled-color: rgba(33, 37, 41, 0.75);--bs-list-group-disabled-bg: #ffffff;--bs-list-group-active-color: #ffffff;--bs-list-group-active-bg: #0d6efd;--bs-list-group-active-border-color: #0d6efd;display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;padding-left:0;margin-bottom:0;border-radius:var(--bs-list-group-border-radius)}.list-group-numbered{list-style-type:none;counter-reset:section}.list-group-numbered>.list-group-item::before{content:counters(section, ".") ". ";counter-increment:section}.list-group-item-action{width:100%;color:var(--bs-list-group-action-color);text-align:inherit}.list-group-item-action:hover,.list-group-item-action:focus{z-index:1;color:var(--bs-list-group-action-hover-color);text-decoration:none;background-color:var(--bs-list-group-action-hover-bg)}.list-group-item-action:active{color:var(--bs-list-group-action-active-color);background-color:var(--bs-list-group-action-active-bg)}.list-group-item{position:relative;display:block;padding:var(--bs-list-group-item-padding-y) var(--bs-list-group-item-padding-x);color:var(--bs-list-group-color);text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;background-color:var(--bs-list-group-bg);border:var(--bs-list-group-border-width) solid var(--bs-list-group-border-color)}.list-group-item:first-child{border-top-left-radius:inherit;border-top-right-radius:inherit}.list-group-item:last-child{border-bottom-right-radius:inherit;border-bottom-left-radius:inherit}.list-group-item.disabled,.list-group-item:disabled{color:var(--bs-list-group-disabled-color);pointer-events:none;background-color:var(--bs-list-group-disabled-bg)}.list-group-item.active{z-index:2;color:var(--bs-list-group-active-color);background-color:var(--bs-list-group-active-bg);border-color:var(--bs-list-group-active-border-color)}.list-group-item+.list-group-item{border-top-width:0}.list-group-item+.list-group-item.active{margin-top:calc(-1*var(--bs-list-group-border-width));border-top-width:var(--bs-list-group-border-width)}.list-group-horizontal{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal>.list-group-item.active{margin-top:0}.list-group-horizontal>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal>.list-group-item+.list-group-item.active{margin-left:calc(-1*var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}@media(min-width: 576px){.list-group-horizontal-sm{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal-sm>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-sm>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-sm>.list-group-item.active{margin-top:0}.list-group-horizontal-sm>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-sm>.list-group-item+.list-group-item.active{margin-left:calc(-1*var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media(min-width: 768px){.list-group-horizontal-md{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal-md>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-md>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-md>.list-group-item.active{margin-top:0}.list-group-horizontal-md>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-md>.list-group-item+.list-group-item.active{margin-left:calc(-1*var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media(min-width: 992px){.list-group-horizontal-lg{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal-lg>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-lg>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-lg>.list-group-item.active{margin-top:0}.list-group-horizontal-lg>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-lg>.list-group-item+.list-group-item.active{margin-left:calc(-1*var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media(min-width: 1200px){.list-group-horizontal-xl{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal-xl>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-xl>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-xl>.list-group-item.active{margin-top:0}.list-group-horizontal-xl>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-xl>.list-group-item+.list-group-item.active{margin-left:calc(-1*var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media(min-width: 1400px){.list-group-horizontal-xxl{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal-xxl>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-xxl>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-xxl>.list-group-item.active{margin-top:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item.active{margin-left:calc(-1*var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}.list-group-flush{border-radius:0}.list-group-flush>.list-group-item{border-width:0 0 var(--bs-list-group-border-width)}.list-group-flush>.list-group-item:last-child{border-bottom-width:0}.list-group-item-default{--bs-list-group-color: var(--bs-default-text-emphasis);--bs-list-group-bg: var(--bs-default-bg-subtle);--bs-list-group-border-color: var(--bs-default-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-default-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-default-border-subtle);--bs-list-group-active-color: var(--bs-default-bg-subtle);--bs-list-group-active-bg: var(--bs-default-text-emphasis);--bs-list-group-active-border-color: var(--bs-default-text-emphasis)}.list-group-item-primary{--bs-list-group-color: var(--bs-primary-text-emphasis);--bs-list-group-bg: var(--bs-primary-bg-subtle);--bs-list-group-border-color: var(--bs-primary-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-primary-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-primary-border-subtle);--bs-list-group-active-color: var(--bs-primary-bg-subtle);--bs-list-group-active-bg: var(--bs-primary-text-emphasis);--bs-list-group-active-border-color: var(--bs-primary-text-emphasis)}.list-group-item-secondary{--bs-list-group-color: var(--bs-secondary-text-emphasis);--bs-list-group-bg: var(--bs-secondary-bg-subtle);--bs-list-group-border-color: var(--bs-secondary-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-secondary-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-secondary-border-subtle);--bs-list-group-active-color: var(--bs-secondary-bg-subtle);--bs-list-group-active-bg: var(--bs-secondary-text-emphasis);--bs-list-group-active-border-color: var(--bs-secondary-text-emphasis)}.list-group-item-success{--bs-list-group-color: var(--bs-success-text-emphasis);--bs-list-group-bg: var(--bs-success-bg-subtle);--bs-list-group-border-color: var(--bs-success-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-success-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-success-border-subtle);--bs-list-group-active-color: var(--bs-success-bg-subtle);--bs-list-group-active-bg: var(--bs-success-text-emphasis);--bs-list-group-active-border-color: var(--bs-success-text-emphasis)}.list-group-item-info{--bs-list-group-color: var(--bs-info-text-emphasis);--bs-list-group-bg: var(--bs-info-bg-subtle);--bs-list-group-border-color: var(--bs-info-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-info-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-info-border-subtle);--bs-list-group-active-color: var(--bs-info-bg-subtle);--bs-list-group-active-bg: var(--bs-info-text-emphasis);--bs-list-group-active-border-color: var(--bs-info-text-emphasis)}.list-group-item-warning{--bs-list-group-color: var(--bs-warning-text-emphasis);--bs-list-group-bg: var(--bs-warning-bg-subtle);--bs-list-group-border-color: var(--bs-warning-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-warning-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-warning-border-subtle);--bs-list-group-active-color: var(--bs-warning-bg-subtle);--bs-list-group-active-bg: var(--bs-warning-text-emphasis);--bs-list-group-active-border-color: var(--bs-warning-text-emphasis)}.list-group-item-danger{--bs-list-group-color: var(--bs-danger-text-emphasis);--bs-list-group-bg: var(--bs-danger-bg-subtle);--bs-list-group-border-color: var(--bs-danger-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-danger-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-danger-border-subtle);--bs-list-group-active-color: var(--bs-danger-bg-subtle);--bs-list-group-active-bg: var(--bs-danger-text-emphasis);--bs-list-group-active-border-color: var(--bs-danger-text-emphasis)}.list-group-item-light{--bs-list-group-color: var(--bs-light-text-emphasis);--bs-list-group-bg: var(--bs-light-bg-subtle);--bs-list-group-border-color: var(--bs-light-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-light-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-light-border-subtle);--bs-list-group-active-color: var(--bs-light-bg-subtle);--bs-list-group-active-bg: var(--bs-light-text-emphasis);--bs-list-group-active-border-color: var(--bs-light-text-emphasis)}.list-group-item-dark{--bs-list-group-color: var(--bs-dark-text-emphasis);--bs-list-group-bg: var(--bs-dark-bg-subtle);--bs-list-group-border-color: var(--bs-dark-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-dark-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-dark-border-subtle);--bs-list-group-active-color: var(--bs-dark-bg-subtle);--bs-list-group-active-bg: var(--bs-dark-text-emphasis);--bs-list-group-active-border-color: var(--bs-dark-text-emphasis)}.btn-close{--bs-btn-close-color: #000;--bs-btn-close-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath d='M.293.293a1 1 0 0 1 1.414 0L8 6.586 14.293.293a1 1 0 1 1 1.414 1.414L9.414 8l6.293 6.293a1 1 0 0 1-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 0 1-1.414-1.414L6.586 8 .293 1.707a1 1 0 0 1 0-1.414z'/%3e%3c/svg%3e");--bs-btn-close-opacity: 0.5;--bs-btn-close-hover-opacity: 0.75;--bs-btn-close-focus-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);--bs-btn-close-focus-opacity: 1;--bs-btn-close-disabled-opacity: 0.25;--bs-btn-close-white-filter: invert(1) grayscale(100%) brightness(200%);box-sizing:content-box;width:1em;height:1em;padding:.25em .25em;color:var(--bs-btn-close-color);background:rgba(0,0,0,0) var(--bs-btn-close-bg) center/1em auto no-repeat;border:0;border-radius:.375rem;opacity:var(--bs-btn-close-opacity)}.btn-close:hover{color:var(--bs-btn-close-color);text-decoration:none;opacity:var(--bs-btn-close-hover-opacity)}.btn-close:focus{outline:0;box-shadow:var(--bs-btn-close-focus-shadow);opacity:var(--bs-btn-close-focus-opacity)}.btn-close:disabled,.btn-close.disabled{pointer-events:none;user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;opacity:var(--bs-btn-close-disabled-opacity)}.btn-close-white{filter:var(--bs-btn-close-white-filter)}[data-bs-theme=dark] .btn-close{filter:var(--bs-btn-close-white-filter)}.toast{--bs-toast-zindex: 1090;--bs-toast-padding-x: 0.75rem;--bs-toast-padding-y: 0.5rem;--bs-toast-spacing: 1.5rem;--bs-toast-max-width: 350px;--bs-toast-font-size:0.875rem;--bs-toast-color: ;--bs-toast-bg: rgba(255, 255, 255, 0.85);--bs-toast-border-width: 1px;--bs-toast-border-color: rgba(0, 0, 0, 0.175);--bs-toast-border-radius: 0.375rem;--bs-toast-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);--bs-toast-header-color: rgba(33, 37, 41, 0.75);--bs-toast-header-bg: rgba(255, 255, 255, 0.85);--bs-toast-header-border-color: rgba(0, 0, 0, 0.175);width:var(--bs-toast-max-width);max-width:100%;font-size:var(--bs-toast-font-size);color:var(--bs-toast-color);pointer-events:auto;background-color:var(--bs-toast-bg);background-clip:padding-box;border:var(--bs-toast-border-width) solid var(--bs-toast-border-color);box-shadow:var(--bs-toast-box-shadow);border-radius:var(--bs-toast-border-radius)}.toast.showing{opacity:0}.toast:not(.show){display:none}.toast-container{--bs-toast-zindex: 1090;position:absolute;z-index:var(--bs-toast-zindex);width:max-content;width:-webkit-max-content;width:-moz-max-content;width:-ms-max-content;width:-o-max-content;max-width:100%;pointer-events:none}.toast-container>:not(:last-child){margin-bottom:var(--bs-toast-spacing)}.toast-header{display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;padding:var(--bs-toast-padding-y) var(--bs-toast-padding-x);color:var(--bs-toast-header-color);background-color:var(--bs-toast-header-bg);background-clip:padding-box;border-bottom:var(--bs-toast-border-width) solid var(--bs-toast-header-border-color);border-top-left-radius:calc(var(--bs-toast-border-radius) - var(--bs-toast-border-width));border-top-right-radius:calc(var(--bs-toast-border-radius) - var(--bs-toast-border-width))}.toast-header .btn-close{margin-right:calc(-0.5*var(--bs-toast-padding-x));margin-left:var(--bs-toast-padding-x)}.toast-body{padding:var(--bs-toast-padding-x);word-wrap:break-word}.modal{--bs-modal-zindex: 1055;--bs-modal-width: 500px;--bs-modal-padding: 1rem;--bs-modal-margin: 0.5rem;--bs-modal-color: ;--bs-modal-bg: #ffffff;--bs-modal-border-color: rgba(0, 0, 0, 0.175);--bs-modal-border-width: 1px;--bs-modal-border-radius: 0.5rem;--bs-modal-box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);--bs-modal-inner-border-radius: calc(0.5rem - 1px);--bs-modal-header-padding-x: 1rem;--bs-modal-header-padding-y: 1rem;--bs-modal-header-padding: 1rem 1rem;--bs-modal-header-border-color: #dee2e6;--bs-modal-header-border-width: 1px;--bs-modal-title-line-height: 1.5;--bs-modal-footer-gap: 0.5rem;--bs-modal-footer-bg: ;--bs-modal-footer-border-color: #dee2e6;--bs-modal-footer-border-width: 1px;position:fixed;top:0;left:0;z-index:var(--bs-modal-zindex);display:none;width:100%;height:100%;overflow-x:hidden;overflow-y:auto;outline:0}.modal-dialog{position:relative;width:auto;margin:var(--bs-modal-margin);pointer-events:none}.modal.fade .modal-dialog{transition:transform .3s ease-out;transform:translate(0, -50px)}@media(prefers-reduced-motion: reduce){.modal.fade .modal-dialog{transition:none}}.modal.show .modal-dialog{transform:none}.modal.modal-static .modal-dialog{transform:scale(1.02)}.modal-dialog-scrollable{height:calc(100% - var(--bs-modal-margin)*2)}.modal-dialog-scrollable .modal-content{max-height:100%;overflow:hidden}.modal-dialog-scrollable .modal-body{overflow-y:auto}.modal-dialog-centered{display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;min-height:calc(100% - var(--bs-modal-margin)*2)}.modal-content{position:relative;display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;width:100%;color:var(--bs-modal-color);pointer-events:auto;background-color:var(--bs-modal-bg);background-clip:padding-box;border:var(--bs-modal-border-width) solid var(--bs-modal-border-color);border-radius:var(--bs-modal-border-radius);outline:0}.modal-backdrop{--bs-backdrop-zindex: 1050;--bs-backdrop-bg: #000;--bs-backdrop-opacity: 0.5;position:fixed;top:0;left:0;z-index:var(--bs-backdrop-zindex);width:100vw;height:100vh;background-color:var(--bs-backdrop-bg)}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:var(--bs-backdrop-opacity)}.modal-header{display:flex;display:-webkit-flex;flex-shrink:0;-webkit-flex-shrink:0;align-items:center;-webkit-align-items:center;justify-content:space-between;-webkit-justify-content:space-between;padding:var(--bs-modal-header-padding);border-bottom:var(--bs-modal-header-border-width) solid var(--bs-modal-header-border-color);border-top-left-radius:var(--bs-modal-inner-border-radius);border-top-right-radius:var(--bs-modal-inner-border-radius)}.modal-header .btn-close{padding:calc(var(--bs-modal-header-padding-y)*.5) calc(var(--bs-modal-header-padding-x)*.5);margin:calc(-0.5*var(--bs-modal-header-padding-y)) calc(-0.5*var(--bs-modal-header-padding-x)) calc(-0.5*var(--bs-modal-header-padding-y)) auto}.modal-title{margin-bottom:0;line-height:var(--bs-modal-title-line-height)}.modal-body{position:relative;flex:1 1 auto;-webkit-flex:1 1 auto;padding:var(--bs-modal-padding)}.modal-footer{display:flex;display:-webkit-flex;flex-shrink:0;-webkit-flex-shrink:0;flex-wrap:wrap;-webkit-flex-wrap:wrap;align-items:center;-webkit-align-items:center;justify-content:flex-end;-webkit-justify-content:flex-end;padding:calc(var(--bs-modal-padding) - var(--bs-modal-footer-gap)*.5);background-color:var(--bs-modal-footer-bg);border-top:var(--bs-modal-footer-border-width) solid var(--bs-modal-footer-border-color);border-bottom-right-radius:var(--bs-modal-inner-border-radius);border-bottom-left-radius:var(--bs-modal-inner-border-radius)}.modal-footer>*{margin:calc(var(--bs-modal-footer-gap)*.5)}@media(min-width: 576px){.modal{--bs-modal-margin: 1.75rem;--bs-modal-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15)}.modal-dialog{max-width:var(--bs-modal-width);margin-right:auto;margin-left:auto}.modal-sm{--bs-modal-width: 300px}}@media(min-width: 992px){.modal-lg,.modal-xl{--bs-modal-width: 800px}}@media(min-width: 1200px){.modal-xl{--bs-modal-width: 1140px}}.modal-fullscreen{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen .modal-header,.modal-fullscreen .modal-footer{border-radius:0}.modal-fullscreen .modal-body{overflow-y:auto}@media(max-width: 575.98px){.modal-fullscreen-sm-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-sm-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-sm-down .modal-header,.modal-fullscreen-sm-down .modal-footer{border-radius:0}.modal-fullscreen-sm-down .modal-body{overflow-y:auto}}@media(max-width: 767.98px){.modal-fullscreen-md-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-md-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-md-down .modal-header,.modal-fullscreen-md-down .modal-footer{border-radius:0}.modal-fullscreen-md-down .modal-body{overflow-y:auto}}@media(max-width: 991.98px){.modal-fullscreen-lg-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-lg-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-lg-down .modal-header,.modal-fullscreen-lg-down .modal-footer{border-radius:0}.modal-fullscreen-lg-down .modal-body{overflow-y:auto}}@media(max-width: 1199.98px){.modal-fullscreen-xl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xl-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-xl-down .modal-header,.modal-fullscreen-xl-down .modal-footer{border-radius:0}.modal-fullscreen-xl-down .modal-body{overflow-y:auto}}@media(max-width: 1399.98px){.modal-fullscreen-xxl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xxl-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-xxl-down .modal-header,.modal-fullscreen-xxl-down .modal-footer{border-radius:0}.modal-fullscreen-xxl-down .modal-body{overflow-y:auto}}.tooltip{--bs-tooltip-zindex: 1080;--bs-tooltip-max-width: 200px;--bs-tooltip-padding-x: 0.5rem;--bs-tooltip-padding-y: 0.25rem;--bs-tooltip-margin: ;--bs-tooltip-font-size:0.875rem;--bs-tooltip-color: #ffffff;--bs-tooltip-bg: #000;--bs-tooltip-border-radius: 0.375rem;--bs-tooltip-opacity: 0.9;--bs-tooltip-arrow-width: 0.8rem;--bs-tooltip-arrow-height: 0.4rem;z-index:var(--bs-tooltip-zindex);display:block;margin:var(--bs-tooltip-margin);font-family:system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue","Noto Sans","Liberation Sans",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;white-space:normal;word-spacing:normal;line-break:auto;font-size:var(--bs-tooltip-font-size);word-wrap:break-word;opacity:0}.tooltip.show{opacity:var(--bs-tooltip-opacity)}.tooltip .tooltip-arrow{display:block;width:var(--bs-tooltip-arrow-width);height:var(--bs-tooltip-arrow-height)}.tooltip .tooltip-arrow::before{position:absolute;content:"";border-color:rgba(0,0,0,0);border-style:solid}.bs-tooltip-top .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow{bottom:calc(-1*var(--bs-tooltip-arrow-height))}.bs-tooltip-top .tooltip-arrow::before,.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow::before{top:-1px;border-width:var(--bs-tooltip-arrow-height) calc(var(--bs-tooltip-arrow-width)*.5) 0;border-top-color:var(--bs-tooltip-bg)}.bs-tooltip-end .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow{left:calc(-1*var(--bs-tooltip-arrow-height));width:var(--bs-tooltip-arrow-height);height:var(--bs-tooltip-arrow-width)}.bs-tooltip-end .tooltip-arrow::before,.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow::before{right:-1px;border-width:calc(var(--bs-tooltip-arrow-width)*.5) var(--bs-tooltip-arrow-height) calc(var(--bs-tooltip-arrow-width)*.5) 0;border-right-color:var(--bs-tooltip-bg)}.bs-tooltip-bottom .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow{top:calc(-1*var(--bs-tooltip-arrow-height))}.bs-tooltip-bottom .tooltip-arrow::before,.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow::before{bottom:-1px;border-width:0 calc(var(--bs-tooltip-arrow-width)*.5) var(--bs-tooltip-arrow-height);border-bottom-color:var(--bs-tooltip-bg)}.bs-tooltip-start .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow{right:calc(-1*var(--bs-tooltip-arrow-height));width:var(--bs-tooltip-arrow-height);height:var(--bs-tooltip-arrow-width)}.bs-tooltip-start .tooltip-arrow::before,.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow::before{left:-1px;border-width:calc(var(--bs-tooltip-arrow-width)*.5) 0 calc(var(--bs-tooltip-arrow-width)*.5) var(--bs-tooltip-arrow-height);border-left-color:var(--bs-tooltip-bg)}.tooltip-inner{max-width:var(--bs-tooltip-max-width);padding:var(--bs-tooltip-padding-y) var(--bs-tooltip-padding-x);color:var(--bs-tooltip-color);text-align:center;background-color:var(--bs-tooltip-bg);border-radius:var(--bs-tooltip-border-radius)}.popover{--bs-popover-zindex: 1070;--bs-popover-max-width: 276px;--bs-popover-font-size:0.875rem;--bs-popover-bg: #ffffff;--bs-popover-border-width: 1px;--bs-popover-border-color: rgba(0, 0, 0, 0.175);--bs-popover-border-radius: 0.5rem;--bs-popover-inner-border-radius: calc(0.5rem - 1px);--bs-popover-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);--bs-popover-header-padding-x: 1rem;--bs-popover-header-padding-y: 0.5rem;--bs-popover-header-font-size:1rem;--bs-popover-header-color: inherit;--bs-popover-header-bg: #e9ecef;--bs-popover-body-padding-x: 1rem;--bs-popover-body-padding-y: 1rem;--bs-popover-body-color: #212529;--bs-popover-arrow-width: 1rem;--bs-popover-arrow-height: 0.5rem;--bs-popover-arrow-border: var(--bs-popover-border-color);z-index:var(--bs-popover-zindex);display:block;max-width:var(--bs-popover-max-width);font-family:system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue","Noto Sans","Liberation Sans",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;white-space:normal;word-spacing:normal;line-break:auto;font-size:var(--bs-popover-font-size);word-wrap:break-word;background-color:var(--bs-popover-bg);background-clip:padding-box;border:var(--bs-popover-border-width) solid var(--bs-popover-border-color);border-radius:var(--bs-popover-border-radius)}.popover .popover-arrow{display:block;width:var(--bs-popover-arrow-width);height:var(--bs-popover-arrow-height)}.popover .popover-arrow::before,.popover .popover-arrow::after{position:absolute;display:block;content:"";border-color:rgba(0,0,0,0);border-style:solid;border-width:0}.bs-popover-top>.popover-arrow,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow{bottom:calc(-1*(var(--bs-popover-arrow-height)) - var(--bs-popover-border-width))}.bs-popover-top>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::before,.bs-popover-top>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::after{border-width:var(--bs-popover-arrow-height) calc(var(--bs-popover-arrow-width)*.5) 0}.bs-popover-top>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::before{bottom:0;border-top-color:var(--bs-popover-arrow-border)}.bs-popover-top>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::after{bottom:var(--bs-popover-border-width);border-top-color:var(--bs-popover-bg)}.bs-popover-end>.popover-arrow,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow{left:calc(-1*(var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));width:var(--bs-popover-arrow-height);height:var(--bs-popover-arrow-width)}.bs-popover-end>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::before,.bs-popover-end>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::after{border-width:calc(var(--bs-popover-arrow-width)*.5) var(--bs-popover-arrow-height) calc(var(--bs-popover-arrow-width)*.5) 0}.bs-popover-end>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::before{left:0;border-right-color:var(--bs-popover-arrow-border)}.bs-popover-end>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::after{left:var(--bs-popover-border-width);border-right-color:var(--bs-popover-bg)}.bs-popover-bottom>.popover-arrow,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow{top:calc(-1*(var(--bs-popover-arrow-height)) - var(--bs-popover-border-width))}.bs-popover-bottom>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::before,.bs-popover-bottom>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::after{border-width:0 calc(var(--bs-popover-arrow-width)*.5) var(--bs-popover-arrow-height)}.bs-popover-bottom>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::before{top:0;border-bottom-color:var(--bs-popover-arrow-border)}.bs-popover-bottom>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::after{top:var(--bs-popover-border-width);border-bottom-color:var(--bs-popover-bg)}.bs-popover-bottom .popover-header::before,.bs-popover-auto[data-popper-placement^=bottom] .popover-header::before{position:absolute;top:0;left:50%;display:block;width:var(--bs-popover-arrow-width);margin-left:calc(-0.5*var(--bs-popover-arrow-width));content:"";border-bottom:var(--bs-popover-border-width) solid var(--bs-popover-header-bg)}.bs-popover-start>.popover-arrow,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow{right:calc(-1*(var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));width:var(--bs-popover-arrow-height);height:var(--bs-popover-arrow-width)}.bs-popover-start>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::before,.bs-popover-start>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::after{border-width:calc(var(--bs-popover-arrow-width)*.5) 0 calc(var(--bs-popover-arrow-width)*.5) var(--bs-popover-arrow-height)}.bs-popover-start>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::before{right:0;border-left-color:var(--bs-popover-arrow-border)}.bs-popover-start>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::after{right:var(--bs-popover-border-width);border-left-color:var(--bs-popover-bg)}.popover-header{padding:var(--bs-popover-header-padding-y) var(--bs-popover-header-padding-x);margin-bottom:0;font-size:var(--bs-popover-header-font-size);color:var(--bs-popover-header-color);background-color:var(--bs-popover-header-bg);border-bottom:var(--bs-popover-border-width) solid var(--bs-popover-border-color);border-top-left-radius:var(--bs-popover-inner-border-radius);border-top-right-radius:var(--bs-popover-inner-border-radius)}.popover-header:empty{display:none}.popover-body{padding:var(--bs-popover-body-padding-y) var(--bs-popover-body-padding-x);color:var(--bs-popover-body-color)}.carousel{position:relative}.carousel.pointer-event{touch-action:pan-y;-webkit-touch-action:pan-y;-moz-touch-action:pan-y;-ms-touch-action:pan-y;-o-touch-action:pan-y}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner::after{display:block;clear:both;content:""}.carousel-item{position:relative;display:none;float:left;width:100%;margin-right:-100%;backface-visibility:hidden;-webkit-backface-visibility:hidden;-moz-backface-visibility:hidden;-ms-backface-visibility:hidden;-o-backface-visibility:hidden;transition:transform .6s ease-in-out}@media(prefers-reduced-motion: reduce){.carousel-item{transition:none}}.carousel-item.active,.carousel-item-next,.carousel-item-prev{display:block}.carousel-item-next:not(.carousel-item-start),.active.carousel-item-end{transform:translateX(100%)}.carousel-item-prev:not(.carousel-item-end),.active.carousel-item-start{transform:translateX(-100%)}.carousel-fade .carousel-item{opacity:0;transition-property:opacity;transform:none}.carousel-fade .carousel-item.active,.carousel-fade .carousel-item-next.carousel-item-start,.carousel-fade .carousel-item-prev.carousel-item-end{z-index:1;opacity:1}.carousel-fade .active.carousel-item-start,.carousel-fade .active.carousel-item-end{z-index:0;opacity:0;transition:opacity 0s .6s}@media(prefers-reduced-motion: reduce){.carousel-fade .active.carousel-item-start,.carousel-fade .active.carousel-item-end{transition:none}}.carousel-control-prev,.carousel-control-next{position:absolute;top:0;bottom:0;z-index:1;display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;justify-content:center;-webkit-justify-content:center;width:15%;padding:0;color:#fff;text-align:center;background:none;border:0;opacity:.5;transition:opacity .15s ease}@media(prefers-reduced-motion: reduce){.carousel-control-prev,.carousel-control-next{transition:none}}.carousel-control-prev:hover,.carousel-control-prev:focus,.carousel-control-next:hover,.carousel-control-next:focus{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-prev-icon,.carousel-control-next-icon{display:inline-block;width:2rem;height:2rem;background-repeat:no-repeat;background-position:50%;background-size:100% 100%}.carousel-control-prev-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23ffffff'%3e%3cpath d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z'/%3e%3c/svg%3e")}.carousel-control-next-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23ffffff'%3e%3cpath d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e")}.carousel-indicators{position:absolute;right:0;bottom:0;left:0;z-index:2;display:flex;display:-webkit-flex;justify-content:center;-webkit-justify-content:center;padding:0;margin-right:15%;margin-bottom:1rem;margin-left:15%}.carousel-indicators [data-bs-target]{box-sizing:content-box;flex:0 1 auto;-webkit-flex:0 1 auto;width:30px;height:3px;padding:0;margin-right:3px;margin-left:3px;text-indent:-999px;cursor:pointer;background-color:#fff;background-clip:padding-box;border:0;border-top:10px solid rgba(0,0,0,0);border-bottom:10px solid rgba(0,0,0,0);opacity:.5;transition:opacity .6s ease}@media(prefers-reduced-motion: reduce){.carousel-indicators [data-bs-target]{transition:none}}.carousel-indicators .active{opacity:1}.carousel-caption{position:absolute;right:15%;bottom:1.25rem;left:15%;padding-top:1.25rem;padding-bottom:1.25rem;color:#fff;text-align:center}.carousel-dark .carousel-control-prev-icon,.carousel-dark .carousel-control-next-icon{filter:invert(1) grayscale(100)}.carousel-dark .carousel-indicators [data-bs-target]{background-color:#000}.carousel-dark .carousel-caption{color:#000}[data-bs-theme=dark] .carousel .carousel-control-prev-icon,[data-bs-theme=dark] .carousel .carousel-control-next-icon,[data-bs-theme=dark].carousel .carousel-control-prev-icon,[data-bs-theme=dark].carousel .carousel-control-next-icon{filter:invert(1) grayscale(100)}[data-bs-theme=dark] .carousel .carousel-indicators [data-bs-target],[data-bs-theme=dark].carousel .carousel-indicators [data-bs-target]{background-color:#000}[data-bs-theme=dark] .carousel .carousel-caption,[data-bs-theme=dark].carousel .carousel-caption{color:#000}.spinner-grow,.spinner-border{display:inline-block;width:var(--bs-spinner-width);height:var(--bs-spinner-height);vertical-align:var(--bs-spinner-vertical-align);border-radius:50%;animation:var(--bs-spinner-animation-speed) linear infinite var(--bs-spinner-animation-name)}@keyframes spinner-border{to{transform:rotate(360deg) /* rtl:ignore */}}.spinner-border{--bs-spinner-width: 2rem;--bs-spinner-height: 2rem;--bs-spinner-vertical-align: -0.125em;--bs-spinner-border-width: 0.25em;--bs-spinner-animation-speed: 0.75s;--bs-spinner-animation-name: spinner-border;border:var(--bs-spinner-border-width) solid currentcolor;border-right-color:rgba(0,0,0,0)}.spinner-border-sm{--bs-spinner-width: 1rem;--bs-spinner-height: 1rem;--bs-spinner-border-width: 0.2em}@keyframes spinner-grow{0%{transform:scale(0)}50%{opacity:1;transform:none}}.spinner-grow{--bs-spinner-width: 2rem;--bs-spinner-height: 2rem;--bs-spinner-vertical-align: -0.125em;--bs-spinner-animation-speed: 0.75s;--bs-spinner-animation-name: spinner-grow;background-color:currentcolor;opacity:0}.spinner-grow-sm{--bs-spinner-width: 1rem;--bs-spinner-height: 1rem}@media(prefers-reduced-motion: reduce){.spinner-border,.spinner-grow{--bs-spinner-animation-speed: 1.5s}}.offcanvas,.offcanvas-xxl,.offcanvas-xl,.offcanvas-lg,.offcanvas-md,.offcanvas-sm{--bs-offcanvas-zindex: 1045;--bs-offcanvas-width: 400px;--bs-offcanvas-height: 30vh;--bs-offcanvas-padding-x: 1rem;--bs-offcanvas-padding-y: 1rem;--bs-offcanvas-color: #212529;--bs-offcanvas-bg: #ffffff;--bs-offcanvas-border-width: 1px;--bs-offcanvas-border-color: rgba(0, 0, 0, 0.175);--bs-offcanvas-box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);--bs-offcanvas-transition: transform 0.3s ease-in-out;--bs-offcanvas-title-line-height: 1.5}@media(max-width: 575.98px){.offcanvas-sm{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media(max-width: 575.98px)and (prefers-reduced-motion: reduce){.offcanvas-sm{transition:none}}@media(max-width: 575.98px){.offcanvas-sm.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-sm.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-sm.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-sm.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-sm.showing,.offcanvas-sm.show:not(.hiding){transform:none}.offcanvas-sm.showing,.offcanvas-sm.hiding,.offcanvas-sm.show{visibility:visible}}@media(min-width: 576px){.offcanvas-sm{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:rgba(0,0,0,0) !important}.offcanvas-sm .offcanvas-header{display:none}.offcanvas-sm .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible;background-color:rgba(0,0,0,0) !important}}@media(max-width: 767.98px){.offcanvas-md{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media(max-width: 767.98px)and (prefers-reduced-motion: reduce){.offcanvas-md{transition:none}}@media(max-width: 767.98px){.offcanvas-md.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-md.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-md.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-md.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-md.showing,.offcanvas-md.show:not(.hiding){transform:none}.offcanvas-md.showing,.offcanvas-md.hiding,.offcanvas-md.show{visibility:visible}}@media(min-width: 768px){.offcanvas-md{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:rgba(0,0,0,0) !important}.offcanvas-md .offcanvas-header{display:none}.offcanvas-md .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible;background-color:rgba(0,0,0,0) !important}}@media(max-width: 991.98px){.offcanvas-lg{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media(max-width: 991.98px)and (prefers-reduced-motion: reduce){.offcanvas-lg{transition:none}}@media(max-width: 991.98px){.offcanvas-lg.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-lg.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-lg.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-lg.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-lg.showing,.offcanvas-lg.show:not(.hiding){transform:none}.offcanvas-lg.showing,.offcanvas-lg.hiding,.offcanvas-lg.show{visibility:visible}}@media(min-width: 992px){.offcanvas-lg{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:rgba(0,0,0,0) !important}.offcanvas-lg .offcanvas-header{display:none}.offcanvas-lg .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible;background-color:rgba(0,0,0,0) !important}}@media(max-width: 1199.98px){.offcanvas-xl{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media(max-width: 1199.98px)and (prefers-reduced-motion: reduce){.offcanvas-xl{transition:none}}@media(max-width: 1199.98px){.offcanvas-xl.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-xl.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-xl.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-xl.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-xl.showing,.offcanvas-xl.show:not(.hiding){transform:none}.offcanvas-xl.showing,.offcanvas-xl.hiding,.offcanvas-xl.show{visibility:visible}}@media(min-width: 1200px){.offcanvas-xl{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:rgba(0,0,0,0) !important}.offcanvas-xl .offcanvas-header{display:none}.offcanvas-xl .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible;background-color:rgba(0,0,0,0) !important}}@media(max-width: 1399.98px){.offcanvas-xxl{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media(max-width: 1399.98px)and (prefers-reduced-motion: reduce){.offcanvas-xxl{transition:none}}@media(max-width: 1399.98px){.offcanvas-xxl.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-xxl.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-xxl.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-xxl.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-xxl.showing,.offcanvas-xxl.show:not(.hiding){transform:none}.offcanvas-xxl.showing,.offcanvas-xxl.hiding,.offcanvas-xxl.show{visibility:visible}}@media(min-width: 1400px){.offcanvas-xxl{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:rgba(0,0,0,0) !important}.offcanvas-xxl .offcanvas-header{display:none}.offcanvas-xxl .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible;background-color:rgba(0,0,0,0) !important}}.offcanvas{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}@media(prefers-reduced-motion: reduce){.offcanvas{transition:none}}.offcanvas.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas.showing,.offcanvas.show:not(.hiding){transform:none}.offcanvas.showing,.offcanvas.hiding,.offcanvas.show{visibility:visible}.offcanvas-backdrop{position:fixed;top:0;left:0;z-index:1040;width:100vw;height:100vh;background-color:#000}.offcanvas-backdrop.fade{opacity:0}.offcanvas-backdrop.show{opacity:.5}.offcanvas-header{display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;justify-content:space-between;-webkit-justify-content:space-between;padding:var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x)}.offcanvas-header .btn-close{padding:calc(var(--bs-offcanvas-padding-y)*.5) calc(var(--bs-offcanvas-padding-x)*.5);margin-top:calc(-0.5*var(--bs-offcanvas-padding-y));margin-right:calc(-0.5*var(--bs-offcanvas-padding-x));margin-bottom:calc(-0.5*var(--bs-offcanvas-padding-y))}.offcanvas-title{margin-bottom:0;line-height:var(--bs-offcanvas-title-line-height)}.offcanvas-body{flex-grow:1;-webkit-flex-grow:1;padding:var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x);overflow-y:auto}.placeholder{display:inline-block;min-height:1em;vertical-align:middle;cursor:wait;background-color:currentcolor;opacity:.5}.placeholder.btn::before{display:inline-block;content:""}.placeholder-xs{min-height:.6em}.placeholder-sm{min-height:.8em}.placeholder-lg{min-height:1.2em}.placeholder-glow .placeholder{animation:placeholder-glow 2s ease-in-out infinite}@keyframes placeholder-glow{50%{opacity:.2}}.placeholder-wave{mask-image:linear-gradient(130deg, #000 55%, rgba(0, 0, 0, 0.8) 75%, #000 95%);-webkit-mask-image:linear-gradient(130deg, #000 55%, rgba(0, 0, 0, 0.8) 75%, #000 95%);mask-size:200% 100%;-webkit-mask-size:200% 100%;animation:placeholder-wave 2s linear infinite}@keyframes placeholder-wave{100%{mask-position:-200% 0%;-webkit-mask-position:-200% 0%}}.clearfix::after{display:block;clear:both;content:""}.text-bg-default{color:#000 !important;background-color:RGBA(var(--bs-default-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-primary{color:#fff !important;background-color:RGBA(var(--bs-primary-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-secondary{color:#fff !important;background-color:RGBA(var(--bs-secondary-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-success{color:#fff !important;background-color:RGBA(var(--bs-success-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-info{color:#000 !important;background-color:RGBA(var(--bs-info-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-warning{color:#000 !important;background-color:RGBA(var(--bs-warning-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-danger{color:#fff !important;background-color:RGBA(var(--bs-danger-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-light{color:#000 !important;background-color:RGBA(var(--bs-light-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-dark{color:#fff !important;background-color:RGBA(var(--bs-dark-rgb), var(--bs-bg-opacity, 1)) !important}.link-default{color:RGBA(var(--bs-default-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-default-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-default:hover,.link-default:focus{color:RGBA(229, 232, 235, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(229, 232, 235, var(--bs-link-underline-opacity, 1)) !important}.link-primary{color:RGBA(var(--bs-primary-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-primary-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-primary:hover,.link-primary:focus{color:RGBA(10, 88, 202, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(10, 88, 202, var(--bs-link-underline-opacity, 1)) !important}.link-secondary{color:RGBA(var(--bs-secondary-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-secondary-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-secondary:hover,.link-secondary:focus{color:RGBA(86, 94, 100, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(86, 94, 100, var(--bs-link-underline-opacity, 1)) !important}.link-success{color:RGBA(var(--bs-success-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-success-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-success:hover,.link-success:focus{color:RGBA(20, 108, 67, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(20, 108, 67, var(--bs-link-underline-opacity, 1)) !important}.link-info{color:RGBA(var(--bs-info-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-info-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-info:hover,.link-info:focus{color:RGBA(61, 213, 243, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(61, 213, 243, var(--bs-link-underline-opacity, 1)) !important}.link-warning{color:RGBA(var(--bs-warning-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-warning-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-warning:hover,.link-warning:focus{color:RGBA(255, 205, 57, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(255, 205, 57, var(--bs-link-underline-opacity, 1)) !important}.link-danger{color:RGBA(var(--bs-danger-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-danger-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-danger:hover,.link-danger:focus{color:RGBA(176, 42, 55, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(176, 42, 55, var(--bs-link-underline-opacity, 1)) !important}.link-light{color:RGBA(var(--bs-light-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-light-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-light:hover,.link-light:focus{color:RGBA(249, 250, 251, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(249, 250, 251, var(--bs-link-underline-opacity, 1)) !important}.link-dark{color:RGBA(var(--bs-dark-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-dark-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-dark:hover,.link-dark:focus{color:RGBA(26, 30, 33, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(26, 30, 33, var(--bs-link-underline-opacity, 1)) !important}.link-body-emphasis{color:RGBA(var(--bs-emphasis-color-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-emphasis-color-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-body-emphasis:hover,.link-body-emphasis:focus{color:RGBA(var(--bs-emphasis-color-rgb), var(--bs-link-opacity, 0.75)) !important;text-decoration-color:RGBA(var(--bs-emphasis-color-rgb), var(--bs-link-underline-opacity, 0.75)) !important}.focus-ring:focus{outline:0;box-shadow:var(--bs-focus-ring-x, 0) var(--bs-focus-ring-y, 0) var(--bs-focus-ring-blur, 0) var(--bs-focus-ring-width) var(--bs-focus-ring-color)}.icon-link{display:inline-flex;gap:.375rem;align-items:center;-webkit-align-items:center;text-decoration-color:rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 0.5));text-underline-offset:.25em;backface-visibility:hidden;-webkit-backface-visibility:hidden;-moz-backface-visibility:hidden;-ms-backface-visibility:hidden;-o-backface-visibility:hidden}.icon-link>.bi{flex-shrink:0;-webkit-flex-shrink:0;width:1em;height:1em;fill:currentcolor;transition:.2s ease-in-out transform}@media(prefers-reduced-motion: reduce){.icon-link>.bi{transition:none}}.icon-link-hover:hover>.bi,.icon-link-hover:focus-visible>.bi{transform:var(--bs-icon-link-transform, translate3d(0.25em, 0, 0))}.ratio{position:relative;width:100%}.ratio::before{display:block;padding-top:var(--bs-aspect-ratio);content:""}.ratio>*{position:absolute;top:0;left:0;width:100%;height:100%}.ratio-1x1{--bs-aspect-ratio: 100%}.ratio-4x3{--bs-aspect-ratio: 75%}.ratio-16x9{--bs-aspect-ratio: 56.25%}.ratio-21x9{--bs-aspect-ratio: 42.8571428571%}.fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030}.fixed-bottom{position:fixed;right:0;bottom:0;left:0;z-index:1030}.sticky-top{position:sticky;top:0;z-index:1020}.sticky-bottom{position:sticky;bottom:0;z-index:1020}@media(min-width: 576px){.sticky-sm-top{position:sticky;top:0;z-index:1020}.sticky-sm-bottom{position:sticky;bottom:0;z-index:1020}}@media(min-width: 768px){.sticky-md-top{position:sticky;top:0;z-index:1020}.sticky-md-bottom{position:sticky;bottom:0;z-index:1020}}@media(min-width: 992px){.sticky-lg-top{position:sticky;top:0;z-index:1020}.sticky-lg-bottom{position:sticky;bottom:0;z-index:1020}}@media(min-width: 1200px){.sticky-xl-top{position:sticky;top:0;z-index:1020}.sticky-xl-bottom{position:sticky;bottom:0;z-index:1020}}@media(min-width: 1400px){.sticky-xxl-top{position:sticky;top:0;z-index:1020}.sticky-xxl-bottom{position:sticky;bottom:0;z-index:1020}}.hstack{display:flex;display:-webkit-flex;flex-direction:row;-webkit-flex-direction:row;align-items:center;-webkit-align-items:center;align-self:stretch;-webkit-align-self:stretch}.vstack{display:flex;display:-webkit-flex;flex:1 1 auto;-webkit-flex:1 1 auto;flex-direction:column;-webkit-flex-direction:column;align-self:stretch;-webkit-align-self:stretch}.visually-hidden,.visually-hidden-focusable:not(:focus):not(:focus-within){width:1px !important;height:1px !important;padding:0 !important;margin:-1px !important;overflow:hidden !important;clip:rect(0, 0, 0, 0) !important;white-space:nowrap !important;border:0 !important}.visually-hidden:not(caption),.visually-hidden-focusable:not(:focus):not(:focus-within):not(caption){position:absolute !important}.stretched-link::after{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;content:""}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vr{display:inline-block;align-self:stretch;-webkit-align-self:stretch;width:1px;min-height:1em;background-color:currentcolor;opacity:.25}.align-baseline{vertical-align:baseline !important}.align-top{vertical-align:top !important}.align-middle{vertical-align:middle !important}.align-bottom{vertical-align:bottom !important}.align-text-bottom{vertical-align:text-bottom !important}.align-text-top{vertical-align:text-top !important}.float-start{float:left !important}.float-end{float:right !important}.float-none{float:none !important}.object-fit-contain{object-fit:contain !important}.object-fit-cover{object-fit:cover !important}.object-fit-fill{object-fit:fill !important}.object-fit-scale{object-fit:scale-down !important}.object-fit-none{object-fit:none !important}.opacity-0{opacity:0 !important}.opacity-25{opacity:.25 !important}.opacity-50{opacity:.5 !important}.opacity-75{opacity:.75 !important}.opacity-100{opacity:1 !important}.overflow-auto{overflow:auto !important}.overflow-hidden{overflow:hidden !important}.overflow-visible{overflow:visible !important}.overflow-scroll{overflow:scroll !important}.overflow-x-auto{overflow-x:auto !important}.overflow-x-hidden{overflow-x:hidden !important}.overflow-x-visible{overflow-x:visible !important}.overflow-x-scroll{overflow-x:scroll !important}.overflow-y-auto{overflow-y:auto !important}.overflow-y-hidden{overflow-y:hidden !important}.overflow-y-visible{overflow-y:visible !important}.overflow-y-scroll{overflow-y:scroll !important}.d-inline{display:inline !important}.d-inline-block{display:inline-block !important}.d-block{display:block !important}.d-grid{display:grid !important}.d-inline-grid{display:inline-grid !important}.d-table{display:table !important}.d-table-row{display:table-row !important}.d-table-cell{display:table-cell !important}.d-flex{display:flex !important}.d-inline-flex{display:inline-flex !important}.d-none{display:none !important}.shadow{box-shadow:0 .5rem 1rem rgba(0,0,0,.15) !important}.shadow-sm{box-shadow:0 .125rem .25rem rgba(0,0,0,.075) !important}.shadow-lg{box-shadow:0 1rem 3rem rgba(0,0,0,.175) !important}.shadow-none{box-shadow:none !important}.focus-ring-default{--bs-focus-ring-color: rgba(var(--bs-default-rgb), var(--bs-focus-ring-opacity))}.focus-ring-primary{--bs-focus-ring-color: rgba(var(--bs-primary-rgb), var(--bs-focus-ring-opacity))}.focus-ring-secondary{--bs-focus-ring-color: rgba(var(--bs-secondary-rgb), var(--bs-focus-ring-opacity))}.focus-ring-success{--bs-focus-ring-color: rgba(var(--bs-success-rgb), var(--bs-focus-ring-opacity))}.focus-ring-info{--bs-focus-ring-color: rgba(var(--bs-info-rgb), var(--bs-focus-ring-opacity))}.focus-ring-warning{--bs-focus-ring-color: rgba(var(--bs-warning-rgb), var(--bs-focus-ring-opacity))}.focus-ring-danger{--bs-focus-ring-color: rgba(var(--bs-danger-rgb), var(--bs-focus-ring-opacity))}.focus-ring-light{--bs-focus-ring-color: rgba(var(--bs-light-rgb), var(--bs-focus-ring-opacity))}.focus-ring-dark{--bs-focus-ring-color: rgba(var(--bs-dark-rgb), var(--bs-focus-ring-opacity))}.position-static{position:static !important}.position-relative{position:relative !important}.position-absolute{position:absolute !important}.position-fixed{position:fixed !important}.position-sticky{position:sticky !important}.top-0{top:0 !important}.top-50{top:50% !important}.top-100{top:100% !important}.bottom-0{bottom:0 !important}.bottom-50{bottom:50% !important}.bottom-100{bottom:100% !important}.start-0{left:0 !important}.start-50{left:50% !important}.start-100{left:100% !important}.end-0{right:0 !important}.end-50{right:50% !important}.end-100{right:100% !important}.translate-middle{transform:translate(-50%, -50%) !important}.translate-middle-x{transform:translateX(-50%) !important}.translate-middle-y{transform:translateY(-50%) !important}.border{border:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important}.border-0{border:0 !important}.border-top{border-top:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important}.border-top-0{border-top:0 !important}.border-end{border-right:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important}.border-end-0{border-right:0 !important}.border-bottom{border-bottom:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important}.border-bottom-0{border-bottom:0 !important}.border-start{border-left:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important}.border-start-0{border-left:0 !important}.border-default{--bs-border-opacity: 1;border-color:rgba(var(--bs-default-rgb), var(--bs-border-opacity)) !important}.border-primary{--bs-border-opacity: 1;border-color:rgba(var(--bs-primary-rgb), var(--bs-border-opacity)) !important}.border-secondary{--bs-border-opacity: 1;border-color:rgba(var(--bs-secondary-rgb), var(--bs-border-opacity)) !important}.border-success{--bs-border-opacity: 1;border-color:rgba(var(--bs-success-rgb), var(--bs-border-opacity)) !important}.border-info{--bs-border-opacity: 1;border-color:rgba(var(--bs-info-rgb), var(--bs-border-opacity)) !important}.border-warning{--bs-border-opacity: 1;border-color:rgba(var(--bs-warning-rgb), var(--bs-border-opacity)) !important}.border-danger{--bs-border-opacity: 1;border-color:rgba(var(--bs-danger-rgb), var(--bs-border-opacity)) !important}.border-light{--bs-border-opacity: 1;border-color:rgba(var(--bs-light-rgb), var(--bs-border-opacity)) !important}.border-dark{--bs-border-opacity: 1;border-color:rgba(var(--bs-dark-rgb), var(--bs-border-opacity)) !important}.border-black{--bs-border-opacity: 1;border-color:rgba(var(--bs-black-rgb), var(--bs-border-opacity)) !important}.border-white{--bs-border-opacity: 1;border-color:rgba(var(--bs-white-rgb), var(--bs-border-opacity)) !important}.border-primary-subtle{border-color:var(--bs-primary-border-subtle) !important}.border-secondary-subtle{border-color:var(--bs-secondary-border-subtle) !important}.border-success-subtle{border-color:var(--bs-success-border-subtle) !important}.border-info-subtle{border-color:var(--bs-info-border-subtle) !important}.border-warning-subtle{border-color:var(--bs-warning-border-subtle) !important}.border-danger-subtle{border-color:var(--bs-danger-border-subtle) !important}.border-light-subtle{border-color:var(--bs-light-border-subtle) !important}.border-dark-subtle{border-color:var(--bs-dark-border-subtle) !important}.border-1{border-width:1px !important}.border-2{border-width:2px !important}.border-3{border-width:3px !important}.border-4{border-width:4px !important}.border-5{border-width:5px !important}.border-opacity-10{--bs-border-opacity: 0.1}.border-opacity-25{--bs-border-opacity: 0.25}.border-opacity-50{--bs-border-opacity: 0.5}.border-opacity-75{--bs-border-opacity: 0.75}.border-opacity-100{--bs-border-opacity: 1}.w-25{width:25% !important}.w-50{width:50% !important}.w-75{width:75% !important}.w-100{width:100% !important}.w-auto{width:auto !important}.mw-100{max-width:100% !important}.vw-100{width:100vw !important}.min-vw-100{min-width:100vw !important}.h-25{height:25% !important}.h-50{height:50% !important}.h-75{height:75% !important}.h-100{height:100% !important}.h-auto{height:auto !important}.mh-100{max-height:100% !important}.vh-100{height:100vh !important}.min-vh-100{min-height:100vh !important}.flex-fill{flex:1 1 auto !important}.flex-row{flex-direction:row !important}.flex-column{flex-direction:column !important}.flex-row-reverse{flex-direction:row-reverse !important}.flex-column-reverse{flex-direction:column-reverse !important}.flex-grow-0{flex-grow:0 !important}.flex-grow-1{flex-grow:1 !important}.flex-shrink-0{flex-shrink:0 !important}.flex-shrink-1{flex-shrink:1 !important}.flex-wrap{flex-wrap:wrap !important}.flex-nowrap{flex-wrap:nowrap !important}.flex-wrap-reverse{flex-wrap:wrap-reverse !important}.justify-content-start{justify-content:flex-start !important}.justify-content-end{justify-content:flex-end !important}.justify-content-center{justify-content:center !important}.justify-content-between{justify-content:space-between !important}.justify-content-around{justify-content:space-around !important}.justify-content-evenly{justify-content:space-evenly !important}.align-items-start{align-items:flex-start !important}.align-items-end{align-items:flex-end !important}.align-items-center{align-items:center !important}.align-items-baseline{align-items:baseline !important}.align-items-stretch{align-items:stretch !important}.align-content-start{align-content:flex-start !important}.align-content-end{align-content:flex-end !important}.align-content-center{align-content:center !important}.align-content-between{align-content:space-between !important}.align-content-around{align-content:space-around !important}.align-content-stretch{align-content:stretch !important}.align-self-auto{align-self:auto !important}.align-self-start{align-self:flex-start !important}.align-self-end{align-self:flex-end !important}.align-self-center{align-self:center !important}.align-self-baseline{align-self:baseline !important}.align-self-stretch{align-self:stretch !important}.order-first{order:-1 !important}.order-0{order:0 !important}.order-1{order:1 !important}.order-2{order:2 !important}.order-3{order:3 !important}.order-4{order:4 !important}.order-5{order:5 !important}.order-last{order:6 !important}.m-0{margin:0 !important}.m-1{margin:.25rem !important}.m-2{margin:.5rem !important}.m-3{margin:1rem !important}.m-4{margin:1.5rem !important}.m-5{margin:3rem !important}.m-auto{margin:auto !important}.mx-0{margin-right:0 !important;margin-left:0 !important}.mx-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-3{margin-right:1rem !important;margin-left:1rem !important}.mx-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-5{margin-right:3rem !important;margin-left:3rem !important}.mx-auto{margin-right:auto !important;margin-left:auto !important}.my-0{margin-top:0 !important;margin-bottom:0 !important}.my-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-0{margin-top:0 !important}.mt-1{margin-top:.25rem !important}.mt-2{margin-top:.5rem !important}.mt-3{margin-top:1rem !important}.mt-4{margin-top:1.5rem !important}.mt-5{margin-top:3rem !important}.mt-auto{margin-top:auto !important}.me-0{margin-right:0 !important}.me-1{margin-right:.25rem !important}.me-2{margin-right:.5rem !important}.me-3{margin-right:1rem !important}.me-4{margin-right:1.5rem !important}.me-5{margin-right:3rem !important}.me-auto{margin-right:auto !important}.mb-0{margin-bottom:0 !important}.mb-1{margin-bottom:.25rem !important}.mb-2{margin-bottom:.5rem !important}.mb-3{margin-bottom:1rem !important}.mb-4{margin-bottom:1.5rem !important}.mb-5{margin-bottom:3rem !important}.mb-auto{margin-bottom:auto !important}.ms-0{margin-left:0 !important}.ms-1{margin-left:.25rem !important}.ms-2{margin-left:.5rem !important}.ms-3{margin-left:1rem !important}.ms-4{margin-left:1.5rem !important}.ms-5{margin-left:3rem !important}.ms-auto{margin-left:auto !important}.p-0{padding:0 !important}.p-1{padding:.25rem !important}.p-2{padding:.5rem !important}.p-3{padding:1rem !important}.p-4{padding:1.5rem !important}.p-5{padding:3rem !important}.px-0{padding-right:0 !important;padding-left:0 !important}.px-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-3{padding-right:1rem !important;padding-left:1rem !important}.px-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-5{padding-right:3rem !important;padding-left:3rem !important}.py-0{padding-top:0 !important;padding-bottom:0 !important}.py-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-0{padding-top:0 !important}.pt-1{padding-top:.25rem !important}.pt-2{padding-top:.5rem !important}.pt-3{padding-top:1rem !important}.pt-4{padding-top:1.5rem !important}.pt-5{padding-top:3rem !important}.pe-0{padding-right:0 !important}.pe-1{padding-right:.25rem !important}.pe-2{padding-right:.5rem !important}.pe-3{padding-right:1rem !important}.pe-4{padding-right:1.5rem !important}.pe-5{padding-right:3rem !important}.pb-0{padding-bottom:0 !important}.pb-1{padding-bottom:.25rem !important}.pb-2{padding-bottom:.5rem !important}.pb-3{padding-bottom:1rem !important}.pb-4{padding-bottom:1.5rem !important}.pb-5{padding-bottom:3rem !important}.ps-0{padding-left:0 !important}.ps-1{padding-left:.25rem !important}.ps-2{padding-left:.5rem !important}.ps-3{padding-left:1rem !important}.ps-4{padding-left:1.5rem !important}.ps-5{padding-left:3rem !important}.gap-0{gap:0 !important}.gap-1{gap:.25rem !important}.gap-2{gap:.5rem !important}.gap-3{gap:1rem !important}.gap-4{gap:1.5rem !important}.gap-5{gap:3rem !important}.row-gap-0{row-gap:0 !important}.row-gap-1{row-gap:.25rem !important}.row-gap-2{row-gap:.5rem !important}.row-gap-3{row-gap:1rem !important}.row-gap-4{row-gap:1.5rem !important}.row-gap-5{row-gap:3rem !important}.column-gap-0{column-gap:0 !important}.column-gap-1{column-gap:.25rem !important}.column-gap-2{column-gap:.5rem !important}.column-gap-3{column-gap:1rem !important}.column-gap-4{column-gap:1.5rem !important}.column-gap-5{column-gap:3rem !important}.font-monospace{font-family:var(--bs-font-monospace) !important}.fs-1{font-size:calc(1.325rem + 0.9vw) !important}.fs-2{font-size:calc(1.29rem + 0.48vw) !important}.fs-3{font-size:calc(1.27rem + 0.24vw) !important}.fs-4{font-size:1.25rem !important}.fs-5{font-size:1.1rem !important}.fs-6{font-size:1rem !important}.fst-italic{font-style:italic !important}.fst-normal{font-style:normal !important}.fw-lighter{font-weight:lighter !important}.fw-light{font-weight:300 !important}.fw-normal{font-weight:400 !important}.fw-medium{font-weight:500 !important}.fw-semibold{font-weight:600 !important}.fw-bold{font-weight:700 !important}.fw-bolder{font-weight:bolder !important}.lh-1{line-height:1 !important}.lh-sm{line-height:1.25 !important}.lh-base{line-height:1.5 !important}.lh-lg{line-height:2 !important}.text-start{text-align:left !important}.text-end{text-align:right !important}.text-center{text-align:center !important}.text-decoration-none{text-decoration:none !important}.text-decoration-underline{text-decoration:underline !important}.text-decoration-line-through{text-decoration:line-through !important}.text-lowercase{text-transform:lowercase !important}.text-uppercase{text-transform:uppercase !important}.text-capitalize{text-transform:capitalize !important}.text-wrap{white-space:normal !important}.text-nowrap{white-space:nowrap !important}.text-break{word-wrap:break-word !important;word-break:break-word !important}.text-default{--bs-text-opacity: 1;color:rgba(var(--bs-default-rgb), var(--bs-text-opacity)) !important}.text-primary{--bs-text-opacity: 1;color:rgba(var(--bs-primary-rgb), var(--bs-text-opacity)) !important}.text-secondary{--bs-text-opacity: 1;color:rgba(var(--bs-secondary-rgb), var(--bs-text-opacity)) !important}.text-success{--bs-text-opacity: 1;color:rgba(var(--bs-success-rgb), var(--bs-text-opacity)) !important}.text-info{--bs-text-opacity: 1;color:rgba(var(--bs-info-rgb), var(--bs-text-opacity)) !important}.text-warning{--bs-text-opacity: 1;color:rgba(var(--bs-warning-rgb), var(--bs-text-opacity)) !important}.text-danger{--bs-text-opacity: 1;color:rgba(var(--bs-danger-rgb), var(--bs-text-opacity)) !important}.text-light{--bs-text-opacity: 1;color:rgba(var(--bs-light-rgb), var(--bs-text-opacity)) !important}.text-dark{--bs-text-opacity: 1;color:rgba(var(--bs-dark-rgb), var(--bs-text-opacity)) !important}.text-black{--bs-text-opacity: 1;color:rgba(var(--bs-black-rgb), var(--bs-text-opacity)) !important}.text-white{--bs-text-opacity: 1;color:rgba(var(--bs-white-rgb), var(--bs-text-opacity)) !important}.text-body{--bs-text-opacity: 1;color:rgba(var(--bs-body-color-rgb), var(--bs-text-opacity)) !important}.text-muted{--bs-text-opacity: 1;color:var(--bs-secondary-color) !important}.text-black-50{--bs-text-opacity: 1;color:rgba(0,0,0,.5) !important}.text-white-50{--bs-text-opacity: 1;color:rgba(255,255,255,.5) !important}.text-body-secondary{--bs-text-opacity: 1;color:var(--bs-secondary-color) !important}.text-body-tertiary{--bs-text-opacity: 1;color:var(--bs-tertiary-color) !important}.text-body-emphasis{--bs-text-opacity: 1;color:var(--bs-emphasis-color) !important}.text-reset{--bs-text-opacity: 1;color:inherit !important}.text-opacity-25{--bs-text-opacity: 0.25}.text-opacity-50{--bs-text-opacity: 0.5}.text-opacity-75{--bs-text-opacity: 0.75}.text-opacity-100{--bs-text-opacity: 1}.text-primary-emphasis{color:var(--bs-primary-text-emphasis) !important}.text-secondary-emphasis{color:var(--bs-secondary-text-emphasis) !important}.text-success-emphasis{color:var(--bs-success-text-emphasis) !important}.text-info-emphasis{color:var(--bs-info-text-emphasis) !important}.text-warning-emphasis{color:var(--bs-warning-text-emphasis) !important}.text-danger-emphasis{color:var(--bs-danger-text-emphasis) !important}.text-light-emphasis{color:var(--bs-light-text-emphasis) !important}.text-dark-emphasis{color:var(--bs-dark-text-emphasis) !important}.link-opacity-10{--bs-link-opacity: 0.1}.link-opacity-10-hover:hover{--bs-link-opacity: 0.1}.link-opacity-25{--bs-link-opacity: 0.25}.link-opacity-25-hover:hover{--bs-link-opacity: 0.25}.link-opacity-50{--bs-link-opacity: 0.5}.link-opacity-50-hover:hover{--bs-link-opacity: 0.5}.link-opacity-75{--bs-link-opacity: 0.75}.link-opacity-75-hover:hover{--bs-link-opacity: 0.75}.link-opacity-100{--bs-link-opacity: 1}.link-opacity-100-hover:hover{--bs-link-opacity: 1}.link-offset-1{text-underline-offset:.125em !important}.link-offset-1-hover:hover{text-underline-offset:.125em !important}.link-offset-2{text-underline-offset:.25em !important}.link-offset-2-hover:hover{text-underline-offset:.25em !important}.link-offset-3{text-underline-offset:.375em !important}.link-offset-3-hover:hover{text-underline-offset:.375em !important}.link-underline-default{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-default-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-primary{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-primary-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-secondary{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-secondary-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-success{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-success-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-info{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-info-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-warning{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-warning-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-danger{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-danger-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-light{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-light-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-dark{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-dark-rgb), var(--bs-link-underline-opacity)) !important}.link-underline{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-link-color-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-underline-opacity-0{--bs-link-underline-opacity: 0}.link-underline-opacity-0-hover:hover{--bs-link-underline-opacity: 0}.link-underline-opacity-10{--bs-link-underline-opacity: 0.1}.link-underline-opacity-10-hover:hover{--bs-link-underline-opacity: 0.1}.link-underline-opacity-25{--bs-link-underline-opacity: 0.25}.link-underline-opacity-25-hover:hover{--bs-link-underline-opacity: 0.25}.link-underline-opacity-50{--bs-link-underline-opacity: 0.5}.link-underline-opacity-50-hover:hover{--bs-link-underline-opacity: 0.5}.link-underline-opacity-75{--bs-link-underline-opacity: 0.75}.link-underline-opacity-75-hover:hover{--bs-link-underline-opacity: 0.75}.link-underline-opacity-100{--bs-link-underline-opacity: 1}.link-underline-opacity-100-hover:hover{--bs-link-underline-opacity: 1}.bg-default{--bs-bg-opacity: 1;background-color:rgba(var(--bs-default-rgb), var(--bs-bg-opacity)) !important}.bg-primary{--bs-bg-opacity: 1;background-color:rgba(var(--bs-primary-rgb), var(--bs-bg-opacity)) !important}.bg-secondary{--bs-bg-opacity: 1;background-color:rgba(var(--bs-secondary-rgb), var(--bs-bg-opacity)) !important}.bg-success{--bs-bg-opacity: 1;background-color:rgba(var(--bs-success-rgb), var(--bs-bg-opacity)) !important}.bg-info{--bs-bg-opacity: 1;background-color:rgba(var(--bs-info-rgb), var(--bs-bg-opacity)) !important}.bg-warning{--bs-bg-opacity: 1;background-color:rgba(var(--bs-warning-rgb), var(--bs-bg-opacity)) !important}.bg-danger{--bs-bg-opacity: 1;background-color:rgba(var(--bs-danger-rgb), var(--bs-bg-opacity)) !important}.bg-light{--bs-bg-opacity: 1;background-color:rgba(var(--bs-light-rgb), var(--bs-bg-opacity)) !important}.bg-dark{--bs-bg-opacity: 1;background-color:rgba(var(--bs-dark-rgb), var(--bs-bg-opacity)) !important}.bg-black{--bs-bg-opacity: 1;background-color:rgba(var(--bs-black-rgb), var(--bs-bg-opacity)) !important}.bg-white{--bs-bg-opacity: 1;background-color:rgba(var(--bs-white-rgb), var(--bs-bg-opacity)) !important}.bg-body{--bs-bg-opacity: 1;background-color:rgba(var(--bs-body-bg-rgb), var(--bs-bg-opacity)) !important}.bg-transparent{--bs-bg-opacity: 1;background-color:rgba(0,0,0,0) !important}.bg-body-secondary{--bs-bg-opacity: 1;background-color:rgba(var(--bs-secondary-bg-rgb), var(--bs-bg-opacity)) !important}.bg-body-tertiary{--bs-bg-opacity: 1;background-color:rgba(var(--bs-tertiary-bg-rgb), var(--bs-bg-opacity)) !important}.bg-opacity-10{--bs-bg-opacity: 0.1}.bg-opacity-25{--bs-bg-opacity: 0.25}.bg-opacity-50{--bs-bg-opacity: 0.5}.bg-opacity-75{--bs-bg-opacity: 0.75}.bg-opacity-100{--bs-bg-opacity: 1}.bg-primary-subtle{background-color:var(--bs-primary-bg-subtle) !important}.bg-secondary-subtle{background-color:var(--bs-secondary-bg-subtle) !important}.bg-success-subtle{background-color:var(--bs-success-bg-subtle) !important}.bg-info-subtle{background-color:var(--bs-info-bg-subtle) !important}.bg-warning-subtle{background-color:var(--bs-warning-bg-subtle) !important}.bg-danger-subtle{background-color:var(--bs-danger-bg-subtle) !important}.bg-light-subtle{background-color:var(--bs-light-bg-subtle) !important}.bg-dark-subtle{background-color:var(--bs-dark-bg-subtle) !important}.bg-gradient{background-image:var(--bs-gradient) !important}.user-select-all{user-select:all !important}.user-select-auto{user-select:auto !important}.user-select-none{user-select:none !important}.pe-none{pointer-events:none !important}.pe-auto{pointer-events:auto !important}.rounded{border-radius:var(--bs-border-radius) !important}.rounded-0{border-radius:0 !important}.rounded-1{border-radius:var(--bs-border-radius-sm) !important}.rounded-2{border-radius:var(--bs-border-radius) !important}.rounded-3{border-radius:var(--bs-border-radius-lg) !important}.rounded-4{border-radius:var(--bs-border-radius-xl) !important}.rounded-5{border-radius:var(--bs-border-radius-xxl) !important}.rounded-circle{border-radius:50% !important}.rounded-pill{border-radius:var(--bs-border-radius-pill) !important}.rounded-top{border-top-left-radius:var(--bs-border-radius) !important;border-top-right-radius:var(--bs-border-radius) !important}.rounded-top-0{border-top-left-radius:0 !important;border-top-right-radius:0 !important}.rounded-top-1{border-top-left-radius:var(--bs-border-radius-sm) !important;border-top-right-radius:var(--bs-border-radius-sm) !important}.rounded-top-2{border-top-left-radius:var(--bs-border-radius) !important;border-top-right-radius:var(--bs-border-radius) !important}.rounded-top-3{border-top-left-radius:var(--bs-border-radius-lg) !important;border-top-right-radius:var(--bs-border-radius-lg) !important}.rounded-top-4{border-top-left-radius:var(--bs-border-radius-xl) !important;border-top-right-radius:var(--bs-border-radius-xl) !important}.rounded-top-5{border-top-left-radius:var(--bs-border-radius-xxl) !important;border-top-right-radius:var(--bs-border-radius-xxl) !important}.rounded-top-circle{border-top-left-radius:50% !important;border-top-right-radius:50% !important}.rounded-top-pill{border-top-left-radius:var(--bs-border-radius-pill) !important;border-top-right-radius:var(--bs-border-radius-pill) !important}.rounded-end{border-top-right-radius:var(--bs-border-radius) !important;border-bottom-right-radius:var(--bs-border-radius) !important}.rounded-end-0{border-top-right-radius:0 !important;border-bottom-right-radius:0 !important}.rounded-end-1{border-top-right-radius:var(--bs-border-radius-sm) !important;border-bottom-right-radius:var(--bs-border-radius-sm) !important}.rounded-end-2{border-top-right-radius:var(--bs-border-radius) !important;border-bottom-right-radius:var(--bs-border-radius) !important}.rounded-end-3{border-top-right-radius:var(--bs-border-radius-lg) !important;border-bottom-right-radius:var(--bs-border-radius-lg) !important}.rounded-end-4{border-top-right-radius:var(--bs-border-radius-xl) !important;border-bottom-right-radius:var(--bs-border-radius-xl) !important}.rounded-end-5{border-top-right-radius:var(--bs-border-radius-xxl) !important;border-bottom-right-radius:var(--bs-border-radius-xxl) !important}.rounded-end-circle{border-top-right-radius:50% !important;border-bottom-right-radius:50% !important}.rounded-end-pill{border-top-right-radius:var(--bs-border-radius-pill) !important;border-bottom-right-radius:var(--bs-border-radius-pill) !important}.rounded-bottom{border-bottom-right-radius:var(--bs-border-radius) !important;border-bottom-left-radius:var(--bs-border-radius) !important}.rounded-bottom-0{border-bottom-right-radius:0 !important;border-bottom-left-radius:0 !important}.rounded-bottom-1{border-bottom-right-radius:var(--bs-border-radius-sm) !important;border-bottom-left-radius:var(--bs-border-radius-sm) !important}.rounded-bottom-2{border-bottom-right-radius:var(--bs-border-radius) !important;border-bottom-left-radius:var(--bs-border-radius) !important}.rounded-bottom-3{border-bottom-right-radius:var(--bs-border-radius-lg) !important;border-bottom-left-radius:var(--bs-border-radius-lg) !important}.rounded-bottom-4{border-bottom-right-radius:var(--bs-border-radius-xl) !important;border-bottom-left-radius:var(--bs-border-radius-xl) !important}.rounded-bottom-5{border-bottom-right-radius:var(--bs-border-radius-xxl) !important;border-bottom-left-radius:var(--bs-border-radius-xxl) !important}.rounded-bottom-circle{border-bottom-right-radius:50% !important;border-bottom-left-radius:50% !important}.rounded-bottom-pill{border-bottom-right-radius:var(--bs-border-radius-pill) !important;border-bottom-left-radius:var(--bs-border-radius-pill) !important}.rounded-start{border-bottom-left-radius:var(--bs-border-radius) !important;border-top-left-radius:var(--bs-border-radius) !important}.rounded-start-0{border-bottom-left-radius:0 !important;border-top-left-radius:0 !important}.rounded-start-1{border-bottom-left-radius:var(--bs-border-radius-sm) !important;border-top-left-radius:var(--bs-border-radius-sm) !important}.rounded-start-2{border-bottom-left-radius:var(--bs-border-radius) !important;border-top-left-radius:var(--bs-border-radius) !important}.rounded-start-3{border-bottom-left-radius:var(--bs-border-radius-lg) !important;border-top-left-radius:var(--bs-border-radius-lg) !important}.rounded-start-4{border-bottom-left-radius:var(--bs-border-radius-xl) !important;border-top-left-radius:var(--bs-border-radius-xl) !important}.rounded-start-5{border-bottom-left-radius:var(--bs-border-radius-xxl) !important;border-top-left-radius:var(--bs-border-radius-xxl) !important}.rounded-start-circle{border-bottom-left-radius:50% !important;border-top-left-radius:50% !important}.rounded-start-pill{border-bottom-left-radius:var(--bs-border-radius-pill) !important;border-top-left-radius:var(--bs-border-radius-pill) !important}.visible{visibility:visible !important}.invisible{visibility:hidden !important}.z-n1{z-index:-1 !important}.z-0{z-index:0 !important}.z-1{z-index:1 !important}.z-2{z-index:2 !important}.z-3{z-index:3 !important}@media(min-width: 576px){.float-sm-start{float:left !important}.float-sm-end{float:right !important}.float-sm-none{float:none !important}.object-fit-sm-contain{object-fit:contain !important}.object-fit-sm-cover{object-fit:cover !important}.object-fit-sm-fill{object-fit:fill !important}.object-fit-sm-scale{object-fit:scale-down !important}.object-fit-sm-none{object-fit:none !important}.d-sm-inline{display:inline !important}.d-sm-inline-block{display:inline-block !important}.d-sm-block{display:block !important}.d-sm-grid{display:grid !important}.d-sm-inline-grid{display:inline-grid !important}.d-sm-table{display:table !important}.d-sm-table-row{display:table-row !important}.d-sm-table-cell{display:table-cell !important}.d-sm-flex{display:flex !important}.d-sm-inline-flex{display:inline-flex !important}.d-sm-none{display:none !important}.flex-sm-fill{flex:1 1 auto !important}.flex-sm-row{flex-direction:row !important}.flex-sm-column{flex-direction:column !important}.flex-sm-row-reverse{flex-direction:row-reverse !important}.flex-sm-column-reverse{flex-direction:column-reverse !important}.flex-sm-grow-0{flex-grow:0 !important}.flex-sm-grow-1{flex-grow:1 !important}.flex-sm-shrink-0{flex-shrink:0 !important}.flex-sm-shrink-1{flex-shrink:1 !important}.flex-sm-wrap{flex-wrap:wrap !important}.flex-sm-nowrap{flex-wrap:nowrap !important}.flex-sm-wrap-reverse{flex-wrap:wrap-reverse !important}.justify-content-sm-start{justify-content:flex-start !important}.justify-content-sm-end{justify-content:flex-end !important}.justify-content-sm-center{justify-content:center !important}.justify-content-sm-between{justify-content:space-between !important}.justify-content-sm-around{justify-content:space-around !important}.justify-content-sm-evenly{justify-content:space-evenly !important}.align-items-sm-start{align-items:flex-start !important}.align-items-sm-end{align-items:flex-end !important}.align-items-sm-center{align-items:center !important}.align-items-sm-baseline{align-items:baseline !important}.align-items-sm-stretch{align-items:stretch !important}.align-content-sm-start{align-content:flex-start !important}.align-content-sm-end{align-content:flex-end !important}.align-content-sm-center{align-content:center !important}.align-content-sm-between{align-content:space-between !important}.align-content-sm-around{align-content:space-around !important}.align-content-sm-stretch{align-content:stretch !important}.align-self-sm-auto{align-self:auto !important}.align-self-sm-start{align-self:flex-start !important}.align-self-sm-end{align-self:flex-end !important}.align-self-sm-center{align-self:center !important}.align-self-sm-baseline{align-self:baseline !important}.align-self-sm-stretch{align-self:stretch !important}.order-sm-first{order:-1 !important}.order-sm-0{order:0 !important}.order-sm-1{order:1 !important}.order-sm-2{order:2 !important}.order-sm-3{order:3 !important}.order-sm-4{order:4 !important}.order-sm-5{order:5 !important}.order-sm-last{order:6 !important}.m-sm-0{margin:0 !important}.m-sm-1{margin:.25rem !important}.m-sm-2{margin:.5rem !important}.m-sm-3{margin:1rem !important}.m-sm-4{margin:1.5rem !important}.m-sm-5{margin:3rem !important}.m-sm-auto{margin:auto !important}.mx-sm-0{margin-right:0 !important;margin-left:0 !important}.mx-sm-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-sm-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-sm-3{margin-right:1rem !important;margin-left:1rem !important}.mx-sm-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-sm-5{margin-right:3rem !important;margin-left:3rem !important}.mx-sm-auto{margin-right:auto !important;margin-left:auto !important}.my-sm-0{margin-top:0 !important;margin-bottom:0 !important}.my-sm-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-sm-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-sm-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-sm-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-sm-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-sm-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-sm-0{margin-top:0 !important}.mt-sm-1{margin-top:.25rem !important}.mt-sm-2{margin-top:.5rem !important}.mt-sm-3{margin-top:1rem !important}.mt-sm-4{margin-top:1.5rem !important}.mt-sm-5{margin-top:3rem !important}.mt-sm-auto{margin-top:auto !important}.me-sm-0{margin-right:0 !important}.me-sm-1{margin-right:.25rem !important}.me-sm-2{margin-right:.5rem !important}.me-sm-3{margin-right:1rem !important}.me-sm-4{margin-right:1.5rem !important}.me-sm-5{margin-right:3rem !important}.me-sm-auto{margin-right:auto !important}.mb-sm-0{margin-bottom:0 !important}.mb-sm-1{margin-bottom:.25rem !important}.mb-sm-2{margin-bottom:.5rem !important}.mb-sm-3{margin-bottom:1rem !important}.mb-sm-4{margin-bottom:1.5rem !important}.mb-sm-5{margin-bottom:3rem !important}.mb-sm-auto{margin-bottom:auto !important}.ms-sm-0{margin-left:0 !important}.ms-sm-1{margin-left:.25rem !important}.ms-sm-2{margin-left:.5rem !important}.ms-sm-3{margin-left:1rem !important}.ms-sm-4{margin-left:1.5rem !important}.ms-sm-5{margin-left:3rem !important}.ms-sm-auto{margin-left:auto !important}.p-sm-0{padding:0 !important}.p-sm-1{padding:.25rem !important}.p-sm-2{padding:.5rem !important}.p-sm-3{padding:1rem !important}.p-sm-4{padding:1.5rem !important}.p-sm-5{padding:3rem !important}.px-sm-0{padding-right:0 !important;padding-left:0 !important}.px-sm-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-sm-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-sm-3{padding-right:1rem !important;padding-left:1rem !important}.px-sm-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-sm-5{padding-right:3rem !important;padding-left:3rem !important}.py-sm-0{padding-top:0 !important;padding-bottom:0 !important}.py-sm-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-sm-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-sm-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-sm-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-sm-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-sm-0{padding-top:0 !important}.pt-sm-1{padding-top:.25rem !important}.pt-sm-2{padding-top:.5rem !important}.pt-sm-3{padding-top:1rem !important}.pt-sm-4{padding-top:1.5rem !important}.pt-sm-5{padding-top:3rem !important}.pe-sm-0{padding-right:0 !important}.pe-sm-1{padding-right:.25rem !important}.pe-sm-2{padding-right:.5rem !important}.pe-sm-3{padding-right:1rem !important}.pe-sm-4{padding-right:1.5rem !important}.pe-sm-5{padding-right:3rem !important}.pb-sm-0{padding-bottom:0 !important}.pb-sm-1{padding-bottom:.25rem !important}.pb-sm-2{padding-bottom:.5rem !important}.pb-sm-3{padding-bottom:1rem !important}.pb-sm-4{padding-bottom:1.5rem !important}.pb-sm-5{padding-bottom:3rem !important}.ps-sm-0{padding-left:0 !important}.ps-sm-1{padding-left:.25rem !important}.ps-sm-2{padding-left:.5rem !important}.ps-sm-3{padding-left:1rem !important}.ps-sm-4{padding-left:1.5rem !important}.ps-sm-5{padding-left:3rem !important}.gap-sm-0{gap:0 !important}.gap-sm-1{gap:.25rem !important}.gap-sm-2{gap:.5rem !important}.gap-sm-3{gap:1rem !important}.gap-sm-4{gap:1.5rem !important}.gap-sm-5{gap:3rem !important}.row-gap-sm-0{row-gap:0 !important}.row-gap-sm-1{row-gap:.25rem !important}.row-gap-sm-2{row-gap:.5rem !important}.row-gap-sm-3{row-gap:1rem !important}.row-gap-sm-4{row-gap:1.5rem !important}.row-gap-sm-5{row-gap:3rem !important}.column-gap-sm-0{column-gap:0 !important}.column-gap-sm-1{column-gap:.25rem !important}.column-gap-sm-2{column-gap:.5rem !important}.column-gap-sm-3{column-gap:1rem !important}.column-gap-sm-4{column-gap:1.5rem !important}.column-gap-sm-5{column-gap:3rem !important}.text-sm-start{text-align:left !important}.text-sm-end{text-align:right !important}.text-sm-center{text-align:center !important}}@media(min-width: 768px){.float-md-start{float:left !important}.float-md-end{float:right !important}.float-md-none{float:none !important}.object-fit-md-contain{object-fit:contain !important}.object-fit-md-cover{object-fit:cover !important}.object-fit-md-fill{object-fit:fill !important}.object-fit-md-scale{object-fit:scale-down !important}.object-fit-md-none{object-fit:none !important}.d-md-inline{display:inline !important}.d-md-inline-block{display:inline-block !important}.d-md-block{display:block !important}.d-md-grid{display:grid !important}.d-md-inline-grid{display:inline-grid !important}.d-md-table{display:table !important}.d-md-table-row{display:table-row !important}.d-md-table-cell{display:table-cell !important}.d-md-flex{display:flex !important}.d-md-inline-flex{display:inline-flex !important}.d-md-none{display:none !important}.flex-md-fill{flex:1 1 auto !important}.flex-md-row{flex-direction:row !important}.flex-md-column{flex-direction:column !important}.flex-md-row-reverse{flex-direction:row-reverse !important}.flex-md-column-reverse{flex-direction:column-reverse !important}.flex-md-grow-0{flex-grow:0 !important}.flex-md-grow-1{flex-grow:1 !important}.flex-md-shrink-0{flex-shrink:0 !important}.flex-md-shrink-1{flex-shrink:1 !important}.flex-md-wrap{flex-wrap:wrap !important}.flex-md-nowrap{flex-wrap:nowrap !important}.flex-md-wrap-reverse{flex-wrap:wrap-reverse !important}.justify-content-md-start{justify-content:flex-start !important}.justify-content-md-end{justify-content:flex-end !important}.justify-content-md-center{justify-content:center !important}.justify-content-md-between{justify-content:space-between !important}.justify-content-md-around{justify-content:space-around !important}.justify-content-md-evenly{justify-content:space-evenly !important}.align-items-md-start{align-items:flex-start !important}.align-items-md-end{align-items:flex-end !important}.align-items-md-center{align-items:center !important}.align-items-md-baseline{align-items:baseline !important}.align-items-md-stretch{align-items:stretch !important}.align-content-md-start{align-content:flex-start !important}.align-content-md-end{align-content:flex-end !important}.align-content-md-center{align-content:center !important}.align-content-md-between{align-content:space-between !important}.align-content-md-around{align-content:space-around !important}.align-content-md-stretch{align-content:stretch !important}.align-self-md-auto{align-self:auto !important}.align-self-md-start{align-self:flex-start !important}.align-self-md-end{align-self:flex-end !important}.align-self-md-center{align-self:center !important}.align-self-md-baseline{align-self:baseline !important}.align-self-md-stretch{align-self:stretch !important}.order-md-first{order:-1 !important}.order-md-0{order:0 !important}.order-md-1{order:1 !important}.order-md-2{order:2 !important}.order-md-3{order:3 !important}.order-md-4{order:4 !important}.order-md-5{order:5 !important}.order-md-last{order:6 !important}.m-md-0{margin:0 !important}.m-md-1{margin:.25rem !important}.m-md-2{margin:.5rem !important}.m-md-3{margin:1rem !important}.m-md-4{margin:1.5rem !important}.m-md-5{margin:3rem !important}.m-md-auto{margin:auto !important}.mx-md-0{margin-right:0 !important;margin-left:0 !important}.mx-md-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-md-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-md-3{margin-right:1rem !important;margin-left:1rem !important}.mx-md-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-md-5{margin-right:3rem !important;margin-left:3rem !important}.mx-md-auto{margin-right:auto !important;margin-left:auto !important}.my-md-0{margin-top:0 !important;margin-bottom:0 !important}.my-md-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-md-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-md-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-md-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-md-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-md-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-md-0{margin-top:0 !important}.mt-md-1{margin-top:.25rem !important}.mt-md-2{margin-top:.5rem !important}.mt-md-3{margin-top:1rem !important}.mt-md-4{margin-top:1.5rem !important}.mt-md-5{margin-top:3rem !important}.mt-md-auto{margin-top:auto !important}.me-md-0{margin-right:0 !important}.me-md-1{margin-right:.25rem !important}.me-md-2{margin-right:.5rem !important}.me-md-3{margin-right:1rem !important}.me-md-4{margin-right:1.5rem !important}.me-md-5{margin-right:3rem !important}.me-md-auto{margin-right:auto !important}.mb-md-0{margin-bottom:0 !important}.mb-md-1{margin-bottom:.25rem !important}.mb-md-2{margin-bottom:.5rem !important}.mb-md-3{margin-bottom:1rem !important}.mb-md-4{margin-bottom:1.5rem !important}.mb-md-5{margin-bottom:3rem !important}.mb-md-auto{margin-bottom:auto !important}.ms-md-0{margin-left:0 !important}.ms-md-1{margin-left:.25rem !important}.ms-md-2{margin-left:.5rem !important}.ms-md-3{margin-left:1rem !important}.ms-md-4{margin-left:1.5rem !important}.ms-md-5{margin-left:3rem !important}.ms-md-auto{margin-left:auto !important}.p-md-0{padding:0 !important}.p-md-1{padding:.25rem !important}.p-md-2{padding:.5rem !important}.p-md-3{padding:1rem !important}.p-md-4{padding:1.5rem !important}.p-md-5{padding:3rem !important}.px-md-0{padding-right:0 !important;padding-left:0 !important}.px-md-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-md-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-md-3{padding-right:1rem !important;padding-left:1rem !important}.px-md-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-md-5{padding-right:3rem !important;padding-left:3rem !important}.py-md-0{padding-top:0 !important;padding-bottom:0 !important}.py-md-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-md-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-md-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-md-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-md-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-md-0{padding-top:0 !important}.pt-md-1{padding-top:.25rem !important}.pt-md-2{padding-top:.5rem !important}.pt-md-3{padding-top:1rem !important}.pt-md-4{padding-top:1.5rem !important}.pt-md-5{padding-top:3rem !important}.pe-md-0{padding-right:0 !important}.pe-md-1{padding-right:.25rem !important}.pe-md-2{padding-right:.5rem !important}.pe-md-3{padding-right:1rem !important}.pe-md-4{padding-right:1.5rem !important}.pe-md-5{padding-right:3rem !important}.pb-md-0{padding-bottom:0 !important}.pb-md-1{padding-bottom:.25rem !important}.pb-md-2{padding-bottom:.5rem !important}.pb-md-3{padding-bottom:1rem !important}.pb-md-4{padding-bottom:1.5rem !important}.pb-md-5{padding-bottom:3rem !important}.ps-md-0{padding-left:0 !important}.ps-md-1{padding-left:.25rem !important}.ps-md-2{padding-left:.5rem !important}.ps-md-3{padding-left:1rem !important}.ps-md-4{padding-left:1.5rem !important}.ps-md-5{padding-left:3rem !important}.gap-md-0{gap:0 !important}.gap-md-1{gap:.25rem !important}.gap-md-2{gap:.5rem !important}.gap-md-3{gap:1rem !important}.gap-md-4{gap:1.5rem !important}.gap-md-5{gap:3rem !important}.row-gap-md-0{row-gap:0 !important}.row-gap-md-1{row-gap:.25rem !important}.row-gap-md-2{row-gap:.5rem !important}.row-gap-md-3{row-gap:1rem !important}.row-gap-md-4{row-gap:1.5rem !important}.row-gap-md-5{row-gap:3rem !important}.column-gap-md-0{column-gap:0 !important}.column-gap-md-1{column-gap:.25rem !important}.column-gap-md-2{column-gap:.5rem !important}.column-gap-md-3{column-gap:1rem !important}.column-gap-md-4{column-gap:1.5rem !important}.column-gap-md-5{column-gap:3rem !important}.text-md-start{text-align:left !important}.text-md-end{text-align:right !important}.text-md-center{text-align:center !important}}@media(min-width: 992px){.float-lg-start{float:left !important}.float-lg-end{float:right !important}.float-lg-none{float:none !important}.object-fit-lg-contain{object-fit:contain !important}.object-fit-lg-cover{object-fit:cover !important}.object-fit-lg-fill{object-fit:fill !important}.object-fit-lg-scale{object-fit:scale-down !important}.object-fit-lg-none{object-fit:none !important}.d-lg-inline{display:inline !important}.d-lg-inline-block{display:inline-block !important}.d-lg-block{display:block !important}.d-lg-grid{display:grid !important}.d-lg-inline-grid{display:inline-grid !important}.d-lg-table{display:table !important}.d-lg-table-row{display:table-row !important}.d-lg-table-cell{display:table-cell !important}.d-lg-flex{display:flex !important}.d-lg-inline-flex{display:inline-flex !important}.d-lg-none{display:none !important}.flex-lg-fill{flex:1 1 auto !important}.flex-lg-row{flex-direction:row !important}.flex-lg-column{flex-direction:column !important}.flex-lg-row-reverse{flex-direction:row-reverse !important}.flex-lg-column-reverse{flex-direction:column-reverse !important}.flex-lg-grow-0{flex-grow:0 !important}.flex-lg-grow-1{flex-grow:1 !important}.flex-lg-shrink-0{flex-shrink:0 !important}.flex-lg-shrink-1{flex-shrink:1 !important}.flex-lg-wrap{flex-wrap:wrap !important}.flex-lg-nowrap{flex-wrap:nowrap !important}.flex-lg-wrap-reverse{flex-wrap:wrap-reverse !important}.justify-content-lg-start{justify-content:flex-start !important}.justify-content-lg-end{justify-content:flex-end !important}.justify-content-lg-center{justify-content:center !important}.justify-content-lg-between{justify-content:space-between !important}.justify-content-lg-around{justify-content:space-around !important}.justify-content-lg-evenly{justify-content:space-evenly !important}.align-items-lg-start{align-items:flex-start !important}.align-items-lg-end{align-items:flex-end !important}.align-items-lg-center{align-items:center !important}.align-items-lg-baseline{align-items:baseline !important}.align-items-lg-stretch{align-items:stretch !important}.align-content-lg-start{align-content:flex-start !important}.align-content-lg-end{align-content:flex-end !important}.align-content-lg-center{align-content:center !important}.align-content-lg-between{align-content:space-between !important}.align-content-lg-around{align-content:space-around !important}.align-content-lg-stretch{align-content:stretch !important}.align-self-lg-auto{align-self:auto !important}.align-self-lg-start{align-self:flex-start !important}.align-self-lg-end{align-self:flex-end !important}.align-self-lg-center{align-self:center !important}.align-self-lg-baseline{align-self:baseline !important}.align-self-lg-stretch{align-self:stretch !important}.order-lg-first{order:-1 !important}.order-lg-0{order:0 !important}.order-lg-1{order:1 !important}.order-lg-2{order:2 !important}.order-lg-3{order:3 !important}.order-lg-4{order:4 !important}.order-lg-5{order:5 !important}.order-lg-last{order:6 !important}.m-lg-0{margin:0 !important}.m-lg-1{margin:.25rem !important}.m-lg-2{margin:.5rem !important}.m-lg-3{margin:1rem !important}.m-lg-4{margin:1.5rem !important}.m-lg-5{margin:3rem !important}.m-lg-auto{margin:auto !important}.mx-lg-0{margin-right:0 !important;margin-left:0 !important}.mx-lg-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-lg-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-lg-3{margin-right:1rem !important;margin-left:1rem !important}.mx-lg-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-lg-5{margin-right:3rem !important;margin-left:3rem !important}.mx-lg-auto{margin-right:auto !important;margin-left:auto !important}.my-lg-0{margin-top:0 !important;margin-bottom:0 !important}.my-lg-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-lg-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-lg-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-lg-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-lg-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-lg-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-lg-0{margin-top:0 !important}.mt-lg-1{margin-top:.25rem !important}.mt-lg-2{margin-top:.5rem !important}.mt-lg-3{margin-top:1rem !important}.mt-lg-4{margin-top:1.5rem !important}.mt-lg-5{margin-top:3rem !important}.mt-lg-auto{margin-top:auto !important}.me-lg-0{margin-right:0 !important}.me-lg-1{margin-right:.25rem !important}.me-lg-2{margin-right:.5rem !important}.me-lg-3{margin-right:1rem !important}.me-lg-4{margin-right:1.5rem !important}.me-lg-5{margin-right:3rem !important}.me-lg-auto{margin-right:auto !important}.mb-lg-0{margin-bottom:0 !important}.mb-lg-1{margin-bottom:.25rem !important}.mb-lg-2{margin-bottom:.5rem !important}.mb-lg-3{margin-bottom:1rem !important}.mb-lg-4{margin-bottom:1.5rem !important}.mb-lg-5{margin-bottom:3rem !important}.mb-lg-auto{margin-bottom:auto !important}.ms-lg-0{margin-left:0 !important}.ms-lg-1{margin-left:.25rem !important}.ms-lg-2{margin-left:.5rem !important}.ms-lg-3{margin-left:1rem !important}.ms-lg-4{margin-left:1.5rem !important}.ms-lg-5{margin-left:3rem !important}.ms-lg-auto{margin-left:auto !important}.p-lg-0{padding:0 !important}.p-lg-1{padding:.25rem !important}.p-lg-2{padding:.5rem !important}.p-lg-3{padding:1rem !important}.p-lg-4{padding:1.5rem !important}.p-lg-5{padding:3rem !important}.px-lg-0{padding-right:0 !important;padding-left:0 !important}.px-lg-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-lg-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-lg-3{padding-right:1rem !important;padding-left:1rem !important}.px-lg-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-lg-5{padding-right:3rem !important;padding-left:3rem !important}.py-lg-0{padding-top:0 !important;padding-bottom:0 !important}.py-lg-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-lg-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-lg-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-lg-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-lg-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-lg-0{padding-top:0 !important}.pt-lg-1{padding-top:.25rem !important}.pt-lg-2{padding-top:.5rem !important}.pt-lg-3{padding-top:1rem !important}.pt-lg-4{padding-top:1.5rem !important}.pt-lg-5{padding-top:3rem !important}.pe-lg-0{padding-right:0 !important}.pe-lg-1{padding-right:.25rem !important}.pe-lg-2{padding-right:.5rem !important}.pe-lg-3{padding-right:1rem !important}.pe-lg-4{padding-right:1.5rem !important}.pe-lg-5{padding-right:3rem !important}.pb-lg-0{padding-bottom:0 !important}.pb-lg-1{padding-bottom:.25rem !important}.pb-lg-2{padding-bottom:.5rem !important}.pb-lg-3{padding-bottom:1rem !important}.pb-lg-4{padding-bottom:1.5rem !important}.pb-lg-5{padding-bottom:3rem !important}.ps-lg-0{padding-left:0 !important}.ps-lg-1{padding-left:.25rem !important}.ps-lg-2{padding-left:.5rem !important}.ps-lg-3{padding-left:1rem !important}.ps-lg-4{padding-left:1.5rem !important}.ps-lg-5{padding-left:3rem !important}.gap-lg-0{gap:0 !important}.gap-lg-1{gap:.25rem !important}.gap-lg-2{gap:.5rem !important}.gap-lg-3{gap:1rem !important}.gap-lg-4{gap:1.5rem !important}.gap-lg-5{gap:3rem !important}.row-gap-lg-0{row-gap:0 !important}.row-gap-lg-1{row-gap:.25rem !important}.row-gap-lg-2{row-gap:.5rem !important}.row-gap-lg-3{row-gap:1rem !important}.row-gap-lg-4{row-gap:1.5rem !important}.row-gap-lg-5{row-gap:3rem !important}.column-gap-lg-0{column-gap:0 !important}.column-gap-lg-1{column-gap:.25rem !important}.column-gap-lg-2{column-gap:.5rem !important}.column-gap-lg-3{column-gap:1rem !important}.column-gap-lg-4{column-gap:1.5rem !important}.column-gap-lg-5{column-gap:3rem !important}.text-lg-start{text-align:left !important}.text-lg-end{text-align:right !important}.text-lg-center{text-align:center !important}}@media(min-width: 1200px){.float-xl-start{float:left !important}.float-xl-end{float:right !important}.float-xl-none{float:none !important}.object-fit-xl-contain{object-fit:contain !important}.object-fit-xl-cover{object-fit:cover !important}.object-fit-xl-fill{object-fit:fill !important}.object-fit-xl-scale{object-fit:scale-down !important}.object-fit-xl-none{object-fit:none !important}.d-xl-inline{display:inline !important}.d-xl-inline-block{display:inline-block !important}.d-xl-block{display:block !important}.d-xl-grid{display:grid !important}.d-xl-inline-grid{display:inline-grid !important}.d-xl-table{display:table !important}.d-xl-table-row{display:table-row !important}.d-xl-table-cell{display:table-cell !important}.d-xl-flex{display:flex !important}.d-xl-inline-flex{display:inline-flex !important}.d-xl-none{display:none !important}.flex-xl-fill{flex:1 1 auto !important}.flex-xl-row{flex-direction:row !important}.flex-xl-column{flex-direction:column !important}.flex-xl-row-reverse{flex-direction:row-reverse !important}.flex-xl-column-reverse{flex-direction:column-reverse !important}.flex-xl-grow-0{flex-grow:0 !important}.flex-xl-grow-1{flex-grow:1 !important}.flex-xl-shrink-0{flex-shrink:0 !important}.flex-xl-shrink-1{flex-shrink:1 !important}.flex-xl-wrap{flex-wrap:wrap !important}.flex-xl-nowrap{flex-wrap:nowrap !important}.flex-xl-wrap-reverse{flex-wrap:wrap-reverse !important}.justify-content-xl-start{justify-content:flex-start !important}.justify-content-xl-end{justify-content:flex-end !important}.justify-content-xl-center{justify-content:center !important}.justify-content-xl-between{justify-content:space-between !important}.justify-content-xl-around{justify-content:space-around !important}.justify-content-xl-evenly{justify-content:space-evenly !important}.align-items-xl-start{align-items:flex-start !important}.align-items-xl-end{align-items:flex-end !important}.align-items-xl-center{align-items:center !important}.align-items-xl-baseline{align-items:baseline !important}.align-items-xl-stretch{align-items:stretch !important}.align-content-xl-start{align-content:flex-start !important}.align-content-xl-end{align-content:flex-end !important}.align-content-xl-center{align-content:center !important}.align-content-xl-between{align-content:space-between !important}.align-content-xl-around{align-content:space-around !important}.align-content-xl-stretch{align-content:stretch !important}.align-self-xl-auto{align-self:auto !important}.align-self-xl-start{align-self:flex-start !important}.align-self-xl-end{align-self:flex-end !important}.align-self-xl-center{align-self:center !important}.align-self-xl-baseline{align-self:baseline !important}.align-self-xl-stretch{align-self:stretch !important}.order-xl-first{order:-1 !important}.order-xl-0{order:0 !important}.order-xl-1{order:1 !important}.order-xl-2{order:2 !important}.order-xl-3{order:3 !important}.order-xl-4{order:4 !important}.order-xl-5{order:5 !important}.order-xl-last{order:6 !important}.m-xl-0{margin:0 !important}.m-xl-1{margin:.25rem !important}.m-xl-2{margin:.5rem !important}.m-xl-3{margin:1rem !important}.m-xl-4{margin:1.5rem !important}.m-xl-5{margin:3rem !important}.m-xl-auto{margin:auto !important}.mx-xl-0{margin-right:0 !important;margin-left:0 !important}.mx-xl-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-xl-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-xl-3{margin-right:1rem !important;margin-left:1rem !important}.mx-xl-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-xl-5{margin-right:3rem !important;margin-left:3rem !important}.mx-xl-auto{margin-right:auto !important;margin-left:auto !important}.my-xl-0{margin-top:0 !important;margin-bottom:0 !important}.my-xl-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-xl-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-xl-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-xl-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-xl-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-xl-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-xl-0{margin-top:0 !important}.mt-xl-1{margin-top:.25rem !important}.mt-xl-2{margin-top:.5rem !important}.mt-xl-3{margin-top:1rem !important}.mt-xl-4{margin-top:1.5rem !important}.mt-xl-5{margin-top:3rem !important}.mt-xl-auto{margin-top:auto !important}.me-xl-0{margin-right:0 !important}.me-xl-1{margin-right:.25rem !important}.me-xl-2{margin-right:.5rem !important}.me-xl-3{margin-right:1rem !important}.me-xl-4{margin-right:1.5rem !important}.me-xl-5{margin-right:3rem !important}.me-xl-auto{margin-right:auto !important}.mb-xl-0{margin-bottom:0 !important}.mb-xl-1{margin-bottom:.25rem !important}.mb-xl-2{margin-bottom:.5rem !important}.mb-xl-3{margin-bottom:1rem !important}.mb-xl-4{margin-bottom:1.5rem !important}.mb-xl-5{margin-bottom:3rem !important}.mb-xl-auto{margin-bottom:auto !important}.ms-xl-0{margin-left:0 !important}.ms-xl-1{margin-left:.25rem !important}.ms-xl-2{margin-left:.5rem !important}.ms-xl-3{margin-left:1rem !important}.ms-xl-4{margin-left:1.5rem !important}.ms-xl-5{margin-left:3rem !important}.ms-xl-auto{margin-left:auto !important}.p-xl-0{padding:0 !important}.p-xl-1{padding:.25rem !important}.p-xl-2{padding:.5rem !important}.p-xl-3{padding:1rem !important}.p-xl-4{padding:1.5rem !important}.p-xl-5{padding:3rem !important}.px-xl-0{padding-right:0 !important;padding-left:0 !important}.px-xl-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-xl-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-xl-3{padding-right:1rem !important;padding-left:1rem !important}.px-xl-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-xl-5{padding-right:3rem !important;padding-left:3rem !important}.py-xl-0{padding-top:0 !important;padding-bottom:0 !important}.py-xl-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-xl-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-xl-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-xl-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-xl-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-xl-0{padding-top:0 !important}.pt-xl-1{padding-top:.25rem !important}.pt-xl-2{padding-top:.5rem !important}.pt-xl-3{padding-top:1rem !important}.pt-xl-4{padding-top:1.5rem !important}.pt-xl-5{padding-top:3rem !important}.pe-xl-0{padding-right:0 !important}.pe-xl-1{padding-right:.25rem !important}.pe-xl-2{padding-right:.5rem !important}.pe-xl-3{padding-right:1rem !important}.pe-xl-4{padding-right:1.5rem !important}.pe-xl-5{padding-right:3rem !important}.pb-xl-0{padding-bottom:0 !important}.pb-xl-1{padding-bottom:.25rem !important}.pb-xl-2{padding-bottom:.5rem !important}.pb-xl-3{padding-bottom:1rem !important}.pb-xl-4{padding-bottom:1.5rem !important}.pb-xl-5{padding-bottom:3rem !important}.ps-xl-0{padding-left:0 !important}.ps-xl-1{padding-left:.25rem !important}.ps-xl-2{padding-left:.5rem !important}.ps-xl-3{padding-left:1rem !important}.ps-xl-4{padding-left:1.5rem !important}.ps-xl-5{padding-left:3rem !important}.gap-xl-0{gap:0 !important}.gap-xl-1{gap:.25rem !important}.gap-xl-2{gap:.5rem !important}.gap-xl-3{gap:1rem !important}.gap-xl-4{gap:1.5rem !important}.gap-xl-5{gap:3rem !important}.row-gap-xl-0{row-gap:0 !important}.row-gap-xl-1{row-gap:.25rem !important}.row-gap-xl-2{row-gap:.5rem !important}.row-gap-xl-3{row-gap:1rem !important}.row-gap-xl-4{row-gap:1.5rem !important}.row-gap-xl-5{row-gap:3rem !important}.column-gap-xl-0{column-gap:0 !important}.column-gap-xl-1{column-gap:.25rem !important}.column-gap-xl-2{column-gap:.5rem !important}.column-gap-xl-3{column-gap:1rem !important}.column-gap-xl-4{column-gap:1.5rem !important}.column-gap-xl-5{column-gap:3rem !important}.text-xl-start{text-align:left !important}.text-xl-end{text-align:right !important}.text-xl-center{text-align:center !important}}@media(min-width: 1400px){.float-xxl-start{float:left !important}.float-xxl-end{float:right !important}.float-xxl-none{float:none !important}.object-fit-xxl-contain{object-fit:contain !important}.object-fit-xxl-cover{object-fit:cover !important}.object-fit-xxl-fill{object-fit:fill !important}.object-fit-xxl-scale{object-fit:scale-down !important}.object-fit-xxl-none{object-fit:none !important}.d-xxl-inline{display:inline !important}.d-xxl-inline-block{display:inline-block !important}.d-xxl-block{display:block !important}.d-xxl-grid{display:grid !important}.d-xxl-inline-grid{display:inline-grid !important}.d-xxl-table{display:table !important}.d-xxl-table-row{display:table-row !important}.d-xxl-table-cell{display:table-cell !important}.d-xxl-flex{display:flex !important}.d-xxl-inline-flex{display:inline-flex !important}.d-xxl-none{display:none !important}.flex-xxl-fill{flex:1 1 auto !important}.flex-xxl-row{flex-direction:row !important}.flex-xxl-column{flex-direction:column !important}.flex-xxl-row-reverse{flex-direction:row-reverse !important}.flex-xxl-column-reverse{flex-direction:column-reverse !important}.flex-xxl-grow-0{flex-grow:0 !important}.flex-xxl-grow-1{flex-grow:1 !important}.flex-xxl-shrink-0{flex-shrink:0 !important}.flex-xxl-shrink-1{flex-shrink:1 !important}.flex-xxl-wrap{flex-wrap:wrap !important}.flex-xxl-nowrap{flex-wrap:nowrap !important}.flex-xxl-wrap-reverse{flex-wrap:wrap-reverse !important}.justify-content-xxl-start{justify-content:flex-start !important}.justify-content-xxl-end{justify-content:flex-end !important}.justify-content-xxl-center{justify-content:center !important}.justify-content-xxl-between{justify-content:space-between !important}.justify-content-xxl-around{justify-content:space-around !important}.justify-content-xxl-evenly{justify-content:space-evenly !important}.align-items-xxl-start{align-items:flex-start !important}.align-items-xxl-end{align-items:flex-end !important}.align-items-xxl-center{align-items:center !important}.align-items-xxl-baseline{align-items:baseline !important}.align-items-xxl-stretch{align-items:stretch !important}.align-content-xxl-start{align-content:flex-start !important}.align-content-xxl-end{align-content:flex-end !important}.align-content-xxl-center{align-content:center !important}.align-content-xxl-between{align-content:space-between !important}.align-content-xxl-around{align-content:space-around !important}.align-content-xxl-stretch{align-content:stretch !important}.align-self-xxl-auto{align-self:auto !important}.align-self-xxl-start{align-self:flex-start !important}.align-self-xxl-end{align-self:flex-end !important}.align-self-xxl-center{align-self:center !important}.align-self-xxl-baseline{align-self:baseline !important}.align-self-xxl-stretch{align-self:stretch !important}.order-xxl-first{order:-1 !important}.order-xxl-0{order:0 !important}.order-xxl-1{order:1 !important}.order-xxl-2{order:2 !important}.order-xxl-3{order:3 !important}.order-xxl-4{order:4 !important}.order-xxl-5{order:5 !important}.order-xxl-last{order:6 !important}.m-xxl-0{margin:0 !important}.m-xxl-1{margin:.25rem !important}.m-xxl-2{margin:.5rem !important}.m-xxl-3{margin:1rem !important}.m-xxl-4{margin:1.5rem !important}.m-xxl-5{margin:3rem !important}.m-xxl-auto{margin:auto !important}.mx-xxl-0{margin-right:0 !important;margin-left:0 !important}.mx-xxl-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-xxl-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-xxl-3{margin-right:1rem !important;margin-left:1rem !important}.mx-xxl-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-xxl-5{margin-right:3rem !important;margin-left:3rem !important}.mx-xxl-auto{margin-right:auto !important;margin-left:auto !important}.my-xxl-0{margin-top:0 !important;margin-bottom:0 !important}.my-xxl-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-xxl-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-xxl-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-xxl-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-xxl-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-xxl-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-xxl-0{margin-top:0 !important}.mt-xxl-1{margin-top:.25rem !important}.mt-xxl-2{margin-top:.5rem !important}.mt-xxl-3{margin-top:1rem !important}.mt-xxl-4{margin-top:1.5rem !important}.mt-xxl-5{margin-top:3rem !important}.mt-xxl-auto{margin-top:auto !important}.me-xxl-0{margin-right:0 !important}.me-xxl-1{margin-right:.25rem !important}.me-xxl-2{margin-right:.5rem !important}.me-xxl-3{margin-right:1rem !important}.me-xxl-4{margin-right:1.5rem !important}.me-xxl-5{margin-right:3rem !important}.me-xxl-auto{margin-right:auto !important}.mb-xxl-0{margin-bottom:0 !important}.mb-xxl-1{margin-bottom:.25rem !important}.mb-xxl-2{margin-bottom:.5rem !important}.mb-xxl-3{margin-bottom:1rem !important}.mb-xxl-4{margin-bottom:1.5rem !important}.mb-xxl-5{margin-bottom:3rem !important}.mb-xxl-auto{margin-bottom:auto !important}.ms-xxl-0{margin-left:0 !important}.ms-xxl-1{margin-left:.25rem !important}.ms-xxl-2{margin-left:.5rem !important}.ms-xxl-3{margin-left:1rem !important}.ms-xxl-4{margin-left:1.5rem !important}.ms-xxl-5{margin-left:3rem !important}.ms-xxl-auto{margin-left:auto !important}.p-xxl-0{padding:0 !important}.p-xxl-1{padding:.25rem !important}.p-xxl-2{padding:.5rem !important}.p-xxl-3{padding:1rem !important}.p-xxl-4{padding:1.5rem !important}.p-xxl-5{padding:3rem !important}.px-xxl-0{padding-right:0 !important;padding-left:0 !important}.px-xxl-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-xxl-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-xxl-3{padding-right:1rem !important;padding-left:1rem !important}.px-xxl-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-xxl-5{padding-right:3rem !important;padding-left:3rem !important}.py-xxl-0{padding-top:0 !important;padding-bottom:0 !important}.py-xxl-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-xxl-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-xxl-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-xxl-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-xxl-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-xxl-0{padding-top:0 !important}.pt-xxl-1{padding-top:.25rem !important}.pt-xxl-2{padding-top:.5rem !important}.pt-xxl-3{padding-top:1rem !important}.pt-xxl-4{padding-top:1.5rem !important}.pt-xxl-5{padding-top:3rem !important}.pe-xxl-0{padding-right:0 !important}.pe-xxl-1{padding-right:.25rem !important}.pe-xxl-2{padding-right:.5rem !important}.pe-xxl-3{padding-right:1rem !important}.pe-xxl-4{padding-right:1.5rem !important}.pe-xxl-5{padding-right:3rem !important}.pb-xxl-0{padding-bottom:0 !important}.pb-xxl-1{padding-bottom:.25rem !important}.pb-xxl-2{padding-bottom:.5rem !important}.pb-xxl-3{padding-bottom:1rem !important}.pb-xxl-4{padding-bottom:1.5rem !important}.pb-xxl-5{padding-bottom:3rem !important}.ps-xxl-0{padding-left:0 !important}.ps-xxl-1{padding-left:.25rem !important}.ps-xxl-2{padding-left:.5rem !important}.ps-xxl-3{padding-left:1rem !important}.ps-xxl-4{padding-left:1.5rem !important}.ps-xxl-5{padding-left:3rem !important}.gap-xxl-0{gap:0 !important}.gap-xxl-1{gap:.25rem !important}.gap-xxl-2{gap:.5rem !important}.gap-xxl-3{gap:1rem !important}.gap-xxl-4{gap:1.5rem !important}.gap-xxl-5{gap:3rem !important}.row-gap-xxl-0{row-gap:0 !important}.row-gap-xxl-1{row-gap:.25rem !important}.row-gap-xxl-2{row-gap:.5rem !important}.row-gap-xxl-3{row-gap:1rem !important}.row-gap-xxl-4{row-gap:1.5rem !important}.row-gap-xxl-5{row-gap:3rem !important}.column-gap-xxl-0{column-gap:0 !important}.column-gap-xxl-1{column-gap:.25rem !important}.column-gap-xxl-2{column-gap:.5rem !important}.column-gap-xxl-3{column-gap:1rem !important}.column-gap-xxl-4{column-gap:1.5rem !important}.column-gap-xxl-5{column-gap:3rem !important}.text-xxl-start{text-align:left !important}.text-xxl-end{text-align:right !important}.text-xxl-center{text-align:center !important}}.bg-default{color:#000}.bg-primary{color:#fff}.bg-secondary{color:#fff}.bg-success{color:#fff}.bg-info{color:#000}.bg-warning{color:#000}.bg-danger{color:#fff}.bg-light{color:#000}.bg-dark{color:#fff}@media(min-width: 1200px){.fs-1{font-size:2rem !important}.fs-2{font-size:1.65rem !important}.fs-3{font-size:1.45rem !important}}@media print{.d-print-inline{display:inline !important}.d-print-inline-block{display:inline-block !important}.d-print-block{display:block !important}.d-print-grid{display:grid !important}.d-print-inline-grid{display:inline-grid !important}.d-print-table{display:table !important}.d-print-table-row{display:table-row !important}.d-print-table-cell{display:table-cell !important}.d-print-flex{display:flex !important}.d-print-inline-flex{display:inline-flex !important}.d-print-none{display:none !important}}.tab-content>.tab-pane.html-fill-container{display:none}.tab-content>.active.html-fill-container{display:flex}.tab-content.html-fill-container{padding:0}:root{--bslib-spacer: 1rem;--bslib-mb-spacer: var(--bslib-spacer, 1rem)}.bslib-mb-spacing{margin-bottom:var(--bslib-mb-spacer)}.bslib-gap-spacing{gap:var(--bslib-mb-spacer)}.bslib-gap-spacing>.bslib-mb-spacing,.bslib-gap-spacing>.form-group,.bslib-gap-spacing>p,.bslib-gap-spacing>pre{margin-bottom:0}.html-fill-container>.html-fill-item.bslib-mb-spacing{margin-bottom:0}.tab-content>.tab-pane.html-fill-container{display:none}.tab-content>.active.html-fill-container{display:flex}.tab-content.html-fill-container{padding:0}.bg-blue{--bslib-color-bg: #0d6efd;--bslib-color-fg: #ffffff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-blue{--bslib-color-fg: #0d6efd;color:var(--bslib-color-fg)}.bg-indigo{--bslib-color-bg: #6610f2;--bslib-color-fg: #ffffff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-indigo{--bslib-color-fg: #6610f2;color:var(--bslib-color-fg)}.bg-purple{--bslib-color-bg: #6f42c1;--bslib-color-fg: #ffffff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-purple{--bslib-color-fg: #6f42c1;color:var(--bslib-color-fg)}.bg-pink{--bslib-color-bg: #d63384;--bslib-color-fg: #ffffff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-pink{--bslib-color-fg: #d63384;color:var(--bslib-color-fg)}.bg-red{--bslib-color-bg: #dc3545;--bslib-color-fg: #ffffff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-red{--bslib-color-fg: #dc3545;color:var(--bslib-color-fg)}.bg-orange{--bslib-color-bg: #fd7e14;--bslib-color-fg: #000;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-orange{--bslib-color-fg: #fd7e14;color:var(--bslib-color-fg)}.bg-yellow{--bslib-color-bg: #ffc107;--bslib-color-fg: #000;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-yellow{--bslib-color-fg: #ffc107;color:var(--bslib-color-fg)}.bg-green{--bslib-color-bg: #198754;--bslib-color-fg: #ffffff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-green{--bslib-color-fg: #198754;color:var(--bslib-color-fg)}.bg-teal{--bslib-color-bg: #20c997;--bslib-color-fg: #000;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-teal{--bslib-color-fg: #20c997;color:var(--bslib-color-fg)}.bg-cyan{--bslib-color-bg: #0dcaf0;--bslib-color-fg: #000;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-cyan{--bslib-color-fg: #0dcaf0;color:var(--bslib-color-fg)}.text-default{--bslib-color-fg: #dee2e6}.bg-default{--bslib-color-bg: #dee2e6;--bslib-color-fg: #000}.text-primary{--bslib-color-fg: #0d6efd}.bg-primary{--bslib-color-bg: #0d6efd;--bslib-color-fg: #ffffff}.text-secondary{--bslib-color-fg: #6c757d}.bg-secondary{--bslib-color-bg: #6c757d;--bslib-color-fg: #ffffff}.text-success{--bslib-color-fg: #198754}.bg-success{--bslib-color-bg: #198754;--bslib-color-fg: #ffffff}.text-info{--bslib-color-fg: #0dcaf0}.bg-info{--bslib-color-bg: #0dcaf0;--bslib-color-fg: #000}.text-warning{--bslib-color-fg: #ffc107}.bg-warning{--bslib-color-bg: #ffc107;--bslib-color-fg: #000}.text-danger{--bslib-color-fg: #dc3545}.bg-danger{--bslib-color-bg: #dc3545;--bslib-color-fg: #ffffff}.text-light{--bslib-color-fg: #f8f9fa}.bg-light{--bslib-color-bg: #f8f9fa;--bslib-color-fg: #000}.text-dark{--bslib-color-fg: #212529}.bg-dark{--bslib-color-bg: #212529;--bslib-color-fg: #ffffff}.bg-gradient-blue-indigo{--bslib-color-fg: #ffffff;--bslib-color-bg: #3148f9;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #3148f9;color:#fff}.bg-gradient-blue-purple{--bslib-color-fg: #ffffff;--bslib-color-bg: #345ce5;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #345ce5;color:#fff}.bg-gradient-blue-pink{--bslib-color-fg: #ffffff;--bslib-color-bg: #5d56cd;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #5d56cd;color:#fff}.bg-gradient-blue-red{--bslib-color-fg: #ffffff;--bslib-color-bg: #6057b3;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #6057b3;color:#fff}.bg-gradient-blue-orange{--bslib-color-fg: #ffffff;--bslib-color-bg: #6d74a0;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #6d74a0;color:#fff}.bg-gradient-blue-yellow{--bslib-color-fg: #000;--bslib-color-bg: #6e8f9b;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #6e8f9b;color:#000}.bg-gradient-blue-green{--bslib-color-fg: #ffffff;--bslib-color-bg: #1278b9;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #1278b9;color:#fff}.bg-gradient-blue-teal{--bslib-color-fg: #000;--bslib-color-bg: #1592d4;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #1592d4;color:#000}.bg-gradient-blue-cyan{--bslib-color-fg: #000;--bslib-color-bg: #0d93f8;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #0d93f8;color:#000}.bg-gradient-indigo-blue{--bslib-color-fg: #ffffff;--bslib-color-bg: #4236f6;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #4236f6;color:#fff}.bg-gradient-indigo-purple{--bslib-color-fg: #ffffff;--bslib-color-bg: #6a24de;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #6a24de;color:#fff}.bg-gradient-indigo-pink{--bslib-color-fg: #ffffff;--bslib-color-bg: #931ec6;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #931ec6;color:#fff}.bg-gradient-indigo-red{--bslib-color-fg: #ffffff;--bslib-color-bg: #951fad;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #951fad;color:#fff}.bg-gradient-indigo-orange{--bslib-color-fg: #ffffff;--bslib-color-bg: #a23c99;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #a23c99;color:#fff}.bg-gradient-indigo-yellow{--bslib-color-fg: #ffffff;--bslib-color-bg: #a35794;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #a35794;color:#fff}.bg-gradient-indigo-green{--bslib-color-fg: #ffffff;--bslib-color-bg: #4740b3;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #4740b3;color:#fff}.bg-gradient-indigo-teal{--bslib-color-fg: #ffffff;--bslib-color-bg: #4a5ace;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #4a5ace;color:#fff}.bg-gradient-indigo-cyan{--bslib-color-fg: #ffffff;--bslib-color-bg: #425af1;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #425af1;color:#fff}.bg-gradient-purple-blue{--bslib-color-fg: #ffffff;--bslib-color-bg: #4854d9;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #4854d9;color:#fff}.bg-gradient-purple-indigo{--bslib-color-fg: #ffffff;--bslib-color-bg: #6b2ed5;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #6b2ed5;color:#fff}.bg-gradient-purple-pink{--bslib-color-fg: #ffffff;--bslib-color-bg: #983ca9;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #983ca9;color:#fff}.bg-gradient-purple-red{--bslib-color-fg: #ffffff;--bslib-color-bg: #9b3d8f;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #9b3d8f;color:#fff}.bg-gradient-purple-orange{--bslib-color-fg: #ffffff;--bslib-color-bg: #a85a7c;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #a85a7c;color:#fff}.bg-gradient-purple-yellow{--bslib-color-fg: #000;--bslib-color-bg: #a97577;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #a97577;color:#000}.bg-gradient-purple-green{--bslib-color-fg: #ffffff;--bslib-color-bg: #4d5e95;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #4d5e95;color:#fff}.bg-gradient-purple-teal{--bslib-color-fg: #ffffff;--bslib-color-bg: #4f78b0;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #4f78b0;color:#fff}.bg-gradient-purple-cyan{--bslib-color-fg: #000;--bslib-color-bg: #4878d4;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #4878d4;color:#000}.bg-gradient-pink-blue{--bslib-color-fg: #ffffff;--bslib-color-bg: #864bb4;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #864bb4;color:#fff}.bg-gradient-pink-indigo{--bslib-color-fg: #ffffff;--bslib-color-bg: #a925b0;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #a925b0;color:#fff}.bg-gradient-pink-purple{--bslib-color-fg: #ffffff;--bslib-color-bg: #ad399c;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #ad399c;color:#fff}.bg-gradient-pink-red{--bslib-color-fg: #ffffff;--bslib-color-bg: #d8346b;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #d8346b;color:#fff}.bg-gradient-pink-orange{--bslib-color-fg: #000;--bslib-color-bg: #e65157;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #e65157;color:#000}.bg-gradient-pink-yellow{--bslib-color-fg: #000;--bslib-color-bg: #e66c52;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #e66c52;color:#000}.bg-gradient-pink-green{--bslib-color-fg: #ffffff;--bslib-color-bg: #8a5571;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #8a5571;color:#fff}.bg-gradient-pink-teal{--bslib-color-fg: #000;--bslib-color-bg: #8d6f8c;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #8d6f8c;color:#000}.bg-gradient-pink-cyan{--bslib-color-fg: #000;--bslib-color-bg: #866faf;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #866faf;color:#000}.bg-gradient-red-blue{--bslib-color-fg: #ffffff;--bslib-color-bg: #894c8f;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #894c8f;color:#fff}.bg-gradient-red-indigo{--bslib-color-fg: #ffffff;--bslib-color-bg: #ad268a;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #ad268a;color:#fff}.bg-gradient-red-purple{--bslib-color-fg: #ffffff;--bslib-color-bg: #b03a77;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #b03a77;color:#fff}.bg-gradient-red-pink{--bslib-color-fg: #ffffff;--bslib-color-bg: #da345e;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #da345e;color:#fff}.bg-gradient-red-orange{--bslib-color-fg: #000;--bslib-color-bg: #e95231;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #e95231;color:#000}.bg-gradient-red-yellow{--bslib-color-fg: #000;--bslib-color-bg: #ea6d2c;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #ea6d2c;color:#000}.bg-gradient-red-green{--bslib-color-fg: #ffffff;--bslib-color-bg: #8e564b;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #8e564b;color:#fff}.bg-gradient-red-teal{--bslib-color-fg: #000;--bslib-color-bg: #917066;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #917066;color:#000}.bg-gradient-red-cyan{--bslib-color-fg: #000;--bslib-color-bg: #897189;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #897189;color:#000}.bg-gradient-orange-blue{--bslib-color-fg: #000;--bslib-color-bg: #9d7871;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #9d7871;color:#000}.bg-gradient-orange-indigo{--bslib-color-fg: #000;--bslib-color-bg: #c1526d;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #c1526d;color:#000}.bg-gradient-orange-purple{--bslib-color-fg: #000;--bslib-color-bg: #c46659;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #c46659;color:#000}.bg-gradient-orange-pink{--bslib-color-fg: #000;--bslib-color-bg: #ed6041;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #ed6041;color:#000}.bg-gradient-orange-red{--bslib-color-fg: #000;--bslib-color-bg: #f06128;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #f06128;color:#000}.bg-gradient-orange-yellow{--bslib-color-fg: #000;--bslib-color-bg: #fe990f;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #fe990f;color:#000}.bg-gradient-orange-green{--bslib-color-fg: #000;--bslib-color-bg: #a2822e;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #a2822e;color:#000}.bg-gradient-orange-teal{--bslib-color-fg: #000;--bslib-color-bg: #a59c48;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #a59c48;color:#000}.bg-gradient-orange-cyan{--bslib-color-fg: #000;--bslib-color-bg: #9d9c6c;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #9d9c6c;color:#000}.bg-gradient-yellow-blue{--bslib-color-fg: #000;--bslib-color-bg: #9ea069;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #9ea069;color:#000}.bg-gradient-yellow-indigo{--bslib-color-fg: #000;--bslib-color-bg: #c27a65;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #c27a65;color:#000}.bg-gradient-yellow-purple{--bslib-color-fg: #000;--bslib-color-bg: #c58e51;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #c58e51;color:#000}.bg-gradient-yellow-pink{--bslib-color-fg: #000;--bslib-color-bg: #ef8839;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #ef8839;color:#000}.bg-gradient-yellow-red{--bslib-color-fg: #000;--bslib-color-bg: #f18920;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #f18920;color:#000}.bg-gradient-yellow-orange{--bslib-color-fg: #000;--bslib-color-bg: #fea60c;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #fea60c;color:#000}.bg-gradient-yellow-green{--bslib-color-fg: #000;--bslib-color-bg: #a3aa26;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #a3aa26;color:#000}.bg-gradient-yellow-teal{--bslib-color-fg: #000;--bslib-color-bg: #a6c441;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #a6c441;color:#000}.bg-gradient-yellow-cyan{--bslib-color-fg: #000;--bslib-color-bg: #9ec564;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #9ec564;color:#000}.bg-gradient-green-blue{--bslib-color-fg: #ffffff;--bslib-color-bg: #147d98;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #147d98;color:#fff}.bg-gradient-green-indigo{--bslib-color-fg: #ffffff;--bslib-color-bg: #385793;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #385793;color:#fff}.bg-gradient-green-purple{--bslib-color-fg: #ffffff;--bslib-color-bg: #3b6b80;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #3b6b80;color:#fff}.bg-gradient-green-pink{--bslib-color-fg: #ffffff;--bslib-color-bg: #656567;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #656567;color:#fff}.bg-gradient-green-red{--bslib-color-fg: #ffffff;--bslib-color-bg: #67664e;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #67664e;color:#fff}.bg-gradient-green-orange{--bslib-color-fg: #000;--bslib-color-bg: #74833a;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #74833a;color:#000}.bg-gradient-green-yellow{--bslib-color-fg: #000;--bslib-color-bg: #759e35;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #759e35;color:#000}.bg-gradient-green-teal{--bslib-color-fg: #000;--bslib-color-bg: #1ca16f;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #1ca16f;color:#000}.bg-gradient-green-cyan{--bslib-color-fg: #000;--bslib-color-bg: #14a292;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #14a292;color:#000}.bg-gradient-teal-blue{--bslib-color-fg: #000;--bslib-color-bg: #18a5c0;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #18a5c0;color:#000}.bg-gradient-teal-indigo{--bslib-color-fg: #000;--bslib-color-bg: #3c7fbb;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #3c7fbb;color:#000}.bg-gradient-teal-purple{--bslib-color-fg: #000;--bslib-color-bg: #4093a8;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #4093a8;color:#000}.bg-gradient-teal-pink{--bslib-color-fg: #000;--bslib-color-bg: #698d8f;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #698d8f;color:#000}.bg-gradient-teal-red{--bslib-color-fg: #000;--bslib-color-bg: #6b8e76;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #6b8e76;color:#000}.bg-gradient-teal-orange{--bslib-color-fg: #000;--bslib-color-bg: #78ab63;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #78ab63;color:#000}.bg-gradient-teal-yellow{--bslib-color-fg: #000;--bslib-color-bg: #79c65d;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #79c65d;color:#000}.bg-gradient-teal-green{--bslib-color-fg: #000;--bslib-color-bg: #1daf7c;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #1daf7c;color:#000}.bg-gradient-teal-cyan{--bslib-color-fg: #000;--bslib-color-bg: #18c9bb;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #18c9bb;color:#000}.bg-gradient-cyan-blue{--bslib-color-fg: #000;--bslib-color-bg: #0da5f5;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #0da5f5;color:#000}.bg-gradient-cyan-indigo{--bslib-color-fg: #000;--bslib-color-bg: #3180f1;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #3180f1;color:#000}.bg-gradient-cyan-purple{--bslib-color-fg: #000;--bslib-color-bg: #3494dd;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #3494dd;color:#000}.bg-gradient-cyan-pink{--bslib-color-fg: #000;--bslib-color-bg: #5d8ec5;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #5d8ec5;color:#000}.bg-gradient-cyan-red{--bslib-color-fg: #000;--bslib-color-bg: #608eac;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #608eac;color:#000}.bg-gradient-cyan-orange{--bslib-color-fg: #000;--bslib-color-bg: #6dac98;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #6dac98;color:#000}.bg-gradient-cyan-yellow{--bslib-color-fg: #000;--bslib-color-bg: #6ec693;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #6ec693;color:#000}.bg-gradient-cyan-green{--bslib-color-fg: #000;--bslib-color-bg: #12afb2;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #12afb2;color:#000}.bg-gradient-cyan-teal{--bslib-color-fg: #000;--bslib-color-bg: #15cacc;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #15cacc;color:#000}.bg-blue{--bslib-color-bg: #0d6efd;--bslib-color-fg: #ffffff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-blue{--bslib-color-fg: #0d6efd;color:var(--bslib-color-fg)}.bg-indigo{--bslib-color-bg: #6610f2;--bslib-color-fg: #ffffff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-indigo{--bslib-color-fg: #6610f2;color:var(--bslib-color-fg)}.bg-purple{--bslib-color-bg: #6f42c1;--bslib-color-fg: #ffffff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-purple{--bslib-color-fg: #6f42c1;color:var(--bslib-color-fg)}.bg-pink{--bslib-color-bg: #d63384;--bslib-color-fg: #ffffff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-pink{--bslib-color-fg: #d63384;color:var(--bslib-color-fg)}.bg-red{--bslib-color-bg: #dc3545;--bslib-color-fg: #ffffff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-red{--bslib-color-fg: #dc3545;color:var(--bslib-color-fg)}.bg-orange{--bslib-color-bg: #fd7e14;--bslib-color-fg: #000;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-orange{--bslib-color-fg: #fd7e14;color:var(--bslib-color-fg)}.bg-yellow{--bslib-color-bg: #ffc107;--bslib-color-fg: #000;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-yellow{--bslib-color-fg: #ffc107;color:var(--bslib-color-fg)}.bg-green{--bslib-color-bg: #198754;--bslib-color-fg: #ffffff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-green{--bslib-color-fg: #198754;color:var(--bslib-color-fg)}.bg-teal{--bslib-color-bg: #20c997;--bslib-color-fg: #000;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-teal{--bslib-color-fg: #20c997;color:var(--bslib-color-fg)}.bg-cyan{--bslib-color-bg: #0dcaf0;--bslib-color-fg: #000;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-cyan{--bslib-color-fg: #0dcaf0;color:var(--bslib-color-fg)}.text-default{--bslib-color-fg: #dee2e6}.bg-default{--bslib-color-bg: #dee2e6;--bslib-color-fg: #000}.text-primary{--bslib-color-fg: #0d6efd}.bg-primary{--bslib-color-bg: #0d6efd;--bslib-color-fg: #ffffff}.text-secondary{--bslib-color-fg: #6c757d}.bg-secondary{--bslib-color-bg: #6c757d;--bslib-color-fg: #ffffff}.text-success{--bslib-color-fg: #198754}.bg-success{--bslib-color-bg: #198754;--bslib-color-fg: #ffffff}.text-info{--bslib-color-fg: #0dcaf0}.bg-info{--bslib-color-bg: #0dcaf0;--bslib-color-fg: #000}.text-warning{--bslib-color-fg: #ffc107}.bg-warning{--bslib-color-bg: #ffc107;--bslib-color-fg: #000}.text-danger{--bslib-color-fg: #dc3545}.bg-danger{--bslib-color-bg: #dc3545;--bslib-color-fg: #ffffff}.text-light{--bslib-color-fg: #f8f9fa}.bg-light{--bslib-color-bg: #f8f9fa;--bslib-color-fg: #000}.text-dark{--bslib-color-fg: #212529}.bg-dark{--bslib-color-bg: #212529;--bslib-color-fg: #ffffff}.bg-gradient-blue-indigo{--bslib-color-fg: #ffffff;--bslib-color-bg: #3148f9;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #3148f9;color:#fff}.bg-gradient-blue-purple{--bslib-color-fg: #ffffff;--bslib-color-bg: #345ce5;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #345ce5;color:#fff}.bg-gradient-blue-pink{--bslib-color-fg: #ffffff;--bslib-color-bg: #5d56cd;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #5d56cd;color:#fff}.bg-gradient-blue-red{--bslib-color-fg: #ffffff;--bslib-color-bg: #6057b3;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #6057b3;color:#fff}.bg-gradient-blue-orange{--bslib-color-fg: #ffffff;--bslib-color-bg: #6d74a0;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #6d74a0;color:#fff}.bg-gradient-blue-yellow{--bslib-color-fg: #000;--bslib-color-bg: #6e8f9b;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #6e8f9b;color:#000}.bg-gradient-blue-green{--bslib-color-fg: #ffffff;--bslib-color-bg: #1278b9;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #1278b9;color:#fff}.bg-gradient-blue-teal{--bslib-color-fg: #000;--bslib-color-bg: #1592d4;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #1592d4;color:#000}.bg-gradient-blue-cyan{--bslib-color-fg: #000;--bslib-color-bg: #0d93f8;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #0d93f8;color:#000}.bg-gradient-indigo-blue{--bslib-color-fg: #ffffff;--bslib-color-bg: #4236f6;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #4236f6;color:#fff}.bg-gradient-indigo-purple{--bslib-color-fg: #ffffff;--bslib-color-bg: #6a24de;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #6a24de;color:#fff}.bg-gradient-indigo-pink{--bslib-color-fg: #ffffff;--bslib-color-bg: #931ec6;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #931ec6;color:#fff}.bg-gradient-indigo-red{--bslib-color-fg: #ffffff;--bslib-color-bg: #951fad;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #951fad;color:#fff}.bg-gradient-indigo-orange{--bslib-color-fg: #ffffff;--bslib-color-bg: #a23c99;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #a23c99;color:#fff}.bg-gradient-indigo-yellow{--bslib-color-fg: #ffffff;--bslib-color-bg: #a35794;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #a35794;color:#fff}.bg-gradient-indigo-green{--bslib-color-fg: #ffffff;--bslib-color-bg: #4740b3;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #4740b3;color:#fff}.bg-gradient-indigo-teal{--bslib-color-fg: #ffffff;--bslib-color-bg: #4a5ace;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #4a5ace;color:#fff}.bg-gradient-indigo-cyan{--bslib-color-fg: #ffffff;--bslib-color-bg: #425af1;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #425af1;color:#fff}.bg-gradient-purple-blue{--bslib-color-fg: #ffffff;--bslib-color-bg: #4854d9;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #4854d9;color:#fff}.bg-gradient-purple-indigo{--bslib-color-fg: #ffffff;--bslib-color-bg: #6b2ed5;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #6b2ed5;color:#fff}.bg-gradient-purple-pink{--bslib-color-fg: #ffffff;--bslib-color-bg: #983ca9;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #983ca9;color:#fff}.bg-gradient-purple-red{--bslib-color-fg: #ffffff;--bslib-color-bg: #9b3d8f;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #9b3d8f;color:#fff}.bg-gradient-purple-orange{--bslib-color-fg: #ffffff;--bslib-color-bg: #a85a7c;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #a85a7c;color:#fff}.bg-gradient-purple-yellow{--bslib-color-fg: #000;--bslib-color-bg: #a97577;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #a97577;color:#000}.bg-gradient-purple-green{--bslib-color-fg: #ffffff;--bslib-color-bg: #4d5e95;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #4d5e95;color:#fff}.bg-gradient-purple-teal{--bslib-color-fg: #ffffff;--bslib-color-bg: #4f78b0;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #4f78b0;color:#fff}.bg-gradient-purple-cyan{--bslib-color-fg: #000;--bslib-color-bg: #4878d4;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #4878d4;color:#000}.bg-gradient-pink-blue{--bslib-color-fg: #ffffff;--bslib-color-bg: #864bb4;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #864bb4;color:#fff}.bg-gradient-pink-indigo{--bslib-color-fg: #ffffff;--bslib-color-bg: #a925b0;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #a925b0;color:#fff}.bg-gradient-pink-purple{--bslib-color-fg: #ffffff;--bslib-color-bg: #ad399c;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #ad399c;color:#fff}.bg-gradient-pink-red{--bslib-color-fg: #ffffff;--bslib-color-bg: #d8346b;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #d8346b;color:#fff}.bg-gradient-pink-orange{--bslib-color-fg: #000;--bslib-color-bg: #e65157;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #e65157;color:#000}.bg-gradient-pink-yellow{--bslib-color-fg: #000;--bslib-color-bg: #e66c52;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #e66c52;color:#000}.bg-gradient-pink-green{--bslib-color-fg: #ffffff;--bslib-color-bg: #8a5571;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #8a5571;color:#fff}.bg-gradient-pink-teal{--bslib-color-fg: #000;--bslib-color-bg: #8d6f8c;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #8d6f8c;color:#000}.bg-gradient-pink-cyan{--bslib-color-fg: #000;--bslib-color-bg: #866faf;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #866faf;color:#000}.bg-gradient-red-blue{--bslib-color-fg: #ffffff;--bslib-color-bg: #894c8f;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #894c8f;color:#fff}.bg-gradient-red-indigo{--bslib-color-fg: #ffffff;--bslib-color-bg: #ad268a;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #ad268a;color:#fff}.bg-gradient-red-purple{--bslib-color-fg: #ffffff;--bslib-color-bg: #b03a77;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #b03a77;color:#fff}.bg-gradient-red-pink{--bslib-color-fg: #ffffff;--bslib-color-bg: #da345e;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #da345e;color:#fff}.bg-gradient-red-orange{--bslib-color-fg: #000;--bslib-color-bg: #e95231;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #e95231;color:#000}.bg-gradient-red-yellow{--bslib-color-fg: #000;--bslib-color-bg: #ea6d2c;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #ea6d2c;color:#000}.bg-gradient-red-green{--bslib-color-fg: #ffffff;--bslib-color-bg: #8e564b;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #8e564b;color:#fff}.bg-gradient-red-teal{--bslib-color-fg: #000;--bslib-color-bg: #917066;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #917066;color:#000}.bg-gradient-red-cyan{--bslib-color-fg: #000;--bslib-color-bg: #897189;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #897189;color:#000}.bg-gradient-orange-blue{--bslib-color-fg: #000;--bslib-color-bg: #9d7871;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #9d7871;color:#000}.bg-gradient-orange-indigo{--bslib-color-fg: #000;--bslib-color-bg: #c1526d;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #c1526d;color:#000}.bg-gradient-orange-purple{--bslib-color-fg: #000;--bslib-color-bg: #c46659;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #c46659;color:#000}.bg-gradient-orange-pink{--bslib-color-fg: #000;--bslib-color-bg: #ed6041;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #ed6041;color:#000}.bg-gradient-orange-red{--bslib-color-fg: #000;--bslib-color-bg: #f06128;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #f06128;color:#000}.bg-gradient-orange-yellow{--bslib-color-fg: #000;--bslib-color-bg: #fe990f;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #fe990f;color:#000}.bg-gradient-orange-green{--bslib-color-fg: #000;--bslib-color-bg: #a2822e;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #a2822e;color:#000}.bg-gradient-orange-teal{--bslib-color-fg: #000;--bslib-color-bg: #a59c48;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #a59c48;color:#000}.bg-gradient-orange-cyan{--bslib-color-fg: #000;--bslib-color-bg: #9d9c6c;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #9d9c6c;color:#000}.bg-gradient-yellow-blue{--bslib-color-fg: #000;--bslib-color-bg: #9ea069;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #9ea069;color:#000}.bg-gradient-yellow-indigo{--bslib-color-fg: #000;--bslib-color-bg: #c27a65;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #c27a65;color:#000}.bg-gradient-yellow-purple{--bslib-color-fg: #000;--bslib-color-bg: #c58e51;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #c58e51;color:#000}.bg-gradient-yellow-pink{--bslib-color-fg: #000;--bslib-color-bg: #ef8839;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #ef8839;color:#000}.bg-gradient-yellow-red{--bslib-color-fg: #000;--bslib-color-bg: #f18920;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #f18920;color:#000}.bg-gradient-yellow-orange{--bslib-color-fg: #000;--bslib-color-bg: #fea60c;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #fea60c;color:#000}.bg-gradient-yellow-green{--bslib-color-fg: #000;--bslib-color-bg: #a3aa26;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #a3aa26;color:#000}.bg-gradient-yellow-teal{--bslib-color-fg: #000;--bslib-color-bg: #a6c441;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #a6c441;color:#000}.bg-gradient-yellow-cyan{--bslib-color-fg: #000;--bslib-color-bg: #9ec564;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #9ec564;color:#000}.bg-gradient-green-blue{--bslib-color-fg: #ffffff;--bslib-color-bg: #147d98;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #147d98;color:#fff}.bg-gradient-green-indigo{--bslib-color-fg: #ffffff;--bslib-color-bg: #385793;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #385793;color:#fff}.bg-gradient-green-purple{--bslib-color-fg: #ffffff;--bslib-color-bg: #3b6b80;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #3b6b80;color:#fff}.bg-gradient-green-pink{--bslib-color-fg: #ffffff;--bslib-color-bg: #656567;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #656567;color:#fff}.bg-gradient-green-red{--bslib-color-fg: #ffffff;--bslib-color-bg: #67664e;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #67664e;color:#fff}.bg-gradient-green-orange{--bslib-color-fg: #000;--bslib-color-bg: #74833a;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #74833a;color:#000}.bg-gradient-green-yellow{--bslib-color-fg: #000;--bslib-color-bg: #759e35;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #759e35;color:#000}.bg-gradient-green-teal{--bslib-color-fg: #000;--bslib-color-bg: #1ca16f;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #1ca16f;color:#000}.bg-gradient-green-cyan{--bslib-color-fg: #000;--bslib-color-bg: #14a292;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #14a292;color:#000}.bg-gradient-teal-blue{--bslib-color-fg: #000;--bslib-color-bg: #18a5c0;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #18a5c0;color:#000}.bg-gradient-teal-indigo{--bslib-color-fg: #000;--bslib-color-bg: #3c7fbb;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #3c7fbb;color:#000}.bg-gradient-teal-purple{--bslib-color-fg: #000;--bslib-color-bg: #4093a8;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #4093a8;color:#000}.bg-gradient-teal-pink{--bslib-color-fg: #000;--bslib-color-bg: #698d8f;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #698d8f;color:#000}.bg-gradient-teal-red{--bslib-color-fg: #000;--bslib-color-bg: #6b8e76;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #6b8e76;color:#000}.bg-gradient-teal-orange{--bslib-color-fg: #000;--bslib-color-bg: #78ab63;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #78ab63;color:#000}.bg-gradient-teal-yellow{--bslib-color-fg: #000;--bslib-color-bg: #79c65d;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #79c65d;color:#000}.bg-gradient-teal-green{--bslib-color-fg: #000;--bslib-color-bg: #1daf7c;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #1daf7c;color:#000}.bg-gradient-teal-cyan{--bslib-color-fg: #000;--bslib-color-bg: #18c9bb;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #18c9bb;color:#000}.bg-gradient-cyan-blue{--bslib-color-fg: #000;--bslib-color-bg: #0da5f5;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #0da5f5;color:#000}.bg-gradient-cyan-indigo{--bslib-color-fg: #000;--bslib-color-bg: #3180f1;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #3180f1;color:#000}.bg-gradient-cyan-purple{--bslib-color-fg: #000;--bslib-color-bg: #3494dd;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #3494dd;color:#000}.bg-gradient-cyan-pink{--bslib-color-fg: #000;--bslib-color-bg: #5d8ec5;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #5d8ec5;color:#000}.bg-gradient-cyan-red{--bslib-color-fg: #000;--bslib-color-bg: #608eac;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #608eac;color:#000}.bg-gradient-cyan-orange{--bslib-color-fg: #000;--bslib-color-bg: #6dac98;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #6dac98;color:#000}.bg-gradient-cyan-yellow{--bslib-color-fg: #000;--bslib-color-bg: #6ec693;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #6ec693;color:#000}.bg-gradient-cyan-green{--bslib-color-fg: #000;--bslib-color-bg: #12afb2;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #12afb2;color:#000}.bg-gradient-cyan-teal{--bslib-color-fg: #000;--bslib-color-bg: #15cacc;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #15cacc;color:#000}:root{--bslib-spacer: 1rem;--bslib-mb-spacer: var(--bslib-spacer, 1rem)}.bslib-mb-spacing{margin-bottom:var(--bslib-mb-spacer)}.bslib-gap-spacing{gap:var(--bslib-mb-spacer)}.bslib-gap-spacing>.bslib-mb-spacing,.bslib-gap-spacing>.form-group,.bslib-gap-spacing>p,.bslib-gap-spacing>pre{margin-bottom:0}.html-fill-container>.html-fill-item.bslib-mb-spacing{margin-bottom:0}.bslib-grid{display:grid !important;gap:var(--bslib-spacer, 1rem);height:var(--bslib-grid-height)}.bslib-grid.grid{grid-template-columns:repeat(var(--bs-columns, 12), minmax(0, 1fr));grid-template-rows:unset;grid-auto-rows:var(--bslib-grid--row-heights);--bslib-grid--row-heights--xs: unset;--bslib-grid--row-heights--sm: unset;--bslib-grid--row-heights--md: unset;--bslib-grid--row-heights--lg: unset;--bslib-grid--row-heights--xl: unset;--bslib-grid--row-heights--xxl: unset}.bslib-grid.grid.bslib-grid--row-heights--xs{--bslib-grid--row-heights: var(--bslib-grid--row-heights--xs)}@media(min-width: 576px){.bslib-grid.grid.bslib-grid--row-heights--sm{--bslib-grid--row-heights: var(--bslib-grid--row-heights--sm)}}@media(min-width: 768px){.bslib-grid.grid.bslib-grid--row-heights--md{--bslib-grid--row-heights: var(--bslib-grid--row-heights--md)}}@media(min-width: 992px){.bslib-grid.grid.bslib-grid--row-heights--lg{--bslib-grid--row-heights: var(--bslib-grid--row-heights--lg)}}@media(min-width: 1200px){.bslib-grid.grid.bslib-grid--row-heights--xl{--bslib-grid--row-heights: var(--bslib-grid--row-heights--xl)}}@media(min-width: 1400px){.bslib-grid.grid.bslib-grid--row-heights--xxl{--bslib-grid--row-heights: var(--bslib-grid--row-heights--xxl)}}.bslib-grid>*>.shiny-input-container{width:100%}.bslib-grid-item{grid-column:auto/span 1}@media(max-width: 767.98px){.bslib-grid-item{grid-column:1/-1}}@media(max-width: 575.98px){.bslib-grid{grid-template-columns:1fr !important;height:var(--bslib-grid-height-mobile)}.bslib-grid.grid{height:unset !important;grid-auto-rows:var(--bslib-grid--row-heights--xs, auto)}}@media(min-width: 576px){.nav:not(.nav-hidden){display:flex !important;display:-webkit-flex !important}.nav:not(.nav-hidden):not(.nav-stacked):not(.flex-column){float:none !important}.nav:not(.nav-hidden):not(.nav-stacked):not(.flex-column)>.bslib-nav-spacer{margin-left:auto !important}.nav:not(.nav-hidden):not(.nav-stacked):not(.flex-column)>.form-inline{margin-top:auto;margin-bottom:auto}.nav:not(.nav-hidden).nav-stacked{flex-direction:column;-webkit-flex-direction:column;height:100%}.nav:not(.nav-hidden).nav-stacked>.bslib-nav-spacer{margin-top:auto !important}}.accordion .accordion-header{font-size:calc(1.29rem + 0.48vw);margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2;color:var(--bs-heading-color);margin-bottom:0}@media(min-width: 1200px){.accordion .accordion-header{font-size:1.65rem}}.accordion .accordion-icon:not(:empty){margin-right:.75rem;display:flex}.accordion .accordion-button:not(.collapsed){box-shadow:none}.accordion .accordion-button:not(.collapsed):focus{box-shadow:var(--bs-accordion-btn-focus-box-shadow)}html{height:100%}.bslib-page-fill{width:100%;height:100%;margin:0;padding:var(--bslib-spacer, 1rem);gap:var(--bslib-spacer, 1rem)}@media(max-width: 575.98px){.bslib-page-fill{height:var(--bslib-page-fill-mobile-height, auto)}}.bslib-sidebar-layout{--bslib-sidebar-transition-duration: 500ms;--bslib-sidebar-transition-easing-x: cubic-bezier(0.8, 0.78, 0.22, 1.07);--bslib-sidebar-border: var(--bs-card-border-width, 1px) solid var(--bs-card-border-color, rgba(0, 0, 0, 0.175));--bslib-sidebar-border-radius: var(--bs-border-radius);--bslib-sidebar-vert-border: var(--bs-card-border-width, 1px) solid var(--bs-card-border-color, rgba(0, 0, 0, 0.175));--bslib-sidebar-bg: rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.05);--bslib-sidebar-fg: var(--bs-emphasis-color, black);--bslib-sidebar-main-fg: var(--bs-card-color, var(--bs-body-color));--bslib-sidebar-main-bg: var(--bs-card-bg, var(--bs-body-bg));--bslib-sidebar-toggle-bg: rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.1);--bslib-sidebar-padding: calc(var(--bslib-spacer) * 1.5);--bslib-sidebar-icon-size: var(--bslib-spacer, 1rem);--bslib-sidebar-icon-button-size: calc(var(--bslib-sidebar-icon-size, 1rem) * 2);--bslib-sidebar-padding-icon: calc(var(--bslib-sidebar-icon-button-size, 2rem) * 1.5);--bslib-collapse-toggle-border-radius: var(--bs-border-radius, 0.375rem);--bslib-collapse-toggle-transform: 0deg;--bslib-sidebar-toggle-transition-easing: cubic-bezier(1, 0, 0, 1);--bslib-collapse-toggle-right-transform: 180deg;--bslib-sidebar-column-main: minmax(0, 1fr);display:grid !important;grid-template-columns:min(100% - var(--bslib-sidebar-icon-size),var(--bslib-sidebar-width, 250px)) var(--bslib-sidebar-column-main);position:relative;transition:grid-template-columns ease-in-out var(--bslib-sidebar-transition-duration);border:var(--bslib-sidebar-border);border-radius:var(--bslib-sidebar-border-radius)}@media(prefers-reduced-motion: reduce){.bslib-sidebar-layout{transition:none}}.bslib-sidebar-layout[data-bslib-sidebar-border=false]{border:none}.bslib-sidebar-layout[data-bslib-sidebar-border-radius=false]{border-radius:initial}.bslib-sidebar-layout>.main,.bslib-sidebar-layout>.sidebar{grid-row:1/2;border-radius:inherit;overflow:auto}.bslib-sidebar-layout>.main{grid-column:2/3;border-top-left-radius:0;border-bottom-left-radius:0;padding:var(--bslib-sidebar-padding);transition:padding var(--bslib-sidebar-transition-easing-x) var(--bslib-sidebar-transition-duration);color:var(--bslib-sidebar-main-fg);background-color:var(--bslib-sidebar-main-bg)}.bslib-sidebar-layout>.sidebar{grid-column:1/2;width:100%;height:100%;border-right:var(--bslib-sidebar-vert-border);border-top-right-radius:0;border-bottom-right-radius:0;color:var(--bslib-sidebar-fg);background-color:var(--bslib-sidebar-bg);backdrop-filter:blur(5px)}.bslib-sidebar-layout>.sidebar>.sidebar-content{display:flex;flex-direction:column;gap:var(--bslib-spacer, 1rem);padding:var(--bslib-sidebar-padding);padding-top:var(--bslib-sidebar-padding-icon)}.bslib-sidebar-layout>.sidebar>.sidebar-content>:last-child:not(.sidebar-title){margin-bottom:0}.bslib-sidebar-layout>.sidebar>.sidebar-content>.accordion{margin-left:calc(-1*var(--bslib-sidebar-padding));margin-right:calc(-1*var(--bslib-sidebar-padding))}.bslib-sidebar-layout>.sidebar>.sidebar-content>.accordion:last-child{margin-bottom:calc(-1*var(--bslib-sidebar-padding))}.bslib-sidebar-layout>.sidebar>.sidebar-content>.accordion:not(:last-child){margin-bottom:1rem}.bslib-sidebar-layout>.sidebar>.sidebar-content>.accordion .accordion-body{display:flex;flex-direction:column}.bslib-sidebar-layout>.sidebar>.sidebar-content>.accordion:not(:first-child) .accordion-item:first-child{border-top:var(--bs-accordion-border-width) solid var(--bs-accordion-border-color)}.bslib-sidebar-layout>.sidebar>.sidebar-content>.accordion:not(:last-child) .accordion-item:last-child{border-bottom:var(--bs-accordion-border-width) solid var(--bs-accordion-border-color)}.bslib-sidebar-layout>.sidebar>.sidebar-content.has-accordion>.sidebar-title{border-bottom:none;padding-bottom:0}.bslib-sidebar-layout>.sidebar .shiny-input-container{width:100%}.bslib-sidebar-layout[data-bslib-sidebar-open=always]>.sidebar>.sidebar-content{padding-top:var(--bslib-sidebar-padding)}.bslib-sidebar-layout>.collapse-toggle{grid-row:1/2;grid-column:1/2;display:inline-flex;align-items:center;position:absolute;right:calc(var(--bslib-sidebar-icon-size));top:calc(var(--bslib-sidebar-icon-size, 1rem)/2);border:none;border-radius:var(--bslib-collapse-toggle-border-radius);height:var(--bslib-sidebar-icon-button-size, 2rem);width:var(--bslib-sidebar-icon-button-size, 2rem);display:flex;align-items:center;justify-content:center;padding:0;color:var(--bslib-sidebar-fg);background-color:unset;transition:color var(--bslib-sidebar-transition-easing-x) var(--bslib-sidebar-transition-duration),top var(--bslib-sidebar-transition-easing-x) var(--bslib-sidebar-transition-duration),right var(--bslib-sidebar-transition-easing-x) var(--bslib-sidebar-transition-duration),left var(--bslib-sidebar-transition-easing-x) var(--bslib-sidebar-transition-duration)}.bslib-sidebar-layout>.collapse-toggle:hover{background-color:var(--bslib-sidebar-toggle-bg)}.bslib-sidebar-layout>.collapse-toggle>.collapse-icon{opacity:.8;width:var(--bslib-sidebar-icon-size);height:var(--bslib-sidebar-icon-size);transform:rotateY(var(--bslib-collapse-toggle-transform));transition:transform var(--bslib-sidebar-toggle-transition-easing) var(--bslib-sidebar-transition-duration)}.bslib-sidebar-layout>.collapse-toggle:hover>.collapse-icon{opacity:1}.bslib-sidebar-layout .sidebar-title{font-size:1.25rem;line-height:1.25;margin-top:0;margin-bottom:1rem;padding-bottom:1rem;border-bottom:var(--bslib-sidebar-border)}.bslib-sidebar-layout.sidebar-right{grid-template-columns:var(--bslib-sidebar-column-main) min(100% - var(--bslib-sidebar-icon-size),var(--bslib-sidebar-width, 250px))}.bslib-sidebar-layout.sidebar-right>.main{grid-column:1/2;border-top-right-radius:0;border-bottom-right-radius:0;border-top-left-radius:inherit;border-bottom-left-radius:inherit}.bslib-sidebar-layout.sidebar-right>.sidebar{grid-column:2/3;border-right:none;border-left:var(--bslib-sidebar-vert-border);border-top-left-radius:0;border-bottom-left-radius:0}.bslib-sidebar-layout.sidebar-right>.collapse-toggle{grid-column:2/3;left:var(--bslib-sidebar-icon-size);right:unset;border:var(--bslib-collapse-toggle-border)}.bslib-sidebar-layout.sidebar-right>.collapse-toggle>.collapse-icon{transform:rotateY(var(--bslib-collapse-toggle-right-transform))}.bslib-sidebar-layout.sidebar-collapsed{--bslib-collapse-toggle-transform: 180deg;--bslib-collapse-toggle-right-transform: 0deg;--bslib-sidebar-vert-border: none;grid-template-columns:0 minmax(0, 1fr)}.bslib-sidebar-layout.sidebar-collapsed.sidebar-right{grid-template-columns:minmax(0, 1fr) 0}.bslib-sidebar-layout.sidebar-collapsed:not(.transitioning)>.sidebar>*{display:none}.bslib-sidebar-layout.sidebar-collapsed>.main{border-radius:inherit}.bslib-sidebar-layout.sidebar-collapsed:not(.sidebar-right)>.main{padding-left:var(--bslib-sidebar-padding-icon)}.bslib-sidebar-layout.sidebar-collapsed.sidebar-right>.main{padding-right:var(--bslib-sidebar-padding-icon)}.bslib-sidebar-layout.sidebar-collapsed>.collapse-toggle{color:var(--bslib-sidebar-main-fg);top:calc(var(--bslib-sidebar-overlap-counter, 0)*(var(--bslib-sidebar-icon-size) + var(--bslib-sidebar-padding)) + var(--bslib-sidebar-icon-size, 1rem)/2);right:calc(-2.5*var(--bslib-sidebar-icon-size) - var(--bs-card-border-width, 1px))}.bslib-sidebar-layout.sidebar-collapsed.sidebar-right>.collapse-toggle{left:calc(-2.5*var(--bslib-sidebar-icon-size) - var(--bs-card-border-width, 1px));right:unset}@media(min-width: 576px){.bslib-sidebar-layout.transitioning>.sidebar>.sidebar-content{display:none}}@media(max-width: 575.98px){.bslib-sidebar-layout[data-bslib-sidebar-open=desktop]{--bslib-sidebar-js-init-collapsed: true}.bslib-sidebar-layout>.sidebar,.bslib-sidebar-layout.sidebar-right>.sidebar{border:none}.bslib-sidebar-layout>.main,.bslib-sidebar-layout.sidebar-right>.main{grid-column:1/3}.bslib-sidebar-layout[data-bslib-sidebar-open=always]{display:block !important}.bslib-sidebar-layout[data-bslib-sidebar-open=always]>.sidebar{max-height:var(--bslib-sidebar-max-height-mobile);overflow-y:auto;border-top:var(--bslib-sidebar-vert-border)}.bslib-sidebar-layout:not([data-bslib-sidebar-open=always]){grid-template-columns:100% 0}.bslib-sidebar-layout:not([data-bslib-sidebar-open=always]):not(.sidebar-collapsed)>.sidebar{z-index:1}.bslib-sidebar-layout:not([data-bslib-sidebar-open=always]):not(.sidebar-collapsed)>.collapse-toggle{z-index:1}.bslib-sidebar-layout:not([data-bslib-sidebar-open=always]).sidebar-right{grid-template-columns:0 100%}.bslib-sidebar-layout:not([data-bslib-sidebar-open=always]).sidebar-collapsed{grid-template-columns:0 100%}.bslib-sidebar-layout:not([data-bslib-sidebar-open=always]).sidebar-collapsed.sidebar-right{grid-template-columns:100% 0}.bslib-sidebar-layout:not([data-bslib-sidebar-open=always]):not(.sidebar-right)>.main{padding-left:var(--bslib-sidebar-padding-icon)}.bslib-sidebar-layout:not([data-bslib-sidebar-open=always]).sidebar-right>.main{padding-right:var(--bslib-sidebar-padding-icon)}.bslib-sidebar-layout:not([data-bslib-sidebar-open=always])>.main{opacity:0;transition:opacity var(--bslib-sidebar-transition-easing-x) var(--bslib-sidebar-transition-duration)}.bslib-sidebar-layout:not([data-bslib-sidebar-open=always]).sidebar-collapsed>.main{opacity:1}}:root{--bslib-value-box-shadow: none;--bslib-value-box-border-width-auto-yes: var(--bslib-value-box-border-width-baseline);--bslib-value-box-border-width-auto-no: 0;--bslib-value-box-border-width-baseline: 1px}.bslib-value-box{border-width:var(--bslib-value-box-border-width-auto-no, var(--bslib-value-box-border-width-baseline));container-name:bslib-value-box;container-type:inline-size}.bslib-value-box.card{box-shadow:var(--bslib-value-box-shadow)}.bslib-value-box.border-auto{border-width:var(--bslib-value-box-border-width-auto-yes, var(--bslib-value-box-border-width-baseline))}.bslib-value-box.default{--bslib-value-box-bg-default: var(--bs-card-bg, #ffffff);--bslib-value-box-border-color-default: var(--bs-card-border-color, rgba(0, 0, 0, 0.175));color:var(--bslib-value-box-color);background-color:var(--bslib-value-box-bg, var(--bslib-value-box-bg-default));border-color:var(--bslib-value-box-border-color, var(--bslib-value-box-border-color-default))}.bslib-value-box .value-box-grid{display:grid;grid-template-areas:"left right";align-items:center;overflow:hidden}.bslib-value-box .value-box-showcase{height:100%;max-height:var(---bslib-value-box-showcase-max-h, 100%)}.bslib-value-box .value-box-showcase,.bslib-value-box .value-box-showcase>.html-fill-item{width:100%}.bslib-value-box[data-full-screen=true] .value-box-showcase{max-height:var(---bslib-value-box-showcase-max-h-fs, 100%)}@media screen and (min-width: 575.98px){@container bslib-value-box (max-width: 300px){.bslib-value-box:not(.showcase-bottom) .value-box-grid{grid-template-columns:1fr !important;grid-template-rows:auto auto;grid-template-areas:"top" "bottom"}.bslib-value-box:not(.showcase-bottom) .value-box-grid .value-box-showcase{grid-area:top !important}.bslib-value-box:not(.showcase-bottom) .value-box-grid .value-box-area{grid-area:bottom !important;justify-content:end}}}.bslib-value-box .value-box-area{justify-content:center;padding:1.5rem 1rem;font-size:.9rem;font-weight:500}.bslib-value-box .value-box-area *{margin-bottom:0;margin-top:0}.bslib-value-box .value-box-title{font-size:1rem;margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2}.bslib-value-box .value-box-title:empty::after{content:" "}.bslib-value-box .value-box-value{font-size:calc(1.29rem + 0.48vw);margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2}@media(min-width: 1200px){.bslib-value-box .value-box-value{font-size:1.65rem}}.bslib-value-box .value-box-value:empty::after{content:" "}.bslib-value-box .value-box-showcase{align-items:center;justify-content:center;margin-top:auto;margin-bottom:auto;padding:1rem}.bslib-value-box .value-box-showcase .bi,.bslib-value-box .value-box-showcase .fa,.bslib-value-box .value-box-showcase .fab,.bslib-value-box .value-box-showcase .fas,.bslib-value-box .value-box-showcase .far{opacity:.85;min-width:50px;max-width:125%}.bslib-value-box .value-box-showcase .bi,.bslib-value-box .value-box-showcase .fa,.bslib-value-box .value-box-showcase .fab,.bslib-value-box .value-box-showcase .fas,.bslib-value-box .value-box-showcase .far{font-size:4rem}.bslib-value-box.showcase-top-right .value-box-grid{grid-template-columns:1fr var(---bslib-value-box-showcase-w, 50%)}.bslib-value-box.showcase-top-right .value-box-grid .value-box-showcase{grid-area:right;margin-left:auto;align-self:start;align-items:end;padding-left:0;padding-bottom:0}.bslib-value-box.showcase-top-right .value-box-grid .value-box-area{grid-area:left;align-self:end}.bslib-value-box.showcase-top-right[data-full-screen=true] .value-box-grid{grid-template-columns:auto var(---bslib-value-box-showcase-w-fs, 1fr)}.bslib-value-box.showcase-top-right[data-full-screen=true] .value-box-grid>div{align-self:center}.bslib-value-box.showcase-top-right:not([data-full-screen=true]) .value-box-showcase{margin-top:0}@container bslib-value-box (max-width: 300px){.bslib-value-box.showcase-top-right:not([data-full-screen=true]) .value-box-grid .value-box-showcase{padding-left:1rem}}.bslib-value-box.showcase-left-center .value-box-grid{grid-template-columns:var(---bslib-value-box-showcase-w, 30%) auto}.bslib-value-box.showcase-left-center[data-full-screen=true] .value-box-grid{grid-template-columns:var(---bslib-value-box-showcase-w-fs, 1fr) auto}.bslib-value-box.showcase-left-center:not([data-fill-screen=true]) .value-box-grid .value-box-showcase{grid-area:left}.bslib-value-box.showcase-left-center:not([data-fill-screen=true]) .value-box-grid .value-box-area{grid-area:right}.bslib-value-box.showcase-bottom .value-box-grid{grid-template-columns:1fr;grid-template-rows:1fr var(---bslib-value-box-showcase-h, auto);grid-template-areas:"top" "bottom";overflow:hidden}.bslib-value-box.showcase-bottom .value-box-grid .value-box-showcase{grid-area:bottom;padding:0;margin:0}.bslib-value-box.showcase-bottom .value-box-grid .value-box-area{grid-area:top}.bslib-value-box.showcase-bottom[data-full-screen=true] .value-box-grid{grid-template-rows:1fr var(---bslib-value-box-showcase-h-fs, 2fr)}.bslib-value-box.showcase-bottom[data-full-screen=true] .value-box-grid .value-box-showcase{padding:1rem}[data-bs-theme=dark] .bslib-value-box{--bslib-value-box-shadow: 0 0.5rem 1rem rgb(0 0 0 / 50%)}.bslib-card{overflow:auto}.bslib-card .card-body+.card-body{padding-top:0}.bslib-card .card-body{overflow:auto}.bslib-card .card-body p{margin-top:0}.bslib-card .card-body p:last-child{margin-bottom:0}.bslib-card .card-body{max-height:var(--bslib-card-body-max-height, none)}.bslib-card[data-full-screen=true]>.card-body{max-height:var(--bslib-card-body-max-height-full-screen, none)}.bslib-card .card-header .form-group{margin-bottom:0}.bslib-card .card-header .selectize-control{margin-bottom:0}.bslib-card .card-header .selectize-control .item{margin-right:1.15rem}.bslib-card .card-footer{margin-top:auto}.bslib-card .bslib-navs-card-title{display:flex;flex-wrap:wrap;justify-content:space-between;align-items:center}.bslib-card .bslib-navs-card-title .nav{margin-left:auto}.bslib-card .bslib-sidebar-layout:not([data-bslib-sidebar-border=true]){border:none}.bslib-card .bslib-sidebar-layout:not([data-bslib-sidebar-border-radius=true]){border-top-left-radius:0;border-top-right-radius:0}[data-full-screen=true]{position:fixed;inset:3.5rem 1rem 1rem;height:auto !important;max-height:none !important;width:auto !important;z-index:1070}.bslib-full-screen-enter{display:none;position:absolute;bottom:var(--bslib-full-screen-enter-bottom, 0.2rem);right:var(--bslib-full-screen-enter-right, 0);top:var(--bslib-full-screen-enter-top);left:var(--bslib-full-screen-enter-left);color:var(--bslib-color-fg, var(--bs-card-color));background-color:var(--bslib-color-bg, var(--bs-card-bg, var(--bs-body-bg)));border:var(--bs-card-border-width) solid var(--bslib-color-fg, var(--bs-card-border-color));box-shadow:0 2px 4px rgba(0,0,0,.15);margin:.2rem .4rem;padding:.55rem !important;font-size:.8rem;cursor:pointer;opacity:.7;z-index:1070}.bslib-full-screen-enter:hover{opacity:1}.card[data-full-screen=false]:hover>*>.bslib-full-screen-enter{display:block}.bslib-has-full-screen .card:hover>*>.bslib-full-screen-enter{display:none}@media(max-width: 575.98px){.bslib-full-screen-enter{display:none !important}}.bslib-full-screen-exit{position:relative;top:1.35rem;font-size:.9rem;cursor:pointer;text-decoration:none;display:flex;float:right;margin-right:2.15rem;align-items:center;color:rgba(var(--bs-body-bg-rgb), 0.8)}.bslib-full-screen-exit:hover{color:rgba(var(--bs-body-bg-rgb), 1)}.bslib-full-screen-exit svg{margin-left:.5rem;font-size:1.5rem}#bslib-full-screen-overlay{position:fixed;inset:0;background-color:rgba(var(--bs-body-color-rgb), 0.6);backdrop-filter:blur(2px);-webkit-backdrop-filter:blur(2px);z-index:1069;animation:bslib-full-screen-overlay-enter 400ms cubic-bezier(0.6, 0.02, 0.65, 1) forwards}@keyframes bslib-full-screen-overlay-enter{0%{opacity:0}100%{opacity:1}}.navbar+.container-fluid:has(>.tab-content>.tab-pane.active.html-fill-container),.navbar+.container-sm:has(>.tab-content>.tab-pane.active.html-fill-container),.navbar+.container-md:has(>.tab-content>.tab-pane.active.html-fill-container),.navbar+.container-lg:has(>.tab-content>.tab-pane.active.html-fill-container),.navbar+.container-xl:has(>.tab-content>.tab-pane.active.html-fill-container),.navbar+.container-xxl:has(>.tab-content>.tab-pane.active.html-fill-container){padding-left:0;padding-right:0}.navbar+.container-fluid>.tab-content>.tab-pane.active.html-fill-container,.navbar+.container-sm>.tab-content>.tab-pane.active.html-fill-container,.navbar+.container-md>.tab-content>.tab-pane.active.html-fill-container,.navbar+.container-lg>.tab-content>.tab-pane.active.html-fill-container,.navbar+.container-xl>.tab-content>.tab-pane.active.html-fill-container,.navbar+.container-xxl>.tab-content>.tab-pane.active.html-fill-container{padding:var(--bslib-spacer, 1rem);gap:var(--bslib-spacer, 1rem)}.navbar+.container-fluid>.tab-content>.tab-pane.active.html-fill-container:has(>.bslib-sidebar-layout:only-child),.navbar+.container-sm>.tab-content>.tab-pane.active.html-fill-container:has(>.bslib-sidebar-layout:only-child),.navbar+.container-md>.tab-content>.tab-pane.active.html-fill-container:has(>.bslib-sidebar-layout:only-child),.navbar+.container-lg>.tab-content>.tab-pane.active.html-fill-container:has(>.bslib-sidebar-layout:only-child),.navbar+.container-xl>.tab-content>.tab-pane.active.html-fill-container:has(>.bslib-sidebar-layout:only-child),.navbar+.container-xxl>.tab-content>.tab-pane.active.html-fill-container:has(>.bslib-sidebar-layout:only-child){padding:0}.navbar+.container-fluid>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border=true]),.navbar+.container-sm>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border=true]),.navbar+.container-md>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border=true]),.navbar+.container-lg>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border=true]),.navbar+.container-xl>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border=true]),.navbar+.container-xxl>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border=true]){border-left:none;border-right:none;border-bottom:none}.navbar+.container-fluid>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border-radius=true]),.navbar+.container-sm>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border-radius=true]),.navbar+.container-md>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border-radius=true]),.navbar+.container-lg>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border-radius=true]),.navbar+.container-xl>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border-radius=true]),.navbar+.container-xxl>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border-radius=true]){border-radius:0}.navbar+div>.bslib-sidebar-layout{border-top:var(--bslib-sidebar-border)}:root{--bslib-page-sidebar-title-bg: #517699;--bslib-page-sidebar-title-color: #ffffff}.bslib-page-title{background-color:var(--bslib-page-sidebar-title-bg);color:var(--bslib-page-sidebar-title-color);font-size:1.25rem;font-weight:300;padding:var(--bslib-spacer, 1rem);padding-left:1.5rem;margin-bottom:0;border-bottom:1px solid #dee2e6}.html-fill-container{display:flex;flex-direction:column;min-height:0;min-width:0}.html-fill-container>.html-fill-item{flex:1 1 auto;min-height:0;min-width:0}.html-fill-container>:not(.html-fill-item){flex:0 0 auto}.tippy-box[data-theme~=quarto]{background-color:#fff;border:solid 1px #dee2e6;border-radius:.375rem;color:#212529;font-size:.875rem}.tippy-box[data-theme~=quarto]>.tippy-backdrop{background-color:#fff}.tippy-box[data-theme~=quarto]>.tippy-arrow:after,.tippy-box[data-theme~=quarto]>.tippy-svg-arrow:after{content:"";position:absolute;z-index:-1}.tippy-box[data-theme~=quarto]>.tippy-arrow:after{border-color:rgba(0,0,0,0);border-style:solid}.tippy-box[data-placement^=top]>.tippy-arrow:before{bottom:-6px}.tippy-box[data-placement^=bottom]>.tippy-arrow:before{top:-6px}.tippy-box[data-placement^=right]>.tippy-arrow:before{left:-6px}.tippy-box[data-placement^=left]>.tippy-arrow:before{right:-6px}.tippy-box[data-theme~=quarto][data-placement^=top]>.tippy-arrow:before{border-top-color:#fff}.tippy-box[data-theme~=quarto][data-placement^=top]>.tippy-arrow:after{border-top-color:#dee2e6;border-width:7px 7px 0;top:17px;left:1px}.tippy-box[data-theme~=quarto][data-placement^=top]>.tippy-svg-arrow>svg{top:16px}.tippy-box[data-theme~=quarto][data-placement^=top]>.tippy-svg-arrow:after{top:17px}.tippy-box[data-theme~=quarto][data-placement^=bottom]>.tippy-arrow:before{border-bottom-color:#fff;bottom:16px}.tippy-box[data-theme~=quarto][data-placement^=bottom]>.tippy-arrow:after{border-bottom-color:#dee2e6;border-width:0 7px 7px;bottom:17px;left:1px}.tippy-box[data-theme~=quarto][data-placement^=bottom]>.tippy-svg-arrow>svg{bottom:15px}.tippy-box[data-theme~=quarto][data-placement^=bottom]>.tippy-svg-arrow:after{bottom:17px}.tippy-box[data-theme~=quarto][data-placement^=left]>.tippy-arrow:before{border-left-color:#fff}.tippy-box[data-theme~=quarto][data-placement^=left]>.tippy-arrow:after{border-left-color:#dee2e6;border-width:7px 0 7px 7px;left:17px;top:1px}.tippy-box[data-theme~=quarto][data-placement^=left]>.tippy-svg-arrow>svg{left:11px}.tippy-box[data-theme~=quarto][data-placement^=left]>.tippy-svg-arrow:after{left:12px}.tippy-box[data-theme~=quarto][data-placement^=right]>.tippy-arrow:before{border-right-color:#fff;right:16px}.tippy-box[data-theme~=quarto][data-placement^=right]>.tippy-arrow:after{border-width:7px 7px 7px 0;right:17px;top:1px;border-right-color:#dee2e6}.tippy-box[data-theme~=quarto][data-placement^=right]>.tippy-svg-arrow>svg{right:11px}.tippy-box[data-theme~=quarto][data-placement^=right]>.tippy-svg-arrow:after{right:12px}.tippy-box[data-theme~=quarto]>.tippy-svg-arrow{fill:#212529}.tippy-box[data-theme~=quarto]>.tippy-svg-arrow:after{background-image:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iNiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMCA2czEuNzk2LS4wMTMgNC42Ny0zLjYxNUM1Ljg1MS45IDYuOTMuMDA2IDggMGMxLjA3LS4wMDYgMi4xNDguODg3IDMuMzQzIDIuMzg1QzE0LjIzMyA2LjAwNSAxNiA2IDE2IDZIMHoiIGZpbGw9InJnYmEoMCwgOCwgMTYsIDAuMikiLz48L3N2Zz4=);background-size:16px 6px;width:16px;height:6px}.top-right{position:absolute;top:1em;right:1em}.visually-hidden{border:0;clip:rect(0 0 0 0);height:auto;margin:0;overflow:hidden;padding:0;position:absolute;width:1px;white-space:nowrap}.hidden{display:none !important}.zindex-bottom{z-index:-1 !important}figure.figure{display:block}.quarto-layout-panel{margin-bottom:1em}.quarto-layout-panel>figure{width:100%}.quarto-layout-panel>figure>figcaption,.quarto-layout-panel>.panel-caption{margin-top:10pt}.quarto-layout-panel>.table-caption{margin-top:0px}.table-caption p{margin-bottom:.5em}.quarto-layout-row{display:flex;flex-direction:row;align-items:flex-start}.quarto-layout-valign-top{align-items:flex-start}.quarto-layout-valign-bottom{align-items:flex-end}.quarto-layout-valign-center{align-items:center}.quarto-layout-cell{position:relative;margin-right:20px}.quarto-layout-cell:last-child{margin-right:0}.quarto-layout-cell figure,.quarto-layout-cell>p{margin:.2em}.quarto-layout-cell img{max-width:100%}.quarto-layout-cell .html-widget{width:100% !important}.quarto-layout-cell div figure p{margin:0}.quarto-layout-cell figure{display:block;margin-inline-start:0;margin-inline-end:0}.quarto-layout-cell table{display:inline-table}.quarto-layout-cell-subref figcaption,figure .quarto-layout-row figure figcaption{text-align:center;font-style:italic}.quarto-figure{position:relative;margin-bottom:1em}.quarto-figure>figure{width:100%;margin-bottom:0}.quarto-figure-left>figure>p,.quarto-figure-left>figure>div{text-align:left}.quarto-figure-center>figure>p,.quarto-figure-center>figure>div{text-align:center}.quarto-figure-right>figure>p,.quarto-figure-right>figure>div{text-align:right}.quarto-figure>figure>div.cell-annotation,.quarto-figure>figure>div code{text-align:left}figure>p:empty{display:none}figure>p:first-child{margin-top:0;margin-bottom:0}figure>figcaption.quarto-float-caption-bottom{margin-bottom:.5em}figure>figcaption.quarto-float-caption-top{margin-top:.5em}div[id^=tbl-]{position:relative}.quarto-figure>.anchorjs-link{position:absolute;top:.6em;right:.5em}div[id^=tbl-]>.anchorjs-link{position:absolute;top:.7em;right:.3em}.quarto-figure:hover>.anchorjs-link,div[id^=tbl-]:hover>.anchorjs-link,h2:hover>.anchorjs-link,.h2:hover>.anchorjs-link,h3:hover>.anchorjs-link,.h3:hover>.anchorjs-link,h4:hover>.anchorjs-link,.h4:hover>.anchorjs-link,h5:hover>.anchorjs-link,.h5:hover>.anchorjs-link,h6:hover>.anchorjs-link,.h6:hover>.anchorjs-link,.reveal-anchorjs-link>.anchorjs-link{opacity:1}#title-block-header{margin-block-end:1rem;position:relative;margin-top:-1px}#title-block-header .abstract{margin-block-start:1rem}#title-block-header .abstract .abstract-title{font-weight:600}#title-block-header a{text-decoration:none}#title-block-header .author,#title-block-header .date,#title-block-header .doi{margin-block-end:.2rem}#title-block-header .quarto-title-block>div{display:flex}#title-block-header .quarto-title-block>div>h1,#title-block-header .quarto-title-block>div>.h1{flex-grow:1}#title-block-header .quarto-title-block>div>button{flex-shrink:0;height:2.25rem;margin-top:0}@media(min-width: 992px){#title-block-header .quarto-title-block>div>button{margin-top:5px}}tr.header>th>p:last-of-type{margin-bottom:0px}table,table.table{margin-top:.5rem;margin-bottom:.5rem}caption,.table-caption{padding-top:.5rem;padding-bottom:.5rem;text-align:center}figure.quarto-float-tbl figcaption.quarto-float-caption-top{margin-top:.5rem;margin-bottom:.25rem;text-align:center}figure.quarto-float-tbl figcaption.quarto-float-caption-bottom{padding-top:.25rem;margin-bottom:.5rem;text-align:center}.utterances{max-width:none;margin-left:-8px}iframe{margin-bottom:1em}details{margin-bottom:1em}details[show]{margin-bottom:0}details>summary{color:rgba(33,37,41,.75)}details>summary>p:only-child{display:inline}pre.sourceCode,code.sourceCode{position:relative}dd code:not(.sourceCode),p code:not(.sourceCode){white-space:pre-wrap}code{white-space:pre}@media print{code{white-space:pre-wrap}}pre>code{display:block}pre>code.sourceCode{white-space:pre}pre>code.sourceCode>span>a:first-child::before{text-decoration:none}pre.code-overflow-wrap>code.sourceCode{white-space:pre-wrap}pre.code-overflow-scroll>code.sourceCode{white-space:pre}code a:any-link{color:inherit;text-decoration:none}code a:hover{color:inherit;text-decoration:underline}ul.task-list{padding-left:1em}[data-tippy-root]{display:inline-block}.tippy-content .footnote-back{display:none}.footnote-back{margin-left:.2em}.tippy-content{overflow-x:auto}.quarto-embedded-source-code{display:none}.quarto-unresolved-ref{font-weight:600}.quarto-cover-image{max-width:35%;float:right;margin-left:30px}.cell-output-display .widget-subarea{margin-bottom:1em}.cell-output-display:not(.no-overflow-x),.knitsql-table:not(.no-overflow-x){overflow-x:auto}.panel-input{margin-bottom:1em}.panel-input>div,.panel-input>div>div{display:inline-block;vertical-align:top;padding-right:12px}.panel-input>p:last-child{margin-bottom:0}.layout-sidebar{margin-bottom:1em}.layout-sidebar .tab-content{border:none}.tab-content>.page-columns.active{display:grid}div.sourceCode>iframe{width:100%;height:300px;margin-bottom:-0.5em}a{text-underline-offset:3px}div.ansi-escaped-output{font-family:monospace;display:block}/*! -* -* ansi colors from IPython notebook's -* -* we also add `bright-[color]-` synonyms for the `-[color]-intense` classes since -* that seems to be what ansi_up emits -* -*/.ansi-black-fg{color:#3e424d}.ansi-black-bg{background-color:#3e424d}.ansi-black-intense-black,.ansi-bright-black-fg{color:#282c36}.ansi-black-intense-black,.ansi-bright-black-bg{background-color:#282c36}.ansi-red-fg{color:#e75c58}.ansi-red-bg{background-color:#e75c58}.ansi-red-intense-red,.ansi-bright-red-fg{color:#b22b31}.ansi-red-intense-red,.ansi-bright-red-bg{background-color:#b22b31}.ansi-green-fg{color:#00a250}.ansi-green-bg{background-color:#00a250}.ansi-green-intense-green,.ansi-bright-green-fg{color:#007427}.ansi-green-intense-green,.ansi-bright-green-bg{background-color:#007427}.ansi-yellow-fg{color:#ddb62b}.ansi-yellow-bg{background-color:#ddb62b}.ansi-yellow-intense-yellow,.ansi-bright-yellow-fg{color:#b27d12}.ansi-yellow-intense-yellow,.ansi-bright-yellow-bg{background-color:#b27d12}.ansi-blue-fg{color:#208ffb}.ansi-blue-bg{background-color:#208ffb}.ansi-blue-intense-blue,.ansi-bright-blue-fg{color:#0065ca}.ansi-blue-intense-blue,.ansi-bright-blue-bg{background-color:#0065ca}.ansi-magenta-fg{color:#d160c4}.ansi-magenta-bg{background-color:#d160c4}.ansi-magenta-intense-magenta,.ansi-bright-magenta-fg{color:#a03196}.ansi-magenta-intense-magenta,.ansi-bright-magenta-bg{background-color:#a03196}.ansi-cyan-fg{color:#60c6c8}.ansi-cyan-bg{background-color:#60c6c8}.ansi-cyan-intense-cyan,.ansi-bright-cyan-fg{color:#258f8f}.ansi-cyan-intense-cyan,.ansi-bright-cyan-bg{background-color:#258f8f}.ansi-white-fg{color:#c5c1b4}.ansi-white-bg{background-color:#c5c1b4}.ansi-white-intense-white,.ansi-bright-white-fg{color:#a1a6b2}.ansi-white-intense-white,.ansi-bright-white-bg{background-color:#a1a6b2}.ansi-default-inverse-fg{color:#fff}.ansi-default-inverse-bg{background-color:#000}.ansi-bold{font-weight:bold}.ansi-underline{text-decoration:underline}:root{--quarto-body-bg: #ffffff;--quarto-body-color: #212529;--quarto-text-muted: rgba(33, 37, 41, 0.75);--quarto-border-color: #dee2e6;--quarto-border-width: 1px;--quarto-border-radius: 0.375rem}table.gt_table{color:var(--quarto-body-color);font-size:1em;width:100%;background-color:rgba(0,0,0,0);border-top-width:inherit;border-bottom-width:inherit;border-color:var(--quarto-border-color)}table.gt_table th.gt_column_spanner_outer{color:var(--quarto-body-color);background-color:rgba(0,0,0,0);border-top-width:inherit;border-bottom-width:inherit;border-color:var(--quarto-border-color)}table.gt_table th.gt_col_heading{color:var(--quarto-body-color);font-weight:bold;background-color:rgba(0,0,0,0)}table.gt_table thead.gt_col_headings{border-bottom:1px solid currentColor;border-top-width:inherit;border-top-color:var(--quarto-border-color)}table.gt_table thead.gt_col_headings:not(:first-child){border-top-width:1px;border-top-color:var(--quarto-border-color)}table.gt_table td.gt_row{border-bottom-width:1px;border-bottom-color:var(--quarto-border-color);border-top-width:0px}table.gt_table tbody.gt_table_body{border-top-width:1px;border-bottom-width:1px;border-bottom-color:var(--quarto-border-color);border-top-color:currentColor}div.columns{display:initial;gap:initial}div.column{display:inline-block;overflow-x:initial;vertical-align:top;width:50%}.code-annotation-tip-content{word-wrap:break-word}.code-annotation-container-hidden{display:none !important}dl.code-annotation-container-grid{display:grid;grid-template-columns:min-content auto}dl.code-annotation-container-grid dt{grid-column:1}dl.code-annotation-container-grid dd{grid-column:2}pre.sourceCode.code-annotation-code{padding-right:0}code.sourceCode .code-annotation-anchor{z-index:100;position:relative;float:right;background-color:rgba(0,0,0,0)}input[type=checkbox]{margin-right:.5ch}:root{--mermaid-bg-color: #ffffff;--mermaid-edge-color: #6c757d;--mermaid-node-fg-color: #212529;--mermaid-fg-color: #212529;--mermaid-fg-color--lighter: #383f45;--mermaid-fg-color--lightest: #4e5862;--mermaid-font-family: system-ui, -apple-system, Segoe UI, Roboto, Helvetica Neue, Noto Sans, Liberation Sans, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol, Noto Color Emoji;--mermaid-label-bg-color: #ffffff;--mermaid-label-fg-color: #0d6efd;--mermaid-node-bg-color: rgba(13, 110, 253, 0.1);--mermaid-node-fg-color: #212529}@media print{:root{font-size:11pt}#quarto-sidebar,#TOC,.nav-page{display:none}.page-columns .content{grid-column-start:page-start}.fixed-top{position:relative}.panel-caption,.figure-caption,figcaption{color:#666}}.code-copy-button{position:absolute;top:0;right:0;border:0;margin-top:5px;margin-right:5px;background-color:rgba(0,0,0,0);z-index:3}.code-copy-button:focus{outline:none}.code-copy-button-tooltip{font-size:.75em}pre.sourceCode:hover>.code-copy-button>.bi::before{display:inline-block;height:1rem;width:1rem;content:"";vertical-align:-0.125em;background-image:url('data:image/svg+xml,');background-repeat:no-repeat;background-size:1rem 1rem}pre.sourceCode:hover>.code-copy-button-checked>.bi::before{background-image:url('data:image/svg+xml,')}pre.sourceCode:hover>.code-copy-button:hover>.bi::before{background-image:url('data:image/svg+xml,')}pre.sourceCode:hover>.code-copy-button-checked:hover>.bi::before{background-image:url('data:image/svg+xml,')}main ol ol,main ul ul,main ol ul,main ul ol{margin-bottom:1em}ul>li:not(:has(>p))>ul,ol>li:not(:has(>p))>ul,ul>li:not(:has(>p))>ol,ol>li:not(:has(>p))>ol{margin-bottom:0}ul>li:not(:has(>p))>ul>li:has(>p),ol>li:not(:has(>p))>ul>li:has(>p),ul>li:not(:has(>p))>ol>li:has(>p),ol>li:not(:has(>p))>ol>li:has(>p){margin-top:1rem}body{margin:0}main.page-columns>header>h1.title,main.page-columns>header>.title.h1{margin-bottom:0}@media(min-width: 992px){body .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset] 35px [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(500px, calc(850px - 3em)) [body-content-end] 1.5em [body-end] 35px [body-end-outset] minmax(75px, 145px) [page-end-inset] 35px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.fullcontent:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset] 35px [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(500px, calc(850px - 3em)) [body-content-end] 1.5em [body-end] 35px [body-end-outset] 35px [page-end-inset page-end] 5fr [screen-end-inset] 1.5em}body.slimcontent:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset] 35px [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(500px, calc(850px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(0px, 200px) [page-end-inset] 35px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.listing:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start] minmax(50px, 100px) [page-start-inset] 50px [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(500px, calc(850px - 3em)) [body-content-end] 3em [body-end] 50px [body-end-outset] minmax(0px, 250px) [page-end-inset] minmax(50px, 100px) [page-end] 1fr [screen-end-inset] 1.5em [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] 35px [page-start-inset] minmax(0px, 175px) [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(450px, calc(800px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(0px, 200px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] 35px [page-start-inset] minmax(0px, 175px) [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(450px, calc(800px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(0px, 200px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] minmax(25px, 50px) [page-start-inset] minmax(50px, 150px) [body-start-outset] minmax(25px, 50px) [body-start] 1.5em [body-content-start] minmax(500px, calc(800px - 3em)) [body-content-end] 1.5em [body-end] minmax(25px, 50px) [body-end-outset] minmax(50px, 150px) [page-end-inset] minmax(25px, 50px) [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start] minmax(50px, 100px) [page-start-inset] 50px [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(500px, calc(1000px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(50px, 100px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked.fullcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start] minmax(50px, 100px) [page-start-inset] 50px [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(500px, calc(1000px - 3em)) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating.fullcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] 50px [page-start-inset] minmax(50px, 150px) [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(500px, calc(800px - 3em)) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked.slimcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start] minmax(50px, 100px) [page-start-inset] 50px [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(450px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(0px, 200px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked.listing .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start] minmax(50px, 100px) [page-start-inset] 50px [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(500px, calc(1000px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(0px, 200px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating.slimcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] 50px [page-start-inset] minmax(50px, 150px) [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(450px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(50px, 150px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating.listing .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] minmax(25px, 50px) [page-start-inset] minmax(50px, 150px) [body-start-outset] minmax(25px, 50px) [body-start] 1.5em [body-content-start] minmax(500px, calc(800px - 3em)) [body-content-end] 1.5em [body-end] minmax(25px, 50px) [body-end-outset] minmax(50px, 150px) [page-end-inset] minmax(25px, 50px) [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}}@media(max-width: 991.98px){body .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset] 5fr [body-start] 1.5em [body-content-start] minmax(500px, calc(800px - 3em)) [body-content-end] 1.5em [body-end] 35px [body-end-outset] minmax(75px, 145px) [page-end-inset] 35px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.fullcontent:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset] 5fr [body-start] 1.5em [body-content-start] minmax(500px, calc(800px - 3em)) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.slimcontent:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset] 5fr [body-start] 1.5em [body-content-start] minmax(500px, calc(800px - 3em)) [body-content-end] 1.5em [body-end] 35px [body-end-outset] minmax(75px, 145px) [page-end-inset] 35px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.listing:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset] 5fr [body-start] 1.5em [body-content-start] minmax(500px, calc(1250px - 3em)) [body-content-end body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] 35px [page-start-inset] minmax(0px, 145px) [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(450px, calc(800px - 3em)) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] 35px [page-start-inset] minmax(0px, 145px) [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(450px, calc(800px - 3em)) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset body-start-outset body-start] 1.5em [body-content-start] minmax(500px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(75px, 150px) [page-end-inset] 25px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(500px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(25px, 50px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked.fullcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(500px, calc(1000px - 3em)) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating.fullcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset body-start-outset body-start] 1em [body-content-start] minmax(500px, calc(800px - 3em)) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 4fr [screen-end-inset] 1.5em [screen-end]}body.docked.slimcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(500px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(25px, 50px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked.listing .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(500px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(25px, 50px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating.slimcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset body-start-outset body-start] 1em [body-content-start] minmax(500px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 35px [body-end-outset] minmax(75px, 145px) [page-end-inset] 35px [page-end] 4fr [screen-end-inset] 1.5em [screen-end]}body.floating.listing .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset body-start-outset body-start] 1em [body-content-start] minmax(500px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(75px, 150px) [page-end-inset] 25px [page-end] 4fr [screen-end-inset] 1.5em [screen-end]}}@media(max-width: 767.98px){body .page-columns,body.fullcontent:not(.floating):not(.docked) .page-columns,body.slimcontent:not(.floating):not(.docked) .page-columns,body.docked .page-columns,body.docked.slimcontent .page-columns,body.docked.fullcontent .page-columns,body.floating .page-columns,body.floating.slimcontent .page-columns,body.floating.fullcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(0px, 1fr) [body-content-end body-end body-end-outset page-end-inset page-end screen-end-inset] 1.5em [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(0px, 1fr) [body-content-end body-end body-end-outset page-end-inset page-end screen-end-inset] 1.5em [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(0px, 1fr) [body-content-end body-end body-end-outset page-end-inset page-end screen-end-inset] 1.5em [screen-end]}nav[role=doc-toc]{display:none}}body,.page-row-navigation{grid-template-rows:[page-top] max-content [contents-top] max-content [contents-bottom] max-content [page-bottom]}.page-rows-contents{grid-template-rows:[content-top] minmax(max-content, 1fr) [content-bottom] minmax(60px, max-content) [page-bottom]}.page-full{grid-column:screen-start/screen-end !important}.page-columns>*{grid-column:body-content-start/body-content-end}.page-columns.column-page>*{grid-column:page-start/page-end}.page-columns.column-page-left .page-columns.page-full>*,.page-columns.column-page-left>*{grid-column:page-start/body-content-end}.page-columns.column-page-right .page-columns.page-full>*,.page-columns.column-page-right>*{grid-column:body-content-start/page-end}.page-rows{grid-auto-rows:auto}.header{grid-column:screen-start/screen-end;grid-row:page-top/contents-top}#quarto-content{padding:0;grid-column:screen-start/screen-end;grid-row:contents-top/contents-bottom}body.floating .sidebar.sidebar-navigation{grid-column:page-start/body-start;grid-row:content-top/page-bottom}body.docked .sidebar.sidebar-navigation{grid-column:screen-start/body-start;grid-row:content-top/page-bottom}.sidebar.toc-left{grid-column:page-start/body-start;grid-row:content-top/page-bottom}.sidebar.margin-sidebar{grid-column:body-end/page-end;grid-row:content-top/page-bottom}.page-columns .content{grid-column:body-content-start/body-content-end;grid-row:content-top/content-bottom;align-content:flex-start}.page-columns .page-navigation{grid-column:body-content-start/body-content-end;grid-row:content-bottom/page-bottom}.page-columns .footer{grid-column:screen-start/screen-end;grid-row:contents-bottom/page-bottom}.page-columns .column-body{grid-column:body-content-start/body-content-end}.page-columns .column-body-fullbleed{grid-column:body-start/body-end}.page-columns .column-body-outset{grid-column:body-start-outset/body-end-outset;z-index:998;opacity:.999}.page-columns .column-body-outset table{background:#fff}.page-columns .column-body-outset-left{grid-column:body-start-outset/body-content-end;z-index:998;opacity:.999}.page-columns .column-body-outset-left table{background:#fff}.page-columns .column-body-outset-right{grid-column:body-content-start/body-end-outset;z-index:998;opacity:.999}.page-columns .column-body-outset-right table{background:#fff}.page-columns .column-page{grid-column:page-start/page-end;z-index:998;opacity:.999}.page-columns .column-page table{background:#fff}.page-columns .column-page-inset{grid-column:page-start-inset/page-end-inset;z-index:998;opacity:.999}.page-columns .column-page-inset table{background:#fff}.page-columns .column-page-inset-left{grid-column:page-start-inset/body-content-end;z-index:998;opacity:.999}.page-columns .column-page-inset-left table{background:#fff}.page-columns .column-page-inset-right{grid-column:body-content-start/page-end-inset;z-index:998;opacity:.999}.page-columns .column-page-inset-right figcaption table{background:#fff}.page-columns .column-page-left{grid-column:page-start/body-content-end;z-index:998;opacity:.999}.page-columns .column-page-left table{background:#fff}.page-columns .column-page-right{grid-column:body-content-start/page-end;z-index:998;opacity:.999}.page-columns .column-page-right figcaption table{background:#fff}#quarto-content.page-columns #quarto-margin-sidebar,#quarto-content.page-columns #quarto-sidebar{z-index:1}@media(max-width: 991.98px){#quarto-content.page-columns #quarto-margin-sidebar.collapse,#quarto-content.page-columns #quarto-sidebar.collapse,#quarto-content.page-columns #quarto-margin-sidebar.collapsing,#quarto-content.page-columns #quarto-sidebar.collapsing{z-index:1055}}#quarto-content.page-columns main.column-page,#quarto-content.page-columns main.column-page-right,#quarto-content.page-columns main.column-page-left{z-index:0}.page-columns .column-screen-inset{grid-column:screen-start-inset/screen-end-inset;z-index:998;opacity:.999}.page-columns .column-screen-inset table{background:#fff}.page-columns .column-screen-inset-left{grid-column:screen-start-inset/body-content-end;z-index:998;opacity:.999}.page-columns .column-screen-inset-left table{background:#fff}.page-columns .column-screen-inset-right{grid-column:body-content-start/screen-end-inset;z-index:998;opacity:.999}.page-columns .column-screen-inset-right table{background:#fff}.page-columns .column-screen{grid-column:screen-start/screen-end;z-index:998;opacity:.999}.page-columns .column-screen table{background:#fff}.page-columns .column-screen-left{grid-column:screen-start/body-content-end;z-index:998;opacity:.999}.page-columns .column-screen-left table{background:#fff}.page-columns .column-screen-right{grid-column:body-content-start/screen-end;z-index:998;opacity:.999}.page-columns .column-screen-right table{background:#fff}.page-columns .column-screen-inset-shaded{grid-column:screen-start/screen-end;padding:1em;background:#f8f9fa;z-index:998;opacity:.999;margin-bottom:1em}.zindex-content{z-index:998;opacity:.999}.zindex-modal{z-index:1055;opacity:.999}.zindex-over-content{z-index:999;opacity:.999}img.img-fluid.column-screen,img.img-fluid.column-screen-inset-shaded,img.img-fluid.column-screen-inset,img.img-fluid.column-screen-inset-left,img.img-fluid.column-screen-inset-right,img.img-fluid.column-screen-left,img.img-fluid.column-screen-right{width:100%}@media(min-width: 992px){.margin-caption,div.aside,aside:not(.footnotes):not(.sidebar),.column-margin{grid-column:body-end/page-end !important;z-index:998}.column-sidebar{grid-column:page-start/body-start !important;z-index:998}.column-leftmargin{grid-column:screen-start-inset/body-start !important;z-index:998}.no-row-height{height:1em;overflow:visible}}@media(max-width: 991.98px){.margin-caption,div.aside,aside:not(.footnotes):not(.sidebar),.column-margin{grid-column:body-end/page-end !important;z-index:998}.no-row-height{height:1em;overflow:visible}.page-columns.page-full{overflow:visible}.page-columns.toc-left .margin-caption,.page-columns.toc-left div.aside,.page-columns.toc-left aside:not(.footnotes):not(.sidebar),.page-columns.toc-left .column-margin{grid-column:body-content-start/body-content-end !important;z-index:998;opacity:.999}.page-columns.toc-left .no-row-height{height:initial;overflow:initial}}@media(max-width: 767.98px){.margin-caption,div.aside,aside:not(.footnotes):not(.sidebar),.column-margin{grid-column:body-content-start/body-content-end !important;z-index:998;opacity:.999}.no-row-height{height:initial;overflow:initial}#quarto-margin-sidebar{display:none}#quarto-sidebar-toc-left{display:none}.hidden-sm{display:none}}.panel-grid{display:grid;grid-template-rows:repeat(1, 1fr);grid-template-columns:repeat(24, 1fr);gap:1em}.panel-grid .g-col-1{grid-column:auto/span 1}.panel-grid .g-col-2{grid-column:auto/span 2}.panel-grid .g-col-3{grid-column:auto/span 3}.panel-grid .g-col-4{grid-column:auto/span 4}.panel-grid .g-col-5{grid-column:auto/span 5}.panel-grid .g-col-6{grid-column:auto/span 6}.panel-grid .g-col-7{grid-column:auto/span 7}.panel-grid .g-col-8{grid-column:auto/span 8}.panel-grid .g-col-9{grid-column:auto/span 9}.panel-grid .g-col-10{grid-column:auto/span 10}.panel-grid .g-col-11{grid-column:auto/span 11}.panel-grid .g-col-12{grid-column:auto/span 12}.panel-grid .g-col-13{grid-column:auto/span 13}.panel-grid .g-col-14{grid-column:auto/span 14}.panel-grid .g-col-15{grid-column:auto/span 15}.panel-grid .g-col-16{grid-column:auto/span 16}.panel-grid .g-col-17{grid-column:auto/span 17}.panel-grid .g-col-18{grid-column:auto/span 18}.panel-grid .g-col-19{grid-column:auto/span 19}.panel-grid .g-col-20{grid-column:auto/span 20}.panel-grid .g-col-21{grid-column:auto/span 21}.panel-grid .g-col-22{grid-column:auto/span 22}.panel-grid .g-col-23{grid-column:auto/span 23}.panel-grid .g-col-24{grid-column:auto/span 24}.panel-grid .g-start-1{grid-column-start:1}.panel-grid .g-start-2{grid-column-start:2}.panel-grid .g-start-3{grid-column-start:3}.panel-grid .g-start-4{grid-column-start:4}.panel-grid .g-start-5{grid-column-start:5}.panel-grid .g-start-6{grid-column-start:6}.panel-grid .g-start-7{grid-column-start:7}.panel-grid .g-start-8{grid-column-start:8}.panel-grid .g-start-9{grid-column-start:9}.panel-grid .g-start-10{grid-column-start:10}.panel-grid .g-start-11{grid-column-start:11}.panel-grid .g-start-12{grid-column-start:12}.panel-grid .g-start-13{grid-column-start:13}.panel-grid .g-start-14{grid-column-start:14}.panel-grid .g-start-15{grid-column-start:15}.panel-grid .g-start-16{grid-column-start:16}.panel-grid .g-start-17{grid-column-start:17}.panel-grid .g-start-18{grid-column-start:18}.panel-grid .g-start-19{grid-column-start:19}.panel-grid .g-start-20{grid-column-start:20}.panel-grid .g-start-21{grid-column-start:21}.panel-grid .g-start-22{grid-column-start:22}.panel-grid .g-start-23{grid-column-start:23}@media(min-width: 576px){.panel-grid .g-col-sm-1{grid-column:auto/span 1}.panel-grid .g-col-sm-2{grid-column:auto/span 2}.panel-grid .g-col-sm-3{grid-column:auto/span 3}.panel-grid .g-col-sm-4{grid-column:auto/span 4}.panel-grid .g-col-sm-5{grid-column:auto/span 5}.panel-grid .g-col-sm-6{grid-column:auto/span 6}.panel-grid .g-col-sm-7{grid-column:auto/span 7}.panel-grid .g-col-sm-8{grid-column:auto/span 8}.panel-grid .g-col-sm-9{grid-column:auto/span 9}.panel-grid .g-col-sm-10{grid-column:auto/span 10}.panel-grid .g-col-sm-11{grid-column:auto/span 11}.panel-grid .g-col-sm-12{grid-column:auto/span 12}.panel-grid .g-col-sm-13{grid-column:auto/span 13}.panel-grid .g-col-sm-14{grid-column:auto/span 14}.panel-grid .g-col-sm-15{grid-column:auto/span 15}.panel-grid .g-col-sm-16{grid-column:auto/span 16}.panel-grid .g-col-sm-17{grid-column:auto/span 17}.panel-grid .g-col-sm-18{grid-column:auto/span 18}.panel-grid .g-col-sm-19{grid-column:auto/span 19}.panel-grid .g-col-sm-20{grid-column:auto/span 20}.panel-grid .g-col-sm-21{grid-column:auto/span 21}.panel-grid .g-col-sm-22{grid-column:auto/span 22}.panel-grid .g-col-sm-23{grid-column:auto/span 23}.panel-grid .g-col-sm-24{grid-column:auto/span 24}.panel-grid .g-start-sm-1{grid-column-start:1}.panel-grid .g-start-sm-2{grid-column-start:2}.panel-grid .g-start-sm-3{grid-column-start:3}.panel-grid .g-start-sm-4{grid-column-start:4}.panel-grid .g-start-sm-5{grid-column-start:5}.panel-grid .g-start-sm-6{grid-column-start:6}.panel-grid .g-start-sm-7{grid-column-start:7}.panel-grid .g-start-sm-8{grid-column-start:8}.panel-grid .g-start-sm-9{grid-column-start:9}.panel-grid .g-start-sm-10{grid-column-start:10}.panel-grid .g-start-sm-11{grid-column-start:11}.panel-grid .g-start-sm-12{grid-column-start:12}.panel-grid .g-start-sm-13{grid-column-start:13}.panel-grid .g-start-sm-14{grid-column-start:14}.panel-grid .g-start-sm-15{grid-column-start:15}.panel-grid .g-start-sm-16{grid-column-start:16}.panel-grid .g-start-sm-17{grid-column-start:17}.panel-grid .g-start-sm-18{grid-column-start:18}.panel-grid .g-start-sm-19{grid-column-start:19}.panel-grid .g-start-sm-20{grid-column-start:20}.panel-grid .g-start-sm-21{grid-column-start:21}.panel-grid .g-start-sm-22{grid-column-start:22}.panel-grid .g-start-sm-23{grid-column-start:23}}@media(min-width: 768px){.panel-grid .g-col-md-1{grid-column:auto/span 1}.panel-grid .g-col-md-2{grid-column:auto/span 2}.panel-grid .g-col-md-3{grid-column:auto/span 3}.panel-grid .g-col-md-4{grid-column:auto/span 4}.panel-grid .g-col-md-5{grid-column:auto/span 5}.panel-grid .g-col-md-6{grid-column:auto/span 6}.panel-grid .g-col-md-7{grid-column:auto/span 7}.panel-grid .g-col-md-8{grid-column:auto/span 8}.panel-grid .g-col-md-9{grid-column:auto/span 9}.panel-grid .g-col-md-10{grid-column:auto/span 10}.panel-grid .g-col-md-11{grid-column:auto/span 11}.panel-grid .g-col-md-12{grid-column:auto/span 12}.panel-grid .g-col-md-13{grid-column:auto/span 13}.panel-grid .g-col-md-14{grid-column:auto/span 14}.panel-grid .g-col-md-15{grid-column:auto/span 15}.panel-grid .g-col-md-16{grid-column:auto/span 16}.panel-grid .g-col-md-17{grid-column:auto/span 17}.panel-grid .g-col-md-18{grid-column:auto/span 18}.panel-grid .g-col-md-19{grid-column:auto/span 19}.panel-grid .g-col-md-20{grid-column:auto/span 20}.panel-grid .g-col-md-21{grid-column:auto/span 21}.panel-grid .g-col-md-22{grid-column:auto/span 22}.panel-grid .g-col-md-23{grid-column:auto/span 23}.panel-grid .g-col-md-24{grid-column:auto/span 24}.panel-grid .g-start-md-1{grid-column-start:1}.panel-grid .g-start-md-2{grid-column-start:2}.panel-grid .g-start-md-3{grid-column-start:3}.panel-grid .g-start-md-4{grid-column-start:4}.panel-grid .g-start-md-5{grid-column-start:5}.panel-grid .g-start-md-6{grid-column-start:6}.panel-grid .g-start-md-7{grid-column-start:7}.panel-grid .g-start-md-8{grid-column-start:8}.panel-grid .g-start-md-9{grid-column-start:9}.panel-grid .g-start-md-10{grid-column-start:10}.panel-grid .g-start-md-11{grid-column-start:11}.panel-grid .g-start-md-12{grid-column-start:12}.panel-grid .g-start-md-13{grid-column-start:13}.panel-grid .g-start-md-14{grid-column-start:14}.panel-grid .g-start-md-15{grid-column-start:15}.panel-grid .g-start-md-16{grid-column-start:16}.panel-grid .g-start-md-17{grid-column-start:17}.panel-grid .g-start-md-18{grid-column-start:18}.panel-grid .g-start-md-19{grid-column-start:19}.panel-grid .g-start-md-20{grid-column-start:20}.panel-grid .g-start-md-21{grid-column-start:21}.panel-grid .g-start-md-22{grid-column-start:22}.panel-grid .g-start-md-23{grid-column-start:23}}@media(min-width: 992px){.panel-grid .g-col-lg-1{grid-column:auto/span 1}.panel-grid .g-col-lg-2{grid-column:auto/span 2}.panel-grid .g-col-lg-3{grid-column:auto/span 3}.panel-grid .g-col-lg-4{grid-column:auto/span 4}.panel-grid .g-col-lg-5{grid-column:auto/span 5}.panel-grid .g-col-lg-6{grid-column:auto/span 6}.panel-grid .g-col-lg-7{grid-column:auto/span 7}.panel-grid .g-col-lg-8{grid-column:auto/span 8}.panel-grid .g-col-lg-9{grid-column:auto/span 9}.panel-grid .g-col-lg-10{grid-column:auto/span 10}.panel-grid .g-col-lg-11{grid-column:auto/span 11}.panel-grid .g-col-lg-12{grid-column:auto/span 12}.panel-grid .g-col-lg-13{grid-column:auto/span 13}.panel-grid .g-col-lg-14{grid-column:auto/span 14}.panel-grid .g-col-lg-15{grid-column:auto/span 15}.panel-grid .g-col-lg-16{grid-column:auto/span 16}.panel-grid .g-col-lg-17{grid-column:auto/span 17}.panel-grid .g-col-lg-18{grid-column:auto/span 18}.panel-grid .g-col-lg-19{grid-column:auto/span 19}.panel-grid .g-col-lg-20{grid-column:auto/span 20}.panel-grid .g-col-lg-21{grid-column:auto/span 21}.panel-grid .g-col-lg-22{grid-column:auto/span 22}.panel-grid .g-col-lg-23{grid-column:auto/span 23}.panel-grid .g-col-lg-24{grid-column:auto/span 24}.panel-grid .g-start-lg-1{grid-column-start:1}.panel-grid .g-start-lg-2{grid-column-start:2}.panel-grid .g-start-lg-3{grid-column-start:3}.panel-grid .g-start-lg-4{grid-column-start:4}.panel-grid .g-start-lg-5{grid-column-start:5}.panel-grid .g-start-lg-6{grid-column-start:6}.panel-grid .g-start-lg-7{grid-column-start:7}.panel-grid .g-start-lg-8{grid-column-start:8}.panel-grid .g-start-lg-9{grid-column-start:9}.panel-grid .g-start-lg-10{grid-column-start:10}.panel-grid .g-start-lg-11{grid-column-start:11}.panel-grid .g-start-lg-12{grid-column-start:12}.panel-grid .g-start-lg-13{grid-column-start:13}.panel-grid .g-start-lg-14{grid-column-start:14}.panel-grid .g-start-lg-15{grid-column-start:15}.panel-grid .g-start-lg-16{grid-column-start:16}.panel-grid .g-start-lg-17{grid-column-start:17}.panel-grid .g-start-lg-18{grid-column-start:18}.panel-grid .g-start-lg-19{grid-column-start:19}.panel-grid .g-start-lg-20{grid-column-start:20}.panel-grid .g-start-lg-21{grid-column-start:21}.panel-grid .g-start-lg-22{grid-column-start:22}.panel-grid .g-start-lg-23{grid-column-start:23}}@media(min-width: 1200px){.panel-grid .g-col-xl-1{grid-column:auto/span 1}.panel-grid .g-col-xl-2{grid-column:auto/span 2}.panel-grid .g-col-xl-3{grid-column:auto/span 3}.panel-grid .g-col-xl-4{grid-column:auto/span 4}.panel-grid .g-col-xl-5{grid-column:auto/span 5}.panel-grid .g-col-xl-6{grid-column:auto/span 6}.panel-grid .g-col-xl-7{grid-column:auto/span 7}.panel-grid .g-col-xl-8{grid-column:auto/span 8}.panel-grid .g-col-xl-9{grid-column:auto/span 9}.panel-grid .g-col-xl-10{grid-column:auto/span 10}.panel-grid .g-col-xl-11{grid-column:auto/span 11}.panel-grid .g-col-xl-12{grid-column:auto/span 12}.panel-grid .g-col-xl-13{grid-column:auto/span 13}.panel-grid .g-col-xl-14{grid-column:auto/span 14}.panel-grid .g-col-xl-15{grid-column:auto/span 15}.panel-grid .g-col-xl-16{grid-column:auto/span 16}.panel-grid .g-col-xl-17{grid-column:auto/span 17}.panel-grid .g-col-xl-18{grid-column:auto/span 18}.panel-grid .g-col-xl-19{grid-column:auto/span 19}.panel-grid .g-col-xl-20{grid-column:auto/span 20}.panel-grid .g-col-xl-21{grid-column:auto/span 21}.panel-grid .g-col-xl-22{grid-column:auto/span 22}.panel-grid .g-col-xl-23{grid-column:auto/span 23}.panel-grid .g-col-xl-24{grid-column:auto/span 24}.panel-grid .g-start-xl-1{grid-column-start:1}.panel-grid .g-start-xl-2{grid-column-start:2}.panel-grid .g-start-xl-3{grid-column-start:3}.panel-grid .g-start-xl-4{grid-column-start:4}.panel-grid .g-start-xl-5{grid-column-start:5}.panel-grid .g-start-xl-6{grid-column-start:6}.panel-grid .g-start-xl-7{grid-column-start:7}.panel-grid .g-start-xl-8{grid-column-start:8}.panel-grid .g-start-xl-9{grid-column-start:9}.panel-grid .g-start-xl-10{grid-column-start:10}.panel-grid .g-start-xl-11{grid-column-start:11}.panel-grid .g-start-xl-12{grid-column-start:12}.panel-grid .g-start-xl-13{grid-column-start:13}.panel-grid .g-start-xl-14{grid-column-start:14}.panel-grid .g-start-xl-15{grid-column-start:15}.panel-grid .g-start-xl-16{grid-column-start:16}.panel-grid .g-start-xl-17{grid-column-start:17}.panel-grid .g-start-xl-18{grid-column-start:18}.panel-grid .g-start-xl-19{grid-column-start:19}.panel-grid .g-start-xl-20{grid-column-start:20}.panel-grid .g-start-xl-21{grid-column-start:21}.panel-grid .g-start-xl-22{grid-column-start:22}.panel-grid .g-start-xl-23{grid-column-start:23}}@media(min-width: 1400px){.panel-grid .g-col-xxl-1{grid-column:auto/span 1}.panel-grid .g-col-xxl-2{grid-column:auto/span 2}.panel-grid .g-col-xxl-3{grid-column:auto/span 3}.panel-grid .g-col-xxl-4{grid-column:auto/span 4}.panel-grid .g-col-xxl-5{grid-column:auto/span 5}.panel-grid .g-col-xxl-6{grid-column:auto/span 6}.panel-grid .g-col-xxl-7{grid-column:auto/span 7}.panel-grid .g-col-xxl-8{grid-column:auto/span 8}.panel-grid .g-col-xxl-9{grid-column:auto/span 9}.panel-grid .g-col-xxl-10{grid-column:auto/span 10}.panel-grid .g-col-xxl-11{grid-column:auto/span 11}.panel-grid .g-col-xxl-12{grid-column:auto/span 12}.panel-grid .g-col-xxl-13{grid-column:auto/span 13}.panel-grid .g-col-xxl-14{grid-column:auto/span 14}.panel-grid .g-col-xxl-15{grid-column:auto/span 15}.panel-grid .g-col-xxl-16{grid-column:auto/span 16}.panel-grid .g-col-xxl-17{grid-column:auto/span 17}.panel-grid .g-col-xxl-18{grid-column:auto/span 18}.panel-grid .g-col-xxl-19{grid-column:auto/span 19}.panel-grid .g-col-xxl-20{grid-column:auto/span 20}.panel-grid .g-col-xxl-21{grid-column:auto/span 21}.panel-grid .g-col-xxl-22{grid-column:auto/span 22}.panel-grid .g-col-xxl-23{grid-column:auto/span 23}.panel-grid .g-col-xxl-24{grid-column:auto/span 24}.panel-grid .g-start-xxl-1{grid-column-start:1}.panel-grid .g-start-xxl-2{grid-column-start:2}.panel-grid .g-start-xxl-3{grid-column-start:3}.panel-grid .g-start-xxl-4{grid-column-start:4}.panel-grid .g-start-xxl-5{grid-column-start:5}.panel-grid .g-start-xxl-6{grid-column-start:6}.panel-grid .g-start-xxl-7{grid-column-start:7}.panel-grid .g-start-xxl-8{grid-column-start:8}.panel-grid .g-start-xxl-9{grid-column-start:9}.panel-grid .g-start-xxl-10{grid-column-start:10}.panel-grid .g-start-xxl-11{grid-column-start:11}.panel-grid .g-start-xxl-12{grid-column-start:12}.panel-grid .g-start-xxl-13{grid-column-start:13}.panel-grid .g-start-xxl-14{grid-column-start:14}.panel-grid .g-start-xxl-15{grid-column-start:15}.panel-grid .g-start-xxl-16{grid-column-start:16}.panel-grid .g-start-xxl-17{grid-column-start:17}.panel-grid .g-start-xxl-18{grid-column-start:18}.panel-grid .g-start-xxl-19{grid-column-start:19}.panel-grid .g-start-xxl-20{grid-column-start:20}.panel-grid .g-start-xxl-21{grid-column-start:21}.panel-grid .g-start-xxl-22{grid-column-start:22}.panel-grid .g-start-xxl-23{grid-column-start:23}}main{margin-top:1em;margin-bottom:1em}h1,.h1,h2,.h2{color:inherit;margin-top:2rem;margin-bottom:1rem;font-weight:600}h1.title,.title.h1{margin-top:0}main.content>section:first-of-type>h2:first-child,main.content>section:first-of-type>.h2:first-child{margin-top:0}h2,.h2{border-bottom:1px solid #dee2e6;padding-bottom:.5rem}h3,.h3{font-weight:600}h3,.h3,h4,.h4{opacity:.9;margin-top:1.5rem}h5,.h5,h6,.h6{opacity:.9}.header-section-number{color:#5a6570}.nav-link.active .header-section-number{color:inherit}mark,.mark{padding:0em}.panel-caption,.figure-caption,.subfigure-caption,.table-caption,figcaption,caption{font-size:.9rem;color:#5a6570}.quarto-layout-cell[data-ref-parent] caption{color:#5a6570}.column-margin figcaption,.margin-caption,div.aside,aside,.column-margin{color:#5a6570;font-size:.825rem}.panel-caption.margin-caption{text-align:inherit}.column-margin.column-container p{margin-bottom:0}.column-margin.column-container>*:not(.collapse):first-child{padding-bottom:.5em;display:block}.column-margin.column-container>*:not(.collapse):not(:first-child){padding-top:.5em;padding-bottom:.5em;display:block}.column-margin.column-container>*.collapse:not(.show){display:none}@media(min-width: 768px){.column-margin.column-container .callout-margin-content:first-child{margin-top:4.5em}.column-margin.column-container .callout-margin-content-simple:first-child{margin-top:3.5em}}.margin-caption>*{padding-top:.5em;padding-bottom:.5em}@media(max-width: 767.98px){.quarto-layout-row{flex-direction:column}}.nav-tabs .nav-item{margin-top:1px;cursor:pointer}.tab-content{margin-top:0px;border-left:#dee2e6 1px solid;border-right:#dee2e6 1px solid;border-bottom:#dee2e6 1px solid;margin-left:0;padding:1em;margin-bottom:1em}@media(max-width: 767.98px){.layout-sidebar{margin-left:0;margin-right:0}}.panel-sidebar,.panel-sidebar .form-control,.panel-input,.panel-input .form-control,.selectize-dropdown{font-size:.9rem}.panel-sidebar .form-control,.panel-input .form-control{padding-top:.1rem}.tab-pane div.sourceCode{margin-top:0px}.tab-pane>p{padding-top:0}.tab-pane>p:nth-child(1){padding-top:0}.tab-pane>p:last-child{margin-bottom:0}.tab-pane>pre:last-child{margin-bottom:0}.tab-content>.tab-pane:not(.active){display:none !important}div.sourceCode{background-color:rgba(233,236,239,.65);border:1px solid rgba(233,236,239,.65);border-radius:.375rem}pre.sourceCode{background-color:rgba(0,0,0,0)}pre.sourceCode{border:none;font-size:.875em;overflow:visible !important;padding:.4em}.callout pre.sourceCode{padding-left:0}div.sourceCode{overflow-y:hidden}.callout div.sourceCode{margin-left:initial}.blockquote{font-size:inherit;padding-left:1rem;padding-right:1.5rem;color:#5a6570}.blockquote h1:first-child,.blockquote .h1:first-child,.blockquote h2:first-child,.blockquote .h2:first-child,.blockquote h3:first-child,.blockquote .h3:first-child,.blockquote h4:first-child,.blockquote .h4:first-child,.blockquote h5:first-child,.blockquote .h5:first-child{margin-top:0}pre{background-color:initial;padding:initial;border:initial}p pre code:not(.sourceCode),li pre code:not(.sourceCode),pre code:not(.sourceCode){background-color:initial}p code:not(.sourceCode),li code:not(.sourceCode),td code:not(.sourceCode){background-color:#f8f9fa;padding:.2em}nav p code:not(.sourceCode),nav li code:not(.sourceCode),nav td code:not(.sourceCode){background-color:rgba(0,0,0,0);padding:0}td code:not(.sourceCode){white-space:pre-wrap}#quarto-embedded-source-code-modal>.modal-dialog{max-width:1000px;padding-left:1.75rem;padding-right:1.75rem}#quarto-embedded-source-code-modal>.modal-dialog>.modal-content>.modal-body{padding:0}#quarto-embedded-source-code-modal>.modal-dialog>.modal-content>.modal-body div.sourceCode{margin:0;padding:.2rem .2rem;border-radius:0px;border:none}#quarto-embedded-source-code-modal>.modal-dialog>.modal-content>.modal-header{padding:.7rem}.code-tools-button{font-size:1rem;padding:.15rem .15rem;margin-left:5px;color:rgba(33,37,41,.75);background-color:rgba(0,0,0,0);transition:initial;cursor:pointer}.code-tools-button>.bi::before{display:inline-block;height:1rem;width:1rem;content:"";vertical-align:-0.125em;background-image:url('data:image/svg+xml,');background-repeat:no-repeat;background-size:1rem 1rem}.code-tools-button:hover>.bi::before{background-image:url('data:image/svg+xml,')}#quarto-embedded-source-code-modal .code-copy-button>.bi::before{background-image:url('data:image/svg+xml,')}#quarto-embedded-source-code-modal .code-copy-button-checked>.bi::before{background-image:url('data:image/svg+xml,')}.sidebar{will-change:top;transition:top 200ms linear;position:sticky;overflow-y:auto;padding-top:1.2em;max-height:100vh}.sidebar.toc-left,.sidebar.margin-sidebar{top:0px;padding-top:1em}.sidebar.quarto-banner-title-block-sidebar>*{padding-top:1.65em}figure .quarto-notebook-link{margin-top:.5em}.quarto-notebook-link{font-size:.75em;color:rgba(33,37,41,.75);margin-bottom:1em;text-decoration:none;display:block}.quarto-notebook-link:hover{text-decoration:underline;color:#0d6efd}.quarto-notebook-link::before{display:inline-block;height:.75rem;width:.75rem;margin-bottom:0em;margin-right:.25em;content:"";vertical-align:-0.125em;background-image:url('data:image/svg+xml,');background-repeat:no-repeat;background-size:.75rem .75rem}.toc-actions i.bi,.quarto-code-links i.bi,.quarto-other-links i.bi,.quarto-alternate-notebooks i.bi,.quarto-alternate-formats i.bi{margin-right:.4em;font-size:.8rem}.quarto-other-links-text-target .quarto-code-links i.bi,.quarto-other-links-text-target .quarto-other-links i.bi{margin-right:.2em}.quarto-other-formats-text-target .quarto-alternate-formats i.bi{margin-right:.1em}.toc-actions i.bi.empty,.quarto-code-links i.bi.empty,.quarto-other-links i.bi.empty,.quarto-alternate-notebooks i.bi.empty,.quarto-alternate-formats i.bi.empty{padding-left:1em}.quarto-notebook h2,.quarto-notebook .h2{border-bottom:none}.quarto-notebook .cell-container{display:flex}.quarto-notebook .cell-container .cell{flex-grow:4}.quarto-notebook .cell-container .cell-decorator{padding-top:1.5em;padding-right:1em;text-align:right}.quarto-notebook .cell-container.code-fold .cell-decorator{padding-top:3em}.quarto-notebook .cell-code code{white-space:pre-wrap}.quarto-notebook .cell .cell-output-stderr pre code,.quarto-notebook .cell .cell-output-stdout pre code{white-space:pre-wrap;overflow-wrap:anywhere}.toc-actions,.quarto-alternate-formats,.quarto-other-links,.quarto-code-links,.quarto-alternate-notebooks{padding-left:0em}.sidebar .toc-actions a,.sidebar .quarto-alternate-formats a,.sidebar .quarto-other-links a,.sidebar .quarto-code-links a,.sidebar .quarto-alternate-notebooks a,.sidebar nav[role=doc-toc] a{text-decoration:none}.sidebar .toc-actions a:hover,.sidebar .quarto-other-links a:hover,.sidebar .quarto-code-links a:hover,.sidebar .quarto-alternate-formats a:hover,.sidebar .quarto-alternate-notebooks a:hover{color:#0d6efd}.sidebar .toc-actions h2,.sidebar .toc-actions .h2,.sidebar .quarto-code-links h2,.sidebar .quarto-code-links .h2,.sidebar .quarto-other-links h2,.sidebar .quarto-other-links .h2,.sidebar .quarto-alternate-notebooks h2,.sidebar .quarto-alternate-notebooks .h2,.sidebar .quarto-alternate-formats h2,.sidebar .quarto-alternate-formats .h2,.sidebar nav[role=doc-toc]>h2,.sidebar nav[role=doc-toc]>.h2{font-weight:500;margin-bottom:.2rem;margin-top:.3rem;font-family:inherit;border-bottom:0;padding-bottom:0;padding-top:0px}.sidebar .toc-actions>h2,.sidebar .toc-actions>.h2,.sidebar .quarto-code-links>h2,.sidebar .quarto-code-links>.h2,.sidebar .quarto-other-links>h2,.sidebar .quarto-other-links>.h2,.sidebar .quarto-alternate-notebooks>h2,.sidebar .quarto-alternate-notebooks>.h2,.sidebar .quarto-alternate-formats>h2,.sidebar .quarto-alternate-formats>.h2{font-size:.8rem}.sidebar nav[role=doc-toc]>h2,.sidebar nav[role=doc-toc]>.h2{font-size:.875rem}.sidebar nav[role=doc-toc]>ul a{border-left:1px solid #e9ecef;padding-left:.6rem}.sidebar .toc-actions h2>ul a,.sidebar .toc-actions .h2>ul a,.sidebar .quarto-code-links h2>ul a,.sidebar .quarto-code-links .h2>ul a,.sidebar .quarto-other-links h2>ul a,.sidebar .quarto-other-links .h2>ul a,.sidebar .quarto-alternate-notebooks h2>ul a,.sidebar .quarto-alternate-notebooks .h2>ul a,.sidebar .quarto-alternate-formats h2>ul a,.sidebar .quarto-alternate-formats .h2>ul a{border-left:none;padding-left:.6rem}.sidebar .toc-actions ul a:empty,.sidebar .quarto-code-links ul a:empty,.sidebar .quarto-other-links ul a:empty,.sidebar .quarto-alternate-notebooks ul a:empty,.sidebar .quarto-alternate-formats ul a:empty,.sidebar nav[role=doc-toc]>ul a:empty{display:none}.sidebar .toc-actions ul,.sidebar .quarto-code-links ul,.sidebar .quarto-other-links ul,.sidebar .quarto-alternate-notebooks ul,.sidebar .quarto-alternate-formats ul{padding-left:0;list-style:none}.sidebar nav[role=doc-toc] ul{list-style:none;padding-left:0;list-style:none}.sidebar nav[role=doc-toc]>ul{margin-left:.45em}.quarto-margin-sidebar nav[role=doc-toc]{padding-left:.5em}.sidebar .toc-actions>ul,.sidebar .quarto-code-links>ul,.sidebar .quarto-other-links>ul,.sidebar .quarto-alternate-notebooks>ul,.sidebar .quarto-alternate-formats>ul{font-size:.8rem}.sidebar nav[role=doc-toc]>ul{font-size:.875rem}.sidebar .toc-actions ul li a,.sidebar .quarto-code-links ul li a,.sidebar .quarto-other-links ul li a,.sidebar .quarto-alternate-notebooks ul li a,.sidebar .quarto-alternate-formats ul li a,.sidebar nav[role=doc-toc]>ul li a{line-height:1.1rem;padding-bottom:.2rem;padding-top:.2rem;color:inherit}.sidebar nav[role=doc-toc] ul>li>ul>li>a{padding-left:1.2em}.sidebar nav[role=doc-toc] ul>li>ul>li>ul>li>a{padding-left:2.4em}.sidebar nav[role=doc-toc] ul>li>ul>li>ul>li>ul>li>a{padding-left:3.6em}.sidebar nav[role=doc-toc] ul>li>ul>li>ul>li>ul>li>ul>li>a{padding-left:4.8em}.sidebar nav[role=doc-toc] ul>li>ul>li>ul>li>ul>li>ul>li>ul>li>a{padding-left:6em}.sidebar nav[role=doc-toc] ul>li>a.active,.sidebar nav[role=doc-toc] ul>li>ul>li>a.active{border-left:1px solid #0d6efd;color:#0d6efd !important}.sidebar nav[role=doc-toc] ul>li>a:hover,.sidebar nav[role=doc-toc] ul>li>ul>li>a:hover{color:#0d6efd !important}kbd,.kbd{color:#212529;background-color:#f8f9fa;border:1px solid;border-radius:5px;border-color:#dee2e6}.quarto-appendix-contents div.hanging-indent{margin-left:0em}.quarto-appendix-contents div.hanging-indent div.csl-entry{margin-left:1em;text-indent:-1em}.citation a,.footnote-ref{text-decoration:none}.footnotes ol{padding-left:1em}.tippy-content>*{margin-bottom:.7em}.tippy-content>*:last-child{margin-bottom:0}.callout{margin-top:1.25rem;margin-bottom:1.25rem;border-radius:.375rem;overflow-wrap:break-word}.callout .callout-title-container{overflow-wrap:anywhere}.callout.callout-style-simple{padding:.4em .7em;border-left:5px solid;border-right:1px solid #dee2e6;border-top:1px solid #dee2e6;border-bottom:1px solid #dee2e6}.callout.callout-style-default{border-left:5px solid;border-right:1px solid #dee2e6;border-top:1px solid #dee2e6;border-bottom:1px solid #dee2e6}.callout .callout-body-container{flex-grow:1}.callout.callout-style-simple .callout-body{font-size:.9rem;font-weight:400}.callout.callout-style-default .callout-body{font-size:.9rem;font-weight:400}.callout:not(.no-icon).callout-titled.callout-style-simple .callout-body{padding-left:1.6em}.callout.callout-titled>.callout-header{padding-top:.2em;margin-bottom:-0.2em}.callout.callout-style-simple>div.callout-header{border-bottom:none;font-size:.9rem;font-weight:600;opacity:75%}.callout.callout-style-default>div.callout-header{border-bottom:none;font-weight:600;opacity:85%;font-size:.9rem;padding-left:.5em;padding-right:.5em}.callout.callout-style-default .callout-body{padding-left:.5em;padding-right:.5em}.callout.callout-style-default .callout-body>:first-child{padding-top:.5rem;margin-top:0}.callout>div.callout-header[data-bs-toggle=collapse]{cursor:pointer}.callout.callout-style-default .callout-header[aria-expanded=false],.callout.callout-style-default .callout-header[aria-expanded=true]{padding-top:0px;margin-bottom:0px;align-items:center}.callout.callout-titled .callout-body>:last-child:not(.sourceCode),.callout.callout-titled .callout-body>div>:last-child:not(.sourceCode){padding-bottom:.5rem;margin-bottom:0}.callout:not(.callout-titled) .callout-body>:first-child,.callout:not(.callout-titled) .callout-body>div>:first-child{margin-top:.25rem}.callout:not(.callout-titled) .callout-body>:last-child,.callout:not(.callout-titled) .callout-body>div>:last-child{margin-bottom:.2rem}.callout.callout-style-simple .callout-icon::before,.callout.callout-style-simple .callout-toggle::before{height:1rem;width:1rem;display:inline-block;content:"";background-repeat:no-repeat;background-size:1rem 1rem}.callout.callout-style-default .callout-icon::before,.callout.callout-style-default .callout-toggle::before{height:.9rem;width:.9rem;display:inline-block;content:"";background-repeat:no-repeat;background-size:.9rem .9rem}.callout.callout-style-default .callout-toggle::before{margin-top:5px}.callout .callout-btn-toggle .callout-toggle::before{transition:transform .2s linear}.callout .callout-header[aria-expanded=false] .callout-toggle::before{transform:rotate(-90deg)}.callout .callout-header[aria-expanded=true] .callout-toggle::before{transform:none}.callout.callout-style-simple:not(.no-icon) div.callout-icon-container{padding-top:.2em;padding-right:.55em}.callout.callout-style-default:not(.no-icon) div.callout-icon-container{padding-top:.1em;padding-right:.35em}.callout.callout-style-default:not(.no-icon) div.callout-title-container{margin-top:-1px}.callout.callout-style-default.callout-caution:not(.no-icon) div.callout-icon-container{padding-top:.3em;padding-right:.35em}.callout>.callout-body>.callout-icon-container>.no-icon,.callout>.callout-header>.callout-icon-container>.no-icon{display:none}div.callout.callout{border-left-color:rgba(33,37,41,.75)}div.callout.callout-style-default>.callout-header{background-color:rgba(33,37,41,.75)}div.callout-note.callout{border-left-color:#0d6efd}div.callout-note.callout-style-default>.callout-header{background-color:#e7f1ff}div.callout-note:not(.callout-titled) .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-note.callout-titled .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-note .callout-toggle::before{background-image:url('data:image/svg+xml,')}div.callout-tip.callout{border-left-color:#198754}div.callout-tip.callout-style-default>.callout-header{background-color:#e8f3ee}div.callout-tip:not(.callout-titled) .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-tip.callout-titled .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-tip .callout-toggle::before{background-image:url('data:image/svg+xml,')}div.callout-warning.callout{border-left-color:#ffc107}div.callout-warning.callout-style-default>.callout-header{background-color:#fff9e6}div.callout-warning:not(.callout-titled) .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-warning.callout-titled .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-warning .callout-toggle::before{background-image:url('data:image/svg+xml,')}div.callout-caution.callout{border-left-color:#fd7e14}div.callout-caution.callout-style-default>.callout-header{background-color:#fff2e8}div.callout-caution:not(.callout-titled) .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-caution.callout-titled .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-caution .callout-toggle::before{background-image:url('data:image/svg+xml,')}div.callout-important.callout{border-left-color:#dc3545}div.callout-important.callout-style-default>.callout-header{background-color:#fcebec}div.callout-important:not(.callout-titled) .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-important.callout-titled .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-important .callout-toggle::before{background-image:url('data:image/svg+xml,')}.quarto-toggle-container{display:flex;align-items:center}.quarto-reader-toggle .bi::before,.quarto-color-scheme-toggle .bi::before{display:inline-block;height:1rem;width:1rem;content:"";background-repeat:no-repeat;background-size:1rem 1rem}.sidebar-navigation{padding-left:20px}.navbar{background-color:#517699;color:#fdfefe}.navbar .quarto-color-scheme-toggle:not(.alternate) .bi::before{background-image:url('data:image/svg+xml,')}.navbar .quarto-color-scheme-toggle.alternate .bi::before{background-image:url('data:image/svg+xml,')}.sidebar-navigation .quarto-color-scheme-toggle:not(.alternate) .bi::before{background-image:url('data:image/svg+xml,')}.sidebar-navigation .quarto-color-scheme-toggle.alternate .bi::before{background-image:url('data:image/svg+xml,')}.quarto-sidebar-toggle{border-color:#dee2e6;border-bottom-left-radius:.375rem;border-bottom-right-radius:.375rem;border-style:solid;border-width:1px;overflow:hidden;border-top-width:0px;padding-top:0px !important}.quarto-sidebar-toggle-title{cursor:pointer;padding-bottom:2px;margin-left:.25em;text-align:center;font-weight:400;font-size:.775em}#quarto-content .quarto-sidebar-toggle{background:#fafafa}#quarto-content .quarto-sidebar-toggle-title{color:#212529}.quarto-sidebar-toggle-icon{color:#dee2e6;margin-right:.5em;float:right;transition:transform .2s ease}.quarto-sidebar-toggle-icon::before{padding-top:5px}.quarto-sidebar-toggle.expanded .quarto-sidebar-toggle-icon{transform:rotate(-180deg)}.quarto-sidebar-toggle.expanded .quarto-sidebar-toggle-title{border-bottom:solid #dee2e6 1px}.quarto-sidebar-toggle-contents{background-color:#fff;padding-right:10px;padding-left:10px;margin-top:0px !important;transition:max-height .5s ease}.quarto-sidebar-toggle.expanded .quarto-sidebar-toggle-contents{padding-top:1em;padding-bottom:10px}@media(max-width: 767.98px){.sidebar-menu-container{padding-bottom:5em}}.quarto-sidebar-toggle:not(.expanded) .quarto-sidebar-toggle-contents{padding-top:0px !important;padding-bottom:0px}nav[role=doc-toc]{z-index:1020}#quarto-sidebar>*,nav[role=doc-toc]>*{transition:opacity .1s ease,border .1s ease}#quarto-sidebar.slow>*,nav[role=doc-toc].slow>*{transition:opacity .4s ease,border .4s ease}.quarto-color-scheme-toggle:not(.alternate).top-right .bi::before{background-image:url('data:image/svg+xml,')}.quarto-color-scheme-toggle.alternate.top-right .bi::before{background-image:url('data:image/svg+xml,')}#quarto-appendix.default{border-top:1px solid #dee2e6}#quarto-appendix.default{background-color:#fff;padding-top:1.5em;margin-top:2em;z-index:998}#quarto-appendix.default .quarto-appendix-heading{margin-top:0;line-height:1.4em;font-weight:600;opacity:.9;border-bottom:none;margin-bottom:0}#quarto-appendix.default .footnotes ol,#quarto-appendix.default .footnotes ol li>p:last-of-type,#quarto-appendix.default .quarto-appendix-contents>p:last-of-type{margin-bottom:0}#quarto-appendix.default .footnotes ol{margin-left:.5em}#quarto-appendix.default .quarto-appendix-secondary-label{margin-bottom:.4em}#quarto-appendix.default .quarto-appendix-bibtex{font-size:.7em;padding:1em;border:solid 1px #dee2e6;margin-bottom:1em}#quarto-appendix.default .quarto-appendix-bibtex code.sourceCode{white-space:pre-wrap}#quarto-appendix.default .quarto-appendix-citeas{font-size:.9em;padding:1em;border:solid 1px #dee2e6;margin-bottom:1em}#quarto-appendix.default .quarto-appendix-heading{font-size:1em !important}#quarto-appendix.default *[role=doc-endnotes]>ol,#quarto-appendix.default .quarto-appendix-contents>*:not(h2):not(.h2){font-size:.9em}#quarto-appendix.default section{padding-bottom:1.5em}#quarto-appendix.default section *[role=doc-endnotes],#quarto-appendix.default section>*:not(a){opacity:.9;word-wrap:break-word}.btn.btn-quarto,div.cell-output-display .btn-quarto{--bs-btn-color: #fefefe;--bs-btn-bg: #6c757d;--bs-btn-border-color: #6c757d;--bs-btn-hover-color: #fefefe;--bs-btn-hover-bg: #828a91;--bs-btn-hover-border-color: #7b838a;--bs-btn-focus-shadow-rgb: 130, 138, 144;--bs-btn-active-color: #000;--bs-btn-active-bg: #899197;--bs-btn-active-border-color: #7b838a;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #ffffff;--bs-btn-disabled-bg: #6c757d;--bs-btn-disabled-border-color: #6c757d}nav.quarto-secondary-nav.color-navbar{background-color:#517699;color:#fdfefe}nav.quarto-secondary-nav.color-navbar h1,nav.quarto-secondary-nav.color-navbar .h1,nav.quarto-secondary-nav.color-navbar .quarto-btn-toggle{color:#fdfefe}@media(max-width: 991.98px){body.nav-sidebar .quarto-title-banner{margin-bottom:0;padding-bottom:1em}body.nav-sidebar #title-block-header{margin-block-end:0}}p.subtitle{margin-top:.25em;margin-bottom:.5em}code a:any-link{color:inherit;text-decoration-color:#6c757d}/*! light */div.observablehq table thead tr th{background-color:var(--bs-body-bg)}input,button,select,optgroup,textarea{background-color:var(--bs-body-bg)}.code-annotated .code-copy-button{margin-right:1.25em;margin-top:0;padding-bottom:0;padding-top:3px}.code-annotation-gutter-bg{background-color:#fff}.code-annotation-gutter{background-color:rgba(233,236,239,.65)}.code-annotation-gutter,.code-annotation-gutter-bg{height:100%;width:calc(20px + .5em);position:absolute;top:0;right:0}dl.code-annotation-container-grid dt{margin-right:1em;margin-top:.25rem}dl.code-annotation-container-grid dt{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;color:#383f45;border:solid #383f45 1px;border-radius:50%;height:22px;width:22px;line-height:22px;font-size:11px;text-align:center;vertical-align:middle;text-decoration:none}dl.code-annotation-container-grid dt[data-target-cell]{cursor:pointer}dl.code-annotation-container-grid dt[data-target-cell].code-annotation-active{color:#fff;border:solid #aaa 1px;background-color:#aaa}pre.code-annotation-code{padding-top:0;padding-bottom:0}pre.code-annotation-code code{z-index:3}#code-annotation-line-highlight-gutter{width:100%;border-top:solid rgba(170,170,170,.2666666667) 1px;border-bottom:solid rgba(170,170,170,.2666666667) 1px;z-index:2;background-color:rgba(170,170,170,.1333333333)}#code-annotation-line-highlight{margin-left:-4em;width:calc(100% + 4em);border-top:solid rgba(170,170,170,.2666666667) 1px;border-bottom:solid rgba(170,170,170,.2666666667) 1px;z-index:2;background-color:rgba(170,170,170,.1333333333)}code.sourceCode .code-annotation-anchor.code-annotation-active{background-color:var(--quarto-hl-normal-color, #aaaaaa);border:solid var(--quarto-hl-normal-color, #aaaaaa) 1px;color:#e9ecef;font-weight:bolder}code.sourceCode .code-annotation-anchor{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;color:var(--quarto-hl-co-color);border:solid var(--quarto-hl-co-color) 1px;border-radius:50%;height:18px;width:18px;font-size:9px;margin-top:2px}code.sourceCode button.code-annotation-anchor{padding:2px;user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none}code.sourceCode a.code-annotation-anchor{line-height:18px;text-align:center;vertical-align:middle;cursor:default;text-decoration:none}@media print{.page-columns .column-screen-inset{grid-column:page-start-inset/page-end-inset;z-index:998;opacity:.999}.page-columns .column-screen-inset table{background:#fff}.page-columns .column-screen-inset-left{grid-column:page-start-inset/body-content-end;z-index:998;opacity:.999}.page-columns .column-screen-inset-left table{background:#fff}.page-columns .column-screen-inset-right{grid-column:body-content-start/page-end-inset;z-index:998;opacity:.999}.page-columns .column-screen-inset-right table{background:#fff}.page-columns .column-screen{grid-column:page-start/page-end;z-index:998;opacity:.999}.page-columns .column-screen table{background:#fff}.page-columns .column-screen-left{grid-column:page-start/body-content-end;z-index:998;opacity:.999}.page-columns .column-screen-left table{background:#fff}.page-columns .column-screen-right{grid-column:body-content-start/page-end;z-index:998;opacity:.999}.page-columns .column-screen-right table{background:#fff}.page-columns .column-screen-inset-shaded{grid-column:page-start-inset/page-end-inset;padding:1em;background:#f8f9fa;z-index:998;opacity:.999;margin-bottom:1em}}.quarto-video{margin-bottom:1em}.table{border-top:1px solid #d3d8dc;border-bottom:1px solid #d3d8dc}.table>thead{border-top-width:0;border-bottom:1px solid #9ba5ae}.table a{word-break:break-word}.table>:not(caption)>*>*{background-color:unset;color:unset}#quarto-document-content .crosstalk-input .checkbox input[type=checkbox],#quarto-document-content .crosstalk-input .checkbox-inline input[type=checkbox]{position:unset;margin-top:unset;margin-left:unset}#quarto-document-content .row{margin-left:unset;margin-right:unset}.quarto-xref{white-space:nowrap}#quarto-draft-alert{margin-top:0px;margin-bottom:0px;padding:.3em;text-align:center;font-size:.9em}#quarto-draft-alert i{margin-right:.3em}a.external:after{content:"";background-image:url('data:image/svg+xml,');background-size:contain;background-repeat:no-repeat;background-position:center center;margin-left:.2em;padding-right:.75em}div.sourceCode code a.external:after{content:none}a.external:after:hover{cursor:pointer}.quarto-ext-icon{display:inline-block;font-size:.75em;padding-left:.3em}.code-with-filename .code-with-filename-file{margin-bottom:0;padding-bottom:2px;padding-top:2px;padding-left:.7em;border:var(--quarto-border-width) solid var(--quarto-border-color);border-radius:var(--quarto-border-radius);border-bottom:0;border-bottom-left-radius:0%;border-bottom-right-radius:0%}.code-with-filename div.sourceCode,.reveal .code-with-filename div.sourceCode{margin-top:0;border-top-left-radius:0%;border-top-right-radius:0%}.code-with-filename .code-with-filename-file pre{margin-bottom:0}.code-with-filename .code-with-filename-file{background-color:rgba(219,219,219,.8)}.quarto-dark .code-with-filename .code-with-filename-file{background-color:#555}.code-with-filename .code-with-filename-file strong{font-weight:400}.quarto-title-banner{margin-bottom:1em;color:#fdfefe;background:#517699}.quarto-title-banner a{color:#fdfefe}.quarto-title-banner h1,.quarto-title-banner .h1,.quarto-title-banner h2,.quarto-title-banner .h2{color:#fdfefe}.quarto-title-banner .code-tools-button{color:#b9dcdc}.quarto-title-banner .code-tools-button:hover{color:#fdfefe}.quarto-title-banner .code-tools-button>.bi::before{background-image:url('data:image/svg+xml,')}.quarto-title-banner .code-tools-button:hover>.bi::before{background-image:url('data:image/svg+xml,')}.quarto-title-banner .quarto-title .title{font-weight:600}.quarto-title-banner .quarto-categories{margin-top:.75em}@media(min-width: 992px){.quarto-title-banner{padding-top:2.5em;padding-bottom:2.5em}}@media(max-width: 991.98px){.quarto-title-banner{padding-top:1em;padding-bottom:1em}}@media(max-width: 767.98px){body.hypothesis-enabled #title-block-header>*{padding-right:20px}}main.quarto-banner-title-block>section:first-child>h2,main.quarto-banner-title-block>section:first-child>.h2,main.quarto-banner-title-block>section:first-child>h3,main.quarto-banner-title-block>section:first-child>.h3,main.quarto-banner-title-block>section:first-child>h4,main.quarto-banner-title-block>section:first-child>.h4{margin-top:0}.quarto-title .quarto-categories{display:flex;flex-wrap:wrap;row-gap:.5em;column-gap:.4em;padding-bottom:.5em;margin-top:.75em}.quarto-title .quarto-categories .quarto-category{padding:.25em .75em;font-size:.65em;text-transform:uppercase;border:solid 1px;border-radius:.375rem;opacity:.6}.quarto-title .quarto-categories .quarto-category a{color:inherit}.quarto-title-meta-container{display:grid;grid-template-columns:1fr auto}.quarto-title-meta-column-end{display:flex;flex-direction:column;padding-left:1em}.quarto-title-meta-column-end a .bi{margin-right:.3em}#title-block-header.quarto-title-block.default .quarto-title-meta{display:grid;grid-template-columns:repeat(2, 1fr);grid-column-gap:1em}#title-block-header.quarto-title-block.default .quarto-title .title{margin-bottom:0}#title-block-header.quarto-title-block.default .quarto-title-author-orcid img{margin-top:-0.2em;height:.8em;width:.8em}#title-block-header.quarto-title-block.default .quarto-title-author-email{opacity:.7}#title-block-header.quarto-title-block.default .quarto-description p:last-of-type{margin-bottom:0}#title-block-header.quarto-title-block.default .quarto-title-meta-contents p,#title-block-header.quarto-title-block.default .quarto-title-authors p,#title-block-header.quarto-title-block.default .quarto-title-affiliations p{margin-bottom:.1em}#title-block-header.quarto-title-block.default .quarto-title-meta-heading{text-transform:uppercase;margin-top:1em;font-size:.8em;opacity:.8;font-weight:400}#title-block-header.quarto-title-block.default .quarto-title-meta-contents{font-size:.9em}#title-block-header.quarto-title-block.default .quarto-title-meta-contents p.affiliation:last-of-type{margin-bottom:.1em}#title-block-header.quarto-title-block.default p.affiliation{margin-bottom:.1em}#title-block-header.quarto-title-block.default .keywords,#title-block-header.quarto-title-block.default .description,#title-block-header.quarto-title-block.default .abstract{margin-top:0}#title-block-header.quarto-title-block.default .keywords>p,#title-block-header.quarto-title-block.default .description>p,#title-block-header.quarto-title-block.default .abstract>p{font-size:.9em}#title-block-header.quarto-title-block.default .keywords>p:last-of-type,#title-block-header.quarto-title-block.default .description>p:last-of-type,#title-block-header.quarto-title-block.default .abstract>p:last-of-type{margin-bottom:0}#title-block-header.quarto-title-block.default .keywords .block-title,#title-block-header.quarto-title-block.default .description .block-title,#title-block-header.quarto-title-block.default .abstract .block-title{margin-top:1em;text-transform:uppercase;font-size:.8em;opacity:.8;font-weight:400}#title-block-header.quarto-title-block.default .quarto-title-meta-author{display:grid;grid-template-columns:minmax(max-content, 1fr) 1fr;grid-column-gap:1em}.quarto-title-tools-only{display:flex;justify-content:right} diff --git a/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/run_pecan_files/libs/bootstrap/bootstrap.min.js b/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/run_pecan_files/libs/bootstrap/bootstrap.min.js deleted file mode 100644 index e8f21f703..000000000 --- a/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/run_pecan_files/libs/bootstrap/bootstrap.min.js +++ /dev/null @@ -1,7 +0,0 @@ -/*! - * Bootstrap v5.3.1 (https://getbootstrap.com/) - * Copyright 2011-2023 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) - */ -!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).bootstrap=e()}(this,(function(){"use strict";const t=new Map,e={set(e,i,n){t.has(e)||t.set(e,new Map);const s=t.get(e);s.has(i)||0===s.size?s.set(i,n):console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(s.keys())[0]}.`)},get:(e,i)=>t.has(e)&&t.get(e).get(i)||null,remove(e,i){if(!t.has(e))return;const n=t.get(e);n.delete(i),0===n.size&&t.delete(e)}},i="transitionend",n=t=>(t&&window.CSS&&window.CSS.escape&&(t=t.replace(/#([^\s"#']+)/g,((t,e)=>`#${CSS.escape(e)}`))),t),s=t=>{t.dispatchEvent(new Event(i))},o=t=>!(!t||"object"!=typeof t)&&(void 0!==t.jquery&&(t=t[0]),void 0!==t.nodeType),r=t=>o(t)?t.jquery?t[0]:t:"string"==typeof t&&t.length>0?document.querySelector(n(t)):null,a=t=>{if(!o(t)||0===t.getClientRects().length)return!1;const e="visible"===getComputedStyle(t).getPropertyValue("visibility"),i=t.closest("details:not([open])");if(!i)return e;if(i!==t){const e=t.closest("summary");if(e&&e.parentNode!==i)return!1;if(null===e)return!1}return e},l=t=>!t||t.nodeType!==Node.ELEMENT_NODE||!!t.classList.contains("disabled")||(void 0!==t.disabled?t.disabled:t.hasAttribute("disabled")&&"false"!==t.getAttribute("disabled")),c=t=>{if(!document.documentElement.attachShadow)return null;if("function"==typeof t.getRootNode){const e=t.getRootNode();return e instanceof ShadowRoot?e:null}return t instanceof ShadowRoot?t:t.parentNode?c(t.parentNode):null},h=()=>{},d=t=>{t.offsetHeight},u=()=>window.jQuery&&!document.body.hasAttribute("data-bs-no-jquery")?window.jQuery:null,f=[],p=()=>"rtl"===document.documentElement.dir,m=t=>{var e;e=()=>{const e=u();if(e){const i=t.NAME,n=e.fn[i];e.fn[i]=t.jQueryInterface,e.fn[i].Constructor=t,e.fn[i].noConflict=()=>(e.fn[i]=n,t.jQueryInterface)}},"loading"===document.readyState?(f.length||document.addEventListener("DOMContentLoaded",(()=>{for(const t of f)t()})),f.push(e)):e()},g=(t,e=[],i=t)=>"function"==typeof t?t(...e):i,_=(t,e,n=!0)=>{if(!n)return void g(t);const o=(t=>{if(!t)return 0;let{transitionDuration:e,transitionDelay:i}=window.getComputedStyle(t);const n=Number.parseFloat(e),s=Number.parseFloat(i);return n||s?(e=e.split(",")[0],i=i.split(",")[0],1e3*(Number.parseFloat(e)+Number.parseFloat(i))):0})(e)+5;let r=!1;const a=({target:n})=>{n===e&&(r=!0,e.removeEventListener(i,a),g(t))};e.addEventListener(i,a),setTimeout((()=>{r||s(e)}),o)},b=(t,e,i,n)=>{const s=t.length;let o=t.indexOf(e);return-1===o?!i&&n?t[s-1]:t[0]:(o+=i?1:-1,n&&(o=(o+s)%s),t[Math.max(0,Math.min(o,s-1))])},v=/[^.]*(?=\..*)\.|.*/,y=/\..*/,w=/::\d+$/,A={};let E=1;const T={mouseenter:"mouseover",mouseleave:"mouseout"},C=new Set(["click","dblclick","mouseup","mousedown","contextmenu","mousewheel","DOMMouseScroll","mouseover","mouseout","mousemove","selectstart","selectend","keydown","keypress","keyup","orientationchange","touchstart","touchmove","touchend","touchcancel","pointerdown","pointermove","pointerup","pointerleave","pointercancel","gesturestart","gesturechange","gestureend","focus","blur","change","reset","select","submit","focusin","focusout","load","unload","beforeunload","resize","move","DOMContentLoaded","readystatechange","error","abort","scroll"]);function O(t,e){return e&&`${e}::${E++}`||t.uidEvent||E++}function x(t){const e=O(t);return t.uidEvent=e,A[e]=A[e]||{},A[e]}function k(t,e,i=null){return Object.values(t).find((t=>t.callable===e&&t.delegationSelector===i))}function L(t,e,i){const n="string"==typeof e,s=n?i:e||i;let o=I(t);return C.has(o)||(o=t),[n,s,o]}function S(t,e,i,n,s){if("string"!=typeof e||!t)return;let[o,r,a]=L(e,i,n);if(e in T){const t=t=>function(e){if(!e.relatedTarget||e.relatedTarget!==e.delegateTarget&&!e.delegateTarget.contains(e.relatedTarget))return t.call(this,e)};r=t(r)}const l=x(t),c=l[a]||(l[a]={}),h=k(c,r,o?i:null);if(h)return void(h.oneOff=h.oneOff&&s);const d=O(r,e.replace(v,"")),u=o?function(t,e,i){return function n(s){const o=t.querySelectorAll(e);for(let{target:r}=s;r&&r!==this;r=r.parentNode)for(const a of o)if(a===r)return P(s,{delegateTarget:r}),n.oneOff&&N.off(t,s.type,e,i),i.apply(r,[s])}}(t,i,r):function(t,e){return function i(n){return P(n,{delegateTarget:t}),i.oneOff&&N.off(t,n.type,e),e.apply(t,[n])}}(t,r);u.delegationSelector=o?i:null,u.callable=r,u.oneOff=s,u.uidEvent=d,c[d]=u,t.addEventListener(a,u,o)}function D(t,e,i,n,s){const o=k(e[i],n,s);o&&(t.removeEventListener(i,o,Boolean(s)),delete e[i][o.uidEvent])}function $(t,e,i,n){const s=e[i]||{};for(const[o,r]of Object.entries(s))o.includes(n)&&D(t,e,i,r.callable,r.delegationSelector)}function I(t){return t=t.replace(y,""),T[t]||t}const N={on(t,e,i,n){S(t,e,i,n,!1)},one(t,e,i,n){S(t,e,i,n,!0)},off(t,e,i,n){if("string"!=typeof e||!t)return;const[s,o,r]=L(e,i,n),a=r!==e,l=x(t),c=l[r]||{},h=e.startsWith(".");if(void 0===o){if(h)for(const i of Object.keys(l))$(t,l,i,e.slice(1));for(const[i,n]of Object.entries(c)){const s=i.replace(w,"");a&&!e.includes(s)||D(t,l,r,n.callable,n.delegationSelector)}}else{if(!Object.keys(c).length)return;D(t,l,r,o,s?i:null)}},trigger(t,e,i){if("string"!=typeof e||!t)return null;const n=u();let s=null,o=!0,r=!0,a=!1;e!==I(e)&&n&&(s=n.Event(e,i),n(t).trigger(s),o=!s.isPropagationStopped(),r=!s.isImmediatePropagationStopped(),a=s.isDefaultPrevented());const l=P(new Event(e,{bubbles:o,cancelable:!0}),i);return a&&l.preventDefault(),r&&t.dispatchEvent(l),l.defaultPrevented&&s&&s.preventDefault(),l}};function P(t,e={}){for(const[i,n]of Object.entries(e))try{t[i]=n}catch(e){Object.defineProperty(t,i,{configurable:!0,get:()=>n})}return t}function M(t){if("true"===t)return!0;if("false"===t)return!1;if(t===Number(t).toString())return Number(t);if(""===t||"null"===t)return null;if("string"!=typeof t)return t;try{return JSON.parse(decodeURIComponent(t))}catch(e){return t}}function j(t){return t.replace(/[A-Z]/g,(t=>`-${t.toLowerCase()}`))}const F={setDataAttribute(t,e,i){t.setAttribute(`data-bs-${j(e)}`,i)},removeDataAttribute(t,e){t.removeAttribute(`data-bs-${j(e)}`)},getDataAttributes(t){if(!t)return{};const e={},i=Object.keys(t.dataset).filter((t=>t.startsWith("bs")&&!t.startsWith("bsConfig")));for(const n of i){let i=n.replace(/^bs/,"");i=i.charAt(0).toLowerCase()+i.slice(1,i.length),e[i]=M(t.dataset[n])}return e},getDataAttribute:(t,e)=>M(t.getAttribute(`data-bs-${j(e)}`))};class H{static get Default(){return{}}static get DefaultType(){return{}}static get NAME(){throw new Error('You have to implement the static method "NAME", for each component!')}_getConfig(t){return t=this._mergeConfigObj(t),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}_configAfterMerge(t){return t}_mergeConfigObj(t,e){const i=o(e)?F.getDataAttribute(e,"config"):{};return{...this.constructor.Default,..."object"==typeof i?i:{},...o(e)?F.getDataAttributes(e):{},..."object"==typeof t?t:{}}}_typeCheckConfig(t,e=this.constructor.DefaultType){for(const[n,s]of Object.entries(e)){const e=t[n],r=o(e)?"element":null==(i=e)?`${i}`:Object.prototype.toString.call(i).match(/\s([a-z]+)/i)[1].toLowerCase();if(!new RegExp(s).test(r))throw new TypeError(`${this.constructor.NAME.toUpperCase()}: Option "${n}" provided type "${r}" but expected type "${s}".`)}var i}}class W extends H{constructor(t,i){super(),(t=r(t))&&(this._element=t,this._config=this._getConfig(i),e.set(this._element,this.constructor.DATA_KEY,this))}dispose(){e.remove(this._element,this.constructor.DATA_KEY),N.off(this._element,this.constructor.EVENT_KEY);for(const t of Object.getOwnPropertyNames(this))this[t]=null}_queueCallback(t,e,i=!0){_(t,e,i)}_getConfig(t){return t=this._mergeConfigObj(t,this._element),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}static getInstance(t){return e.get(r(t),this.DATA_KEY)}static getOrCreateInstance(t,e={}){return this.getInstance(t)||new this(t,"object"==typeof e?e:null)}static get VERSION(){return"5.3.1"}static get DATA_KEY(){return`bs.${this.NAME}`}static get EVENT_KEY(){return`.${this.DATA_KEY}`}static eventName(t){return`${t}${this.EVENT_KEY}`}}const B=t=>{let e=t.getAttribute("data-bs-target");if(!e||"#"===e){let i=t.getAttribute("href");if(!i||!i.includes("#")&&!i.startsWith("."))return null;i.includes("#")&&!i.startsWith("#")&&(i=`#${i.split("#")[1]}`),e=i&&"#"!==i?i.trim():null}return n(e)},z={find:(t,e=document.documentElement)=>[].concat(...Element.prototype.querySelectorAll.call(e,t)),findOne:(t,e=document.documentElement)=>Element.prototype.querySelector.call(e,t),children:(t,e)=>[].concat(...t.children).filter((t=>t.matches(e))),parents(t,e){const i=[];let n=t.parentNode.closest(e);for(;n;)i.push(n),n=n.parentNode.closest(e);return i},prev(t,e){let i=t.previousElementSibling;for(;i;){if(i.matches(e))return[i];i=i.previousElementSibling}return[]},next(t,e){let i=t.nextElementSibling;for(;i;){if(i.matches(e))return[i];i=i.nextElementSibling}return[]},focusableChildren(t){const e=["a","button","input","textarea","select","details","[tabindex]",'[contenteditable="true"]'].map((t=>`${t}:not([tabindex^="-"])`)).join(",");return this.find(e,t).filter((t=>!l(t)&&a(t)))},getSelectorFromElement(t){const e=B(t);return e&&z.findOne(e)?e:null},getElementFromSelector(t){const e=B(t);return e?z.findOne(e):null},getMultipleElementsFromSelector(t){const e=B(t);return e?z.find(e):[]}},R=(t,e="hide")=>{const i=`click.dismiss${t.EVENT_KEY}`,n=t.NAME;N.on(document,i,`[data-bs-dismiss="${n}"]`,(function(i){if(["A","AREA"].includes(this.tagName)&&i.preventDefault(),l(this))return;const s=z.getElementFromSelector(this)||this.closest(`.${n}`);t.getOrCreateInstance(s)[e]()}))},q=".bs.alert",V=`close${q}`,K=`closed${q}`;class Q extends W{static get NAME(){return"alert"}close(){if(N.trigger(this._element,V).defaultPrevented)return;this._element.classList.remove("show");const t=this._element.classList.contains("fade");this._queueCallback((()=>this._destroyElement()),this._element,t)}_destroyElement(){this._element.remove(),N.trigger(this._element,K),this.dispose()}static jQueryInterface(t){return this.each((function(){const e=Q.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}R(Q,"close"),m(Q);const X='[data-bs-toggle="button"]';class Y extends W{static get NAME(){return"button"}toggle(){this._element.setAttribute("aria-pressed",this._element.classList.toggle("active"))}static jQueryInterface(t){return this.each((function(){const e=Y.getOrCreateInstance(this);"toggle"===t&&e[t]()}))}}N.on(document,"click.bs.button.data-api",X,(t=>{t.preventDefault();const e=t.target.closest(X);Y.getOrCreateInstance(e).toggle()})),m(Y);const U=".bs.swipe",G=`touchstart${U}`,J=`touchmove${U}`,Z=`touchend${U}`,tt=`pointerdown${U}`,et=`pointerup${U}`,it={endCallback:null,leftCallback:null,rightCallback:null},nt={endCallback:"(function|null)",leftCallback:"(function|null)",rightCallback:"(function|null)"};class st extends H{constructor(t,e){super(),this._element=t,t&&st.isSupported()&&(this._config=this._getConfig(e),this._deltaX=0,this._supportPointerEvents=Boolean(window.PointerEvent),this._initEvents())}static get Default(){return it}static get DefaultType(){return nt}static get NAME(){return"swipe"}dispose(){N.off(this._element,U)}_start(t){this._supportPointerEvents?this._eventIsPointerPenTouch(t)&&(this._deltaX=t.clientX):this._deltaX=t.touches[0].clientX}_end(t){this._eventIsPointerPenTouch(t)&&(this._deltaX=t.clientX-this._deltaX),this._handleSwipe(),g(this._config.endCallback)}_move(t){this._deltaX=t.touches&&t.touches.length>1?0:t.touches[0].clientX-this._deltaX}_handleSwipe(){const t=Math.abs(this._deltaX);if(t<=40)return;const e=t/this._deltaX;this._deltaX=0,e&&g(e>0?this._config.rightCallback:this._config.leftCallback)}_initEvents(){this._supportPointerEvents?(N.on(this._element,tt,(t=>this._start(t))),N.on(this._element,et,(t=>this._end(t))),this._element.classList.add("pointer-event")):(N.on(this._element,G,(t=>this._start(t))),N.on(this._element,J,(t=>this._move(t))),N.on(this._element,Z,(t=>this._end(t))))}_eventIsPointerPenTouch(t){return this._supportPointerEvents&&("pen"===t.pointerType||"touch"===t.pointerType)}static isSupported(){return"ontouchstart"in document.documentElement||navigator.maxTouchPoints>0}}const ot=".bs.carousel",rt=".data-api",at="next",lt="prev",ct="left",ht="right",dt=`slide${ot}`,ut=`slid${ot}`,ft=`keydown${ot}`,pt=`mouseenter${ot}`,mt=`mouseleave${ot}`,gt=`dragstart${ot}`,_t=`load${ot}${rt}`,bt=`click${ot}${rt}`,vt="carousel",yt="active",wt=".active",At=".carousel-item",Et=wt+At,Tt={ArrowLeft:ht,ArrowRight:ct},Ct={interval:5e3,keyboard:!0,pause:"hover",ride:!1,touch:!0,wrap:!0},Ot={interval:"(number|boolean)",keyboard:"boolean",pause:"(string|boolean)",ride:"(boolean|string)",touch:"boolean",wrap:"boolean"};class xt extends W{constructor(t,e){super(t,e),this._interval=null,this._activeElement=null,this._isSliding=!1,this.touchTimeout=null,this._swipeHelper=null,this._indicatorsElement=z.findOne(".carousel-indicators",this._element),this._addEventListeners(),this._config.ride===vt&&this.cycle()}static get Default(){return Ct}static get DefaultType(){return Ot}static get NAME(){return"carousel"}next(){this._slide(at)}nextWhenVisible(){!document.hidden&&a(this._element)&&this.next()}prev(){this._slide(lt)}pause(){this._isSliding&&s(this._element),this._clearInterval()}cycle(){this._clearInterval(),this._updateInterval(),this._interval=setInterval((()=>this.nextWhenVisible()),this._config.interval)}_maybeEnableCycle(){this._config.ride&&(this._isSliding?N.one(this._element,ut,(()=>this.cycle())):this.cycle())}to(t){const e=this._getItems();if(t>e.length-1||t<0)return;if(this._isSliding)return void N.one(this._element,ut,(()=>this.to(t)));const i=this._getItemIndex(this._getActive());if(i===t)return;const n=t>i?at:lt;this._slide(n,e[t])}dispose(){this._swipeHelper&&this._swipeHelper.dispose(),super.dispose()}_configAfterMerge(t){return t.defaultInterval=t.interval,t}_addEventListeners(){this._config.keyboard&&N.on(this._element,ft,(t=>this._keydown(t))),"hover"===this._config.pause&&(N.on(this._element,pt,(()=>this.pause())),N.on(this._element,mt,(()=>this._maybeEnableCycle()))),this._config.touch&&st.isSupported()&&this._addTouchEventListeners()}_addTouchEventListeners(){for(const t of z.find(".carousel-item img",this._element))N.on(t,gt,(t=>t.preventDefault()));const t={leftCallback:()=>this._slide(this._directionToOrder(ct)),rightCallback:()=>this._slide(this._directionToOrder(ht)),endCallback:()=>{"hover"===this._config.pause&&(this.pause(),this.touchTimeout&&clearTimeout(this.touchTimeout),this.touchTimeout=setTimeout((()=>this._maybeEnableCycle()),500+this._config.interval))}};this._swipeHelper=new st(this._element,t)}_keydown(t){if(/input|textarea/i.test(t.target.tagName))return;const e=Tt[t.key];e&&(t.preventDefault(),this._slide(this._directionToOrder(e)))}_getItemIndex(t){return this._getItems().indexOf(t)}_setActiveIndicatorElement(t){if(!this._indicatorsElement)return;const e=z.findOne(wt,this._indicatorsElement);e.classList.remove(yt),e.removeAttribute("aria-current");const i=z.findOne(`[data-bs-slide-to="${t}"]`,this._indicatorsElement);i&&(i.classList.add(yt),i.setAttribute("aria-current","true"))}_updateInterval(){const t=this._activeElement||this._getActive();if(!t)return;const e=Number.parseInt(t.getAttribute("data-bs-interval"),10);this._config.interval=e||this._config.defaultInterval}_slide(t,e=null){if(this._isSliding)return;const i=this._getActive(),n=t===at,s=e||b(this._getItems(),i,n,this._config.wrap);if(s===i)return;const o=this._getItemIndex(s),r=e=>N.trigger(this._element,e,{relatedTarget:s,direction:this._orderToDirection(t),from:this._getItemIndex(i),to:o});if(r(dt).defaultPrevented)return;if(!i||!s)return;const a=Boolean(this._interval);this.pause(),this._isSliding=!0,this._setActiveIndicatorElement(o),this._activeElement=s;const l=n?"carousel-item-start":"carousel-item-end",c=n?"carousel-item-next":"carousel-item-prev";s.classList.add(c),d(s),i.classList.add(l),s.classList.add(l),this._queueCallback((()=>{s.classList.remove(l,c),s.classList.add(yt),i.classList.remove(yt,c,l),this._isSliding=!1,r(ut)}),i,this._isAnimated()),a&&this.cycle()}_isAnimated(){return this._element.classList.contains("slide")}_getActive(){return z.findOne(Et,this._element)}_getItems(){return z.find(At,this._element)}_clearInterval(){this._interval&&(clearInterval(this._interval),this._interval=null)}_directionToOrder(t){return p()?t===ct?lt:at:t===ct?at:lt}_orderToDirection(t){return p()?t===lt?ct:ht:t===lt?ht:ct}static jQueryInterface(t){return this.each((function(){const e=xt.getOrCreateInstance(this,t);if("number"!=typeof t){if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}else e.to(t)}))}}N.on(document,bt,"[data-bs-slide], [data-bs-slide-to]",(function(t){const e=z.getElementFromSelector(this);if(!e||!e.classList.contains(vt))return;t.preventDefault();const i=xt.getOrCreateInstance(e),n=this.getAttribute("data-bs-slide-to");return n?(i.to(n),void i._maybeEnableCycle()):"next"===F.getDataAttribute(this,"slide")?(i.next(),void i._maybeEnableCycle()):(i.prev(),void i._maybeEnableCycle())})),N.on(window,_t,(()=>{const t=z.find('[data-bs-ride="carousel"]');for(const e of t)xt.getOrCreateInstance(e)})),m(xt);const kt=".bs.collapse",Lt=`show${kt}`,St=`shown${kt}`,Dt=`hide${kt}`,$t=`hidden${kt}`,It=`click${kt}.data-api`,Nt="show",Pt="collapse",Mt="collapsing",jt=`:scope .${Pt} .${Pt}`,Ft='[data-bs-toggle="collapse"]',Ht={parent:null,toggle:!0},Wt={parent:"(null|element)",toggle:"boolean"};class Bt extends W{constructor(t,e){super(t,e),this._isTransitioning=!1,this._triggerArray=[];const i=z.find(Ft);for(const t of i){const e=z.getSelectorFromElement(t),i=z.find(e).filter((t=>t===this._element));null!==e&&i.length&&this._triggerArray.push(t)}this._initializeChildren(),this._config.parent||this._addAriaAndCollapsedClass(this._triggerArray,this._isShown()),this._config.toggle&&this.toggle()}static get Default(){return Ht}static get DefaultType(){return Wt}static get NAME(){return"collapse"}toggle(){this._isShown()?this.hide():this.show()}show(){if(this._isTransitioning||this._isShown())return;let t=[];if(this._config.parent&&(t=this._getFirstLevelChildren(".collapse.show, .collapse.collapsing").filter((t=>t!==this._element)).map((t=>Bt.getOrCreateInstance(t,{toggle:!1})))),t.length&&t[0]._isTransitioning)return;if(N.trigger(this._element,Lt).defaultPrevented)return;for(const e of t)e.hide();const e=this._getDimension();this._element.classList.remove(Pt),this._element.classList.add(Mt),this._element.style[e]=0,this._addAriaAndCollapsedClass(this._triggerArray,!0),this._isTransitioning=!0;const i=`scroll${e[0].toUpperCase()+e.slice(1)}`;this._queueCallback((()=>{this._isTransitioning=!1,this._element.classList.remove(Mt),this._element.classList.add(Pt,Nt),this._element.style[e]="",N.trigger(this._element,St)}),this._element,!0),this._element.style[e]=`${this._element[i]}px`}hide(){if(this._isTransitioning||!this._isShown())return;if(N.trigger(this._element,Dt).defaultPrevented)return;const t=this._getDimension();this._element.style[t]=`${this._element.getBoundingClientRect()[t]}px`,d(this._element),this._element.classList.add(Mt),this._element.classList.remove(Pt,Nt);for(const t of this._triggerArray){const e=z.getElementFromSelector(t);e&&!this._isShown(e)&&this._addAriaAndCollapsedClass([t],!1)}this._isTransitioning=!0,this._element.style[t]="",this._queueCallback((()=>{this._isTransitioning=!1,this._element.classList.remove(Mt),this._element.classList.add(Pt),N.trigger(this._element,$t)}),this._element,!0)}_isShown(t=this._element){return t.classList.contains(Nt)}_configAfterMerge(t){return t.toggle=Boolean(t.toggle),t.parent=r(t.parent),t}_getDimension(){return this._element.classList.contains("collapse-horizontal")?"width":"height"}_initializeChildren(){if(!this._config.parent)return;const t=this._getFirstLevelChildren(Ft);for(const e of t){const t=z.getElementFromSelector(e);t&&this._addAriaAndCollapsedClass([e],this._isShown(t))}}_getFirstLevelChildren(t){const e=z.find(jt,this._config.parent);return z.find(t,this._config.parent).filter((t=>!e.includes(t)))}_addAriaAndCollapsedClass(t,e){if(t.length)for(const i of t)i.classList.toggle("collapsed",!e),i.setAttribute("aria-expanded",e)}static jQueryInterface(t){const e={};return"string"==typeof t&&/show|hide/.test(t)&&(e.toggle=!1),this.each((function(){const i=Bt.getOrCreateInstance(this,e);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t]()}}))}}N.on(document,It,Ft,(function(t){("A"===t.target.tagName||t.delegateTarget&&"A"===t.delegateTarget.tagName)&&t.preventDefault();for(const t of z.getMultipleElementsFromSelector(this))Bt.getOrCreateInstance(t,{toggle:!1}).toggle()})),m(Bt);var zt="top",Rt="bottom",qt="right",Vt="left",Kt="auto",Qt=[zt,Rt,qt,Vt],Xt="start",Yt="end",Ut="clippingParents",Gt="viewport",Jt="popper",Zt="reference",te=Qt.reduce((function(t,e){return t.concat([e+"-"+Xt,e+"-"+Yt])}),[]),ee=[].concat(Qt,[Kt]).reduce((function(t,e){return t.concat([e,e+"-"+Xt,e+"-"+Yt])}),[]),ie="beforeRead",ne="read",se="afterRead",oe="beforeMain",re="main",ae="afterMain",le="beforeWrite",ce="write",he="afterWrite",de=[ie,ne,se,oe,re,ae,le,ce,he];function ue(t){return t?(t.nodeName||"").toLowerCase():null}function fe(t){if(null==t)return window;if("[object Window]"!==t.toString()){var e=t.ownerDocument;return e&&e.defaultView||window}return t}function pe(t){return t instanceof fe(t).Element||t instanceof Element}function me(t){return t instanceof fe(t).HTMLElement||t instanceof HTMLElement}function ge(t){return"undefined"!=typeof ShadowRoot&&(t instanceof fe(t).ShadowRoot||t instanceof ShadowRoot)}const _e={name:"applyStyles",enabled:!0,phase:"write",fn:function(t){var e=t.state;Object.keys(e.elements).forEach((function(t){var i=e.styles[t]||{},n=e.attributes[t]||{},s=e.elements[t];me(s)&&ue(s)&&(Object.assign(s.style,i),Object.keys(n).forEach((function(t){var e=n[t];!1===e?s.removeAttribute(t):s.setAttribute(t,!0===e?"":e)})))}))},effect:function(t){var e=t.state,i={popper:{position:e.options.strategy,left:"0",top:"0",margin:"0"},arrow:{position:"absolute"},reference:{}};return Object.assign(e.elements.popper.style,i.popper),e.styles=i,e.elements.arrow&&Object.assign(e.elements.arrow.style,i.arrow),function(){Object.keys(e.elements).forEach((function(t){var n=e.elements[t],s=e.attributes[t]||{},o=Object.keys(e.styles.hasOwnProperty(t)?e.styles[t]:i[t]).reduce((function(t,e){return t[e]="",t}),{});me(n)&&ue(n)&&(Object.assign(n.style,o),Object.keys(s).forEach((function(t){n.removeAttribute(t)})))}))}},requires:["computeStyles"]};function be(t){return t.split("-")[0]}var ve=Math.max,ye=Math.min,we=Math.round;function Ae(){var t=navigator.userAgentData;return null!=t&&t.brands&&Array.isArray(t.brands)?t.brands.map((function(t){return t.brand+"/"+t.version})).join(" "):navigator.userAgent}function Ee(){return!/^((?!chrome|android).)*safari/i.test(Ae())}function Te(t,e,i){void 0===e&&(e=!1),void 0===i&&(i=!1);var n=t.getBoundingClientRect(),s=1,o=1;e&&me(t)&&(s=t.offsetWidth>0&&we(n.width)/t.offsetWidth||1,o=t.offsetHeight>0&&we(n.height)/t.offsetHeight||1);var r=(pe(t)?fe(t):window).visualViewport,a=!Ee()&&i,l=(n.left+(a&&r?r.offsetLeft:0))/s,c=(n.top+(a&&r?r.offsetTop:0))/o,h=n.width/s,d=n.height/o;return{width:h,height:d,top:c,right:l+h,bottom:c+d,left:l,x:l,y:c}}function Ce(t){var e=Te(t),i=t.offsetWidth,n=t.offsetHeight;return Math.abs(e.width-i)<=1&&(i=e.width),Math.abs(e.height-n)<=1&&(n=e.height),{x:t.offsetLeft,y:t.offsetTop,width:i,height:n}}function Oe(t,e){var i=e.getRootNode&&e.getRootNode();if(t.contains(e))return!0;if(i&&ge(i)){var n=e;do{if(n&&t.isSameNode(n))return!0;n=n.parentNode||n.host}while(n)}return!1}function xe(t){return fe(t).getComputedStyle(t)}function ke(t){return["table","td","th"].indexOf(ue(t))>=0}function Le(t){return((pe(t)?t.ownerDocument:t.document)||window.document).documentElement}function Se(t){return"html"===ue(t)?t:t.assignedSlot||t.parentNode||(ge(t)?t.host:null)||Le(t)}function De(t){return me(t)&&"fixed"!==xe(t).position?t.offsetParent:null}function $e(t){for(var e=fe(t),i=De(t);i&&ke(i)&&"static"===xe(i).position;)i=De(i);return i&&("html"===ue(i)||"body"===ue(i)&&"static"===xe(i).position)?e:i||function(t){var e=/firefox/i.test(Ae());if(/Trident/i.test(Ae())&&me(t)&&"fixed"===xe(t).position)return null;var i=Se(t);for(ge(i)&&(i=i.host);me(i)&&["html","body"].indexOf(ue(i))<0;){var n=xe(i);if("none"!==n.transform||"none"!==n.perspective||"paint"===n.contain||-1!==["transform","perspective"].indexOf(n.willChange)||e&&"filter"===n.willChange||e&&n.filter&&"none"!==n.filter)return i;i=i.parentNode}return null}(t)||e}function Ie(t){return["top","bottom"].indexOf(t)>=0?"x":"y"}function Ne(t,e,i){return ve(t,ye(e,i))}function Pe(t){return Object.assign({},{top:0,right:0,bottom:0,left:0},t)}function Me(t,e){return e.reduce((function(e,i){return e[i]=t,e}),{})}const je={name:"arrow",enabled:!0,phase:"main",fn:function(t){var e,i=t.state,n=t.name,s=t.options,o=i.elements.arrow,r=i.modifiersData.popperOffsets,a=be(i.placement),l=Ie(a),c=[Vt,qt].indexOf(a)>=0?"height":"width";if(o&&r){var h=function(t,e){return Pe("number"!=typeof(t="function"==typeof t?t(Object.assign({},e.rects,{placement:e.placement})):t)?t:Me(t,Qt))}(s.padding,i),d=Ce(o),u="y"===l?zt:Vt,f="y"===l?Rt:qt,p=i.rects.reference[c]+i.rects.reference[l]-r[l]-i.rects.popper[c],m=r[l]-i.rects.reference[l],g=$e(o),_=g?"y"===l?g.clientHeight||0:g.clientWidth||0:0,b=p/2-m/2,v=h[u],y=_-d[c]-h[f],w=_/2-d[c]/2+b,A=Ne(v,w,y),E=l;i.modifiersData[n]=((e={})[E]=A,e.centerOffset=A-w,e)}},effect:function(t){var e=t.state,i=t.options.element,n=void 0===i?"[data-popper-arrow]":i;null!=n&&("string"!=typeof n||(n=e.elements.popper.querySelector(n)))&&Oe(e.elements.popper,n)&&(e.elements.arrow=n)},requires:["popperOffsets"],requiresIfExists:["preventOverflow"]};function Fe(t){return t.split("-")[1]}var He={top:"auto",right:"auto",bottom:"auto",left:"auto"};function We(t){var e,i=t.popper,n=t.popperRect,s=t.placement,o=t.variation,r=t.offsets,a=t.position,l=t.gpuAcceleration,c=t.adaptive,h=t.roundOffsets,d=t.isFixed,u=r.x,f=void 0===u?0:u,p=r.y,m=void 0===p?0:p,g="function"==typeof h?h({x:f,y:m}):{x:f,y:m};f=g.x,m=g.y;var _=r.hasOwnProperty("x"),b=r.hasOwnProperty("y"),v=Vt,y=zt,w=window;if(c){var A=$e(i),E="clientHeight",T="clientWidth";A===fe(i)&&"static"!==xe(A=Le(i)).position&&"absolute"===a&&(E="scrollHeight",T="scrollWidth"),(s===zt||(s===Vt||s===qt)&&o===Yt)&&(y=Rt,m-=(d&&A===w&&w.visualViewport?w.visualViewport.height:A[E])-n.height,m*=l?1:-1),s!==Vt&&(s!==zt&&s!==Rt||o!==Yt)||(v=qt,f-=(d&&A===w&&w.visualViewport?w.visualViewport.width:A[T])-n.width,f*=l?1:-1)}var C,O=Object.assign({position:a},c&&He),x=!0===h?function(t,e){var i=t.x,n=t.y,s=e.devicePixelRatio||1;return{x:we(i*s)/s||0,y:we(n*s)/s||0}}({x:f,y:m},fe(i)):{x:f,y:m};return f=x.x,m=x.y,l?Object.assign({},O,((C={})[y]=b?"0":"",C[v]=_?"0":"",C.transform=(w.devicePixelRatio||1)<=1?"translate("+f+"px, "+m+"px)":"translate3d("+f+"px, "+m+"px, 0)",C)):Object.assign({},O,((e={})[y]=b?m+"px":"",e[v]=_?f+"px":"",e.transform="",e))}const Be={name:"computeStyles",enabled:!0,phase:"beforeWrite",fn:function(t){var e=t.state,i=t.options,n=i.gpuAcceleration,s=void 0===n||n,o=i.adaptive,r=void 0===o||o,a=i.roundOffsets,l=void 0===a||a,c={placement:be(e.placement),variation:Fe(e.placement),popper:e.elements.popper,popperRect:e.rects.popper,gpuAcceleration:s,isFixed:"fixed"===e.options.strategy};null!=e.modifiersData.popperOffsets&&(e.styles.popper=Object.assign({},e.styles.popper,We(Object.assign({},c,{offsets:e.modifiersData.popperOffsets,position:e.options.strategy,adaptive:r,roundOffsets:l})))),null!=e.modifiersData.arrow&&(e.styles.arrow=Object.assign({},e.styles.arrow,We(Object.assign({},c,{offsets:e.modifiersData.arrow,position:"absolute",adaptive:!1,roundOffsets:l})))),e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-placement":e.placement})},data:{}};var ze={passive:!0};const Re={name:"eventListeners",enabled:!0,phase:"write",fn:function(){},effect:function(t){var e=t.state,i=t.instance,n=t.options,s=n.scroll,o=void 0===s||s,r=n.resize,a=void 0===r||r,l=fe(e.elements.popper),c=[].concat(e.scrollParents.reference,e.scrollParents.popper);return o&&c.forEach((function(t){t.addEventListener("scroll",i.update,ze)})),a&&l.addEventListener("resize",i.update,ze),function(){o&&c.forEach((function(t){t.removeEventListener("scroll",i.update,ze)})),a&&l.removeEventListener("resize",i.update,ze)}},data:{}};var qe={left:"right",right:"left",bottom:"top",top:"bottom"};function Ve(t){return t.replace(/left|right|bottom|top/g,(function(t){return qe[t]}))}var Ke={start:"end",end:"start"};function Qe(t){return t.replace(/start|end/g,(function(t){return Ke[t]}))}function Xe(t){var e=fe(t);return{scrollLeft:e.pageXOffset,scrollTop:e.pageYOffset}}function Ye(t){return Te(Le(t)).left+Xe(t).scrollLeft}function Ue(t){var e=xe(t),i=e.overflow,n=e.overflowX,s=e.overflowY;return/auto|scroll|overlay|hidden/.test(i+s+n)}function Ge(t){return["html","body","#document"].indexOf(ue(t))>=0?t.ownerDocument.body:me(t)&&Ue(t)?t:Ge(Se(t))}function Je(t,e){var i;void 0===e&&(e=[]);var n=Ge(t),s=n===(null==(i=t.ownerDocument)?void 0:i.body),o=fe(n),r=s?[o].concat(o.visualViewport||[],Ue(n)?n:[]):n,a=e.concat(r);return s?a:a.concat(Je(Se(r)))}function Ze(t){return Object.assign({},t,{left:t.x,top:t.y,right:t.x+t.width,bottom:t.y+t.height})}function ti(t,e,i){return e===Gt?Ze(function(t,e){var i=fe(t),n=Le(t),s=i.visualViewport,o=n.clientWidth,r=n.clientHeight,a=0,l=0;if(s){o=s.width,r=s.height;var c=Ee();(c||!c&&"fixed"===e)&&(a=s.offsetLeft,l=s.offsetTop)}return{width:o,height:r,x:a+Ye(t),y:l}}(t,i)):pe(e)?function(t,e){var i=Te(t,!1,"fixed"===e);return i.top=i.top+t.clientTop,i.left=i.left+t.clientLeft,i.bottom=i.top+t.clientHeight,i.right=i.left+t.clientWidth,i.width=t.clientWidth,i.height=t.clientHeight,i.x=i.left,i.y=i.top,i}(e,i):Ze(function(t){var e,i=Le(t),n=Xe(t),s=null==(e=t.ownerDocument)?void 0:e.body,o=ve(i.scrollWidth,i.clientWidth,s?s.scrollWidth:0,s?s.clientWidth:0),r=ve(i.scrollHeight,i.clientHeight,s?s.scrollHeight:0,s?s.clientHeight:0),a=-n.scrollLeft+Ye(t),l=-n.scrollTop;return"rtl"===xe(s||i).direction&&(a+=ve(i.clientWidth,s?s.clientWidth:0)-o),{width:o,height:r,x:a,y:l}}(Le(t)))}function ei(t){var e,i=t.reference,n=t.element,s=t.placement,o=s?be(s):null,r=s?Fe(s):null,a=i.x+i.width/2-n.width/2,l=i.y+i.height/2-n.height/2;switch(o){case zt:e={x:a,y:i.y-n.height};break;case Rt:e={x:a,y:i.y+i.height};break;case qt:e={x:i.x+i.width,y:l};break;case Vt:e={x:i.x-n.width,y:l};break;default:e={x:i.x,y:i.y}}var c=o?Ie(o):null;if(null!=c){var h="y"===c?"height":"width";switch(r){case Xt:e[c]=e[c]-(i[h]/2-n[h]/2);break;case Yt:e[c]=e[c]+(i[h]/2-n[h]/2)}}return e}function ii(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=void 0===n?t.placement:n,o=i.strategy,r=void 0===o?t.strategy:o,a=i.boundary,l=void 0===a?Ut:a,c=i.rootBoundary,h=void 0===c?Gt:c,d=i.elementContext,u=void 0===d?Jt:d,f=i.altBoundary,p=void 0!==f&&f,m=i.padding,g=void 0===m?0:m,_=Pe("number"!=typeof g?g:Me(g,Qt)),b=u===Jt?Zt:Jt,v=t.rects.popper,y=t.elements[p?b:u],w=function(t,e,i,n){var s="clippingParents"===e?function(t){var e=Je(Se(t)),i=["absolute","fixed"].indexOf(xe(t).position)>=0&&me(t)?$e(t):t;return pe(i)?e.filter((function(t){return pe(t)&&Oe(t,i)&&"body"!==ue(t)})):[]}(t):[].concat(e),o=[].concat(s,[i]),r=o[0],a=o.reduce((function(e,i){var s=ti(t,i,n);return e.top=ve(s.top,e.top),e.right=ye(s.right,e.right),e.bottom=ye(s.bottom,e.bottom),e.left=ve(s.left,e.left),e}),ti(t,r,n));return a.width=a.right-a.left,a.height=a.bottom-a.top,a.x=a.left,a.y=a.top,a}(pe(y)?y:y.contextElement||Le(t.elements.popper),l,h,r),A=Te(t.elements.reference),E=ei({reference:A,element:v,strategy:"absolute",placement:s}),T=Ze(Object.assign({},v,E)),C=u===Jt?T:A,O={top:w.top-C.top+_.top,bottom:C.bottom-w.bottom+_.bottom,left:w.left-C.left+_.left,right:C.right-w.right+_.right},x=t.modifiersData.offset;if(u===Jt&&x){var k=x[s];Object.keys(O).forEach((function(t){var e=[qt,Rt].indexOf(t)>=0?1:-1,i=[zt,Rt].indexOf(t)>=0?"y":"x";O[t]+=k[i]*e}))}return O}function ni(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=i.boundary,o=i.rootBoundary,r=i.padding,a=i.flipVariations,l=i.allowedAutoPlacements,c=void 0===l?ee:l,h=Fe(n),d=h?a?te:te.filter((function(t){return Fe(t)===h})):Qt,u=d.filter((function(t){return c.indexOf(t)>=0}));0===u.length&&(u=d);var f=u.reduce((function(e,i){return e[i]=ii(t,{placement:i,boundary:s,rootBoundary:o,padding:r})[be(i)],e}),{});return Object.keys(f).sort((function(t,e){return f[t]-f[e]}))}const si={name:"flip",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,n=t.name;if(!e.modifiersData[n]._skip){for(var s=i.mainAxis,o=void 0===s||s,r=i.altAxis,a=void 0===r||r,l=i.fallbackPlacements,c=i.padding,h=i.boundary,d=i.rootBoundary,u=i.altBoundary,f=i.flipVariations,p=void 0===f||f,m=i.allowedAutoPlacements,g=e.options.placement,_=be(g),b=l||(_!==g&&p?function(t){if(be(t)===Kt)return[];var e=Ve(t);return[Qe(t),e,Qe(e)]}(g):[Ve(g)]),v=[g].concat(b).reduce((function(t,i){return t.concat(be(i)===Kt?ni(e,{placement:i,boundary:h,rootBoundary:d,padding:c,flipVariations:p,allowedAutoPlacements:m}):i)}),[]),y=e.rects.reference,w=e.rects.popper,A=new Map,E=!0,T=v[0],C=0;C=0,S=L?"width":"height",D=ii(e,{placement:O,boundary:h,rootBoundary:d,altBoundary:u,padding:c}),$=L?k?qt:Vt:k?Rt:zt;y[S]>w[S]&&($=Ve($));var I=Ve($),N=[];if(o&&N.push(D[x]<=0),a&&N.push(D[$]<=0,D[I]<=0),N.every((function(t){return t}))){T=O,E=!1;break}A.set(O,N)}if(E)for(var P=function(t){var e=v.find((function(e){var i=A.get(e);if(i)return i.slice(0,t).every((function(t){return t}))}));if(e)return T=e,"break"},M=p?3:1;M>0&&"break"!==P(M);M--);e.placement!==T&&(e.modifiersData[n]._skip=!0,e.placement=T,e.reset=!0)}},requiresIfExists:["offset"],data:{_skip:!1}};function oi(t,e,i){return void 0===i&&(i={x:0,y:0}),{top:t.top-e.height-i.y,right:t.right-e.width+i.x,bottom:t.bottom-e.height+i.y,left:t.left-e.width-i.x}}function ri(t){return[zt,qt,Rt,Vt].some((function(e){return t[e]>=0}))}const ai={name:"hide",enabled:!0,phase:"main",requiresIfExists:["preventOverflow"],fn:function(t){var e=t.state,i=t.name,n=e.rects.reference,s=e.rects.popper,o=e.modifiersData.preventOverflow,r=ii(e,{elementContext:"reference"}),a=ii(e,{altBoundary:!0}),l=oi(r,n),c=oi(a,s,o),h=ri(l),d=ri(c);e.modifiersData[i]={referenceClippingOffsets:l,popperEscapeOffsets:c,isReferenceHidden:h,hasPopperEscaped:d},e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-reference-hidden":h,"data-popper-escaped":d})}},li={name:"offset",enabled:!0,phase:"main",requires:["popperOffsets"],fn:function(t){var e=t.state,i=t.options,n=t.name,s=i.offset,o=void 0===s?[0,0]:s,r=ee.reduce((function(t,i){return t[i]=function(t,e,i){var n=be(t),s=[Vt,zt].indexOf(n)>=0?-1:1,o="function"==typeof i?i(Object.assign({},e,{placement:t})):i,r=o[0],a=o[1];return r=r||0,a=(a||0)*s,[Vt,qt].indexOf(n)>=0?{x:a,y:r}:{x:r,y:a}}(i,e.rects,o),t}),{}),a=r[e.placement],l=a.x,c=a.y;null!=e.modifiersData.popperOffsets&&(e.modifiersData.popperOffsets.x+=l,e.modifiersData.popperOffsets.y+=c),e.modifiersData[n]=r}},ci={name:"popperOffsets",enabled:!0,phase:"read",fn:function(t){var e=t.state,i=t.name;e.modifiersData[i]=ei({reference:e.rects.reference,element:e.rects.popper,strategy:"absolute",placement:e.placement})},data:{}},hi={name:"preventOverflow",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,n=t.name,s=i.mainAxis,o=void 0===s||s,r=i.altAxis,a=void 0!==r&&r,l=i.boundary,c=i.rootBoundary,h=i.altBoundary,d=i.padding,u=i.tether,f=void 0===u||u,p=i.tetherOffset,m=void 0===p?0:p,g=ii(e,{boundary:l,rootBoundary:c,padding:d,altBoundary:h}),_=be(e.placement),b=Fe(e.placement),v=!b,y=Ie(_),w="x"===y?"y":"x",A=e.modifiersData.popperOffsets,E=e.rects.reference,T=e.rects.popper,C="function"==typeof m?m(Object.assign({},e.rects,{placement:e.placement})):m,O="number"==typeof C?{mainAxis:C,altAxis:C}:Object.assign({mainAxis:0,altAxis:0},C),x=e.modifiersData.offset?e.modifiersData.offset[e.placement]:null,k={x:0,y:0};if(A){if(o){var L,S="y"===y?zt:Vt,D="y"===y?Rt:qt,$="y"===y?"height":"width",I=A[y],N=I+g[S],P=I-g[D],M=f?-T[$]/2:0,j=b===Xt?E[$]:T[$],F=b===Xt?-T[$]:-E[$],H=e.elements.arrow,W=f&&H?Ce(H):{width:0,height:0},B=e.modifiersData["arrow#persistent"]?e.modifiersData["arrow#persistent"].padding:{top:0,right:0,bottom:0,left:0},z=B[S],R=B[D],q=Ne(0,E[$],W[$]),V=v?E[$]/2-M-q-z-O.mainAxis:j-q-z-O.mainAxis,K=v?-E[$]/2+M+q+R+O.mainAxis:F+q+R+O.mainAxis,Q=e.elements.arrow&&$e(e.elements.arrow),X=Q?"y"===y?Q.clientTop||0:Q.clientLeft||0:0,Y=null!=(L=null==x?void 0:x[y])?L:0,U=I+K-Y,G=Ne(f?ye(N,I+V-Y-X):N,I,f?ve(P,U):P);A[y]=G,k[y]=G-I}if(a){var J,Z="x"===y?zt:Vt,tt="x"===y?Rt:qt,et=A[w],it="y"===w?"height":"width",nt=et+g[Z],st=et-g[tt],ot=-1!==[zt,Vt].indexOf(_),rt=null!=(J=null==x?void 0:x[w])?J:0,at=ot?nt:et-E[it]-T[it]-rt+O.altAxis,lt=ot?et+E[it]+T[it]-rt-O.altAxis:st,ct=f&&ot?function(t,e,i){var n=Ne(t,e,i);return n>i?i:n}(at,et,lt):Ne(f?at:nt,et,f?lt:st);A[w]=ct,k[w]=ct-et}e.modifiersData[n]=k}},requiresIfExists:["offset"]};function di(t,e,i){void 0===i&&(i=!1);var n,s,o=me(e),r=me(e)&&function(t){var e=t.getBoundingClientRect(),i=we(e.width)/t.offsetWidth||1,n=we(e.height)/t.offsetHeight||1;return 1!==i||1!==n}(e),a=Le(e),l=Te(t,r,i),c={scrollLeft:0,scrollTop:0},h={x:0,y:0};return(o||!o&&!i)&&(("body"!==ue(e)||Ue(a))&&(c=(n=e)!==fe(n)&&me(n)?{scrollLeft:(s=n).scrollLeft,scrollTop:s.scrollTop}:Xe(n)),me(e)?((h=Te(e,!0)).x+=e.clientLeft,h.y+=e.clientTop):a&&(h.x=Ye(a))),{x:l.left+c.scrollLeft-h.x,y:l.top+c.scrollTop-h.y,width:l.width,height:l.height}}function ui(t){var e=new Map,i=new Set,n=[];function s(t){i.add(t.name),[].concat(t.requires||[],t.requiresIfExists||[]).forEach((function(t){if(!i.has(t)){var n=e.get(t);n&&s(n)}})),n.push(t)}return t.forEach((function(t){e.set(t.name,t)})),t.forEach((function(t){i.has(t.name)||s(t)})),n}var fi={placement:"bottom",modifiers:[],strategy:"absolute"};function pi(){for(var t=arguments.length,e=new Array(t),i=0;iNumber.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_getPopperConfig(){const t={placement:this._getPlacement(),modifiers:[{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"offset",options:{offset:this._getOffset()}}]};return(this._inNavbar||"static"===this._config.display)&&(F.setDataAttribute(this._menu,"popper","static"),t.modifiers=[{name:"applyStyles",enabled:!1}]),{...t,...g(this._config.popperConfig,[t])}}_selectMenuItem({key:t,target:e}){const i=z.find(".dropdown-menu .dropdown-item:not(.disabled):not(:disabled)",this._menu).filter((t=>a(t)));i.length&&b(i,e,t===Ti,!i.includes(e)).focus()}static jQueryInterface(t){return this.each((function(){const e=qi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}static clearMenus(t){if(2===t.button||"keyup"===t.type&&"Tab"!==t.key)return;const e=z.find(Ni);for(const i of e){const e=qi.getInstance(i);if(!e||!1===e._config.autoClose)continue;const n=t.composedPath(),s=n.includes(e._menu);if(n.includes(e._element)||"inside"===e._config.autoClose&&!s||"outside"===e._config.autoClose&&s)continue;if(e._menu.contains(t.target)&&("keyup"===t.type&&"Tab"===t.key||/input|select|option|textarea|form/i.test(t.target.tagName)))continue;const o={relatedTarget:e._element};"click"===t.type&&(o.clickEvent=t),e._completeHide(o)}}static dataApiKeydownHandler(t){const e=/input|textarea/i.test(t.target.tagName),i="Escape"===t.key,n=[Ei,Ti].includes(t.key);if(!n&&!i)return;if(e&&!i)return;t.preventDefault();const s=this.matches(Ii)?this:z.prev(this,Ii)[0]||z.next(this,Ii)[0]||z.findOne(Ii,t.delegateTarget.parentNode),o=qi.getOrCreateInstance(s);if(n)return t.stopPropagation(),o.show(),void o._selectMenuItem(t);o._isShown()&&(t.stopPropagation(),o.hide(),s.focus())}}N.on(document,Si,Ii,qi.dataApiKeydownHandler),N.on(document,Si,Pi,qi.dataApiKeydownHandler),N.on(document,Li,qi.clearMenus),N.on(document,Di,qi.clearMenus),N.on(document,Li,Ii,(function(t){t.preventDefault(),qi.getOrCreateInstance(this).toggle()})),m(qi);const Vi="backdrop",Ki="show",Qi=`mousedown.bs.${Vi}`,Xi={className:"modal-backdrop",clickCallback:null,isAnimated:!1,isVisible:!0,rootElement:"body"},Yi={className:"string",clickCallback:"(function|null)",isAnimated:"boolean",isVisible:"boolean",rootElement:"(element|string)"};class Ui extends H{constructor(t){super(),this._config=this._getConfig(t),this._isAppended=!1,this._element=null}static get Default(){return Xi}static get DefaultType(){return Yi}static get NAME(){return Vi}show(t){if(!this._config.isVisible)return void g(t);this._append();const e=this._getElement();this._config.isAnimated&&d(e),e.classList.add(Ki),this._emulateAnimation((()=>{g(t)}))}hide(t){this._config.isVisible?(this._getElement().classList.remove(Ki),this._emulateAnimation((()=>{this.dispose(),g(t)}))):g(t)}dispose(){this._isAppended&&(N.off(this._element,Qi),this._element.remove(),this._isAppended=!1)}_getElement(){if(!this._element){const t=document.createElement("div");t.className=this._config.className,this._config.isAnimated&&t.classList.add("fade"),this._element=t}return this._element}_configAfterMerge(t){return t.rootElement=r(t.rootElement),t}_append(){if(this._isAppended)return;const t=this._getElement();this._config.rootElement.append(t),N.on(t,Qi,(()=>{g(this._config.clickCallback)})),this._isAppended=!0}_emulateAnimation(t){_(t,this._getElement(),this._config.isAnimated)}}const Gi=".bs.focustrap",Ji=`focusin${Gi}`,Zi=`keydown.tab${Gi}`,tn="backward",en={autofocus:!0,trapElement:null},nn={autofocus:"boolean",trapElement:"element"};class sn extends H{constructor(t){super(),this._config=this._getConfig(t),this._isActive=!1,this._lastTabNavDirection=null}static get Default(){return en}static get DefaultType(){return nn}static get NAME(){return"focustrap"}activate(){this._isActive||(this._config.autofocus&&this._config.trapElement.focus(),N.off(document,Gi),N.on(document,Ji,(t=>this._handleFocusin(t))),N.on(document,Zi,(t=>this._handleKeydown(t))),this._isActive=!0)}deactivate(){this._isActive&&(this._isActive=!1,N.off(document,Gi))}_handleFocusin(t){const{trapElement:e}=this._config;if(t.target===document||t.target===e||e.contains(t.target))return;const i=z.focusableChildren(e);0===i.length?e.focus():this._lastTabNavDirection===tn?i[i.length-1].focus():i[0].focus()}_handleKeydown(t){"Tab"===t.key&&(this._lastTabNavDirection=t.shiftKey?tn:"forward")}}const on=".fixed-top, .fixed-bottom, .is-fixed, .sticky-top",rn=".sticky-top",an="padding-right",ln="margin-right";class cn{constructor(){this._element=document.body}getWidth(){const t=document.documentElement.clientWidth;return Math.abs(window.innerWidth-t)}hide(){const t=this.getWidth();this._disableOverFlow(),this._setElementAttributes(this._element,an,(e=>e+t)),this._setElementAttributes(on,an,(e=>e+t)),this._setElementAttributes(rn,ln,(e=>e-t))}reset(){this._resetElementAttributes(this._element,"overflow"),this._resetElementAttributes(this._element,an),this._resetElementAttributes(on,an),this._resetElementAttributes(rn,ln)}isOverflowing(){return this.getWidth()>0}_disableOverFlow(){this._saveInitialAttribute(this._element,"overflow"),this._element.style.overflow="hidden"}_setElementAttributes(t,e,i){const n=this.getWidth();this._applyManipulationCallback(t,(t=>{if(t!==this._element&&window.innerWidth>t.clientWidth+n)return;this._saveInitialAttribute(t,e);const s=window.getComputedStyle(t).getPropertyValue(e);t.style.setProperty(e,`${i(Number.parseFloat(s))}px`)}))}_saveInitialAttribute(t,e){const i=t.style.getPropertyValue(e);i&&F.setDataAttribute(t,e,i)}_resetElementAttributes(t,e){this._applyManipulationCallback(t,(t=>{const i=F.getDataAttribute(t,e);null!==i?(F.removeDataAttribute(t,e),t.style.setProperty(e,i)):t.style.removeProperty(e)}))}_applyManipulationCallback(t,e){if(o(t))e(t);else for(const i of z.find(t,this._element))e(i)}}const hn=".bs.modal",dn=`hide${hn}`,un=`hidePrevented${hn}`,fn=`hidden${hn}`,pn=`show${hn}`,mn=`shown${hn}`,gn=`resize${hn}`,_n=`click.dismiss${hn}`,bn=`mousedown.dismiss${hn}`,vn=`keydown.dismiss${hn}`,yn=`click${hn}.data-api`,wn="modal-open",An="show",En="modal-static",Tn={backdrop:!0,focus:!0,keyboard:!0},Cn={backdrop:"(boolean|string)",focus:"boolean",keyboard:"boolean"};class On extends W{constructor(t,e){super(t,e),this._dialog=z.findOne(".modal-dialog",this._element),this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._isShown=!1,this._isTransitioning=!1,this._scrollBar=new cn,this._addEventListeners()}static get Default(){return Tn}static get DefaultType(){return Cn}static get NAME(){return"modal"}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||this._isTransitioning||N.trigger(this._element,pn,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._isTransitioning=!0,this._scrollBar.hide(),document.body.classList.add(wn),this._adjustDialog(),this._backdrop.show((()=>this._showElement(t))))}hide(){this._isShown&&!this._isTransitioning&&(N.trigger(this._element,dn).defaultPrevented||(this._isShown=!1,this._isTransitioning=!0,this._focustrap.deactivate(),this._element.classList.remove(An),this._queueCallback((()=>this._hideModal()),this._element,this._isAnimated())))}dispose(){N.off(window,hn),N.off(this._dialog,hn),this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}handleUpdate(){this._adjustDialog()}_initializeBackDrop(){return new Ui({isVisible:Boolean(this._config.backdrop),isAnimated:this._isAnimated()})}_initializeFocusTrap(){return new sn({trapElement:this._element})}_showElement(t){document.body.contains(this._element)||document.body.append(this._element),this._element.style.display="block",this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.scrollTop=0;const e=z.findOne(".modal-body",this._dialog);e&&(e.scrollTop=0),d(this._element),this._element.classList.add(An),this._queueCallback((()=>{this._config.focus&&this._focustrap.activate(),this._isTransitioning=!1,N.trigger(this._element,mn,{relatedTarget:t})}),this._dialog,this._isAnimated())}_addEventListeners(){N.on(this._element,vn,(t=>{"Escape"===t.key&&(this._config.keyboard?this.hide():this._triggerBackdropTransition())})),N.on(window,gn,(()=>{this._isShown&&!this._isTransitioning&&this._adjustDialog()})),N.on(this._element,bn,(t=>{N.one(this._element,_n,(e=>{this._element===t.target&&this._element===e.target&&("static"!==this._config.backdrop?this._config.backdrop&&this.hide():this._triggerBackdropTransition())}))}))}_hideModal(){this._element.style.display="none",this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._isTransitioning=!1,this._backdrop.hide((()=>{document.body.classList.remove(wn),this._resetAdjustments(),this._scrollBar.reset(),N.trigger(this._element,fn)}))}_isAnimated(){return this._element.classList.contains("fade")}_triggerBackdropTransition(){if(N.trigger(this._element,un).defaultPrevented)return;const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._element.style.overflowY;"hidden"===e||this._element.classList.contains(En)||(t||(this._element.style.overflowY="hidden"),this._element.classList.add(En),this._queueCallback((()=>{this._element.classList.remove(En),this._queueCallback((()=>{this._element.style.overflowY=e}),this._dialog)}),this._dialog),this._element.focus())}_adjustDialog(){const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._scrollBar.getWidth(),i=e>0;if(i&&!t){const t=p()?"paddingLeft":"paddingRight";this._element.style[t]=`${e}px`}if(!i&&t){const t=p()?"paddingRight":"paddingLeft";this._element.style[t]=`${e}px`}}_resetAdjustments(){this._element.style.paddingLeft="",this._element.style.paddingRight=""}static jQueryInterface(t,e){return this.each((function(){const i=On.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t](e)}}))}}N.on(document,yn,'[data-bs-toggle="modal"]',(function(t){const e=z.getElementFromSelector(this);["A","AREA"].includes(this.tagName)&&t.preventDefault(),N.one(e,pn,(t=>{t.defaultPrevented||N.one(e,fn,(()=>{a(this)&&this.focus()}))}));const i=z.findOne(".modal.show");i&&On.getInstance(i).hide(),On.getOrCreateInstance(e).toggle(this)})),R(On),m(On);const xn=".bs.offcanvas",kn=".data-api",Ln=`load${xn}${kn}`,Sn="show",Dn="showing",$n="hiding",In=".offcanvas.show",Nn=`show${xn}`,Pn=`shown${xn}`,Mn=`hide${xn}`,jn=`hidePrevented${xn}`,Fn=`hidden${xn}`,Hn=`resize${xn}`,Wn=`click${xn}${kn}`,Bn=`keydown.dismiss${xn}`,zn={backdrop:!0,keyboard:!0,scroll:!1},Rn={backdrop:"(boolean|string)",keyboard:"boolean",scroll:"boolean"};class qn extends W{constructor(t,e){super(t,e),this._isShown=!1,this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._addEventListeners()}static get Default(){return zn}static get DefaultType(){return Rn}static get NAME(){return"offcanvas"}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||N.trigger(this._element,Nn,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._backdrop.show(),this._config.scroll||(new cn).hide(),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.classList.add(Dn),this._queueCallback((()=>{this._config.scroll&&!this._config.backdrop||this._focustrap.activate(),this._element.classList.add(Sn),this._element.classList.remove(Dn),N.trigger(this._element,Pn,{relatedTarget:t})}),this._element,!0))}hide(){this._isShown&&(N.trigger(this._element,Mn).defaultPrevented||(this._focustrap.deactivate(),this._element.blur(),this._isShown=!1,this._element.classList.add($n),this._backdrop.hide(),this._queueCallback((()=>{this._element.classList.remove(Sn,$n),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._config.scroll||(new cn).reset(),N.trigger(this._element,Fn)}),this._element,!0)))}dispose(){this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}_initializeBackDrop(){const t=Boolean(this._config.backdrop);return new Ui({className:"offcanvas-backdrop",isVisible:t,isAnimated:!0,rootElement:this._element.parentNode,clickCallback:t?()=>{"static"!==this._config.backdrop?this.hide():N.trigger(this._element,jn)}:null})}_initializeFocusTrap(){return new sn({trapElement:this._element})}_addEventListeners(){N.on(this._element,Bn,(t=>{"Escape"===t.key&&(this._config.keyboard?this.hide():N.trigger(this._element,jn))}))}static jQueryInterface(t){return this.each((function(){const e=qn.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}N.on(document,Wn,'[data-bs-toggle="offcanvas"]',(function(t){const e=z.getElementFromSelector(this);if(["A","AREA"].includes(this.tagName)&&t.preventDefault(),l(this))return;N.one(e,Fn,(()=>{a(this)&&this.focus()}));const i=z.findOne(In);i&&i!==e&&qn.getInstance(i).hide(),qn.getOrCreateInstance(e).toggle(this)})),N.on(window,Ln,(()=>{for(const t of z.find(In))qn.getOrCreateInstance(t).show()})),N.on(window,Hn,(()=>{for(const t of z.find("[aria-modal][class*=show][class*=offcanvas-]"))"fixed"!==getComputedStyle(t).position&&qn.getOrCreateInstance(t).hide()})),R(qn),m(qn);const Vn={"*":["class","dir","id","lang","role",/^aria-[\w-]*$/i],a:["target","href","title","rel"],area:[],b:[],br:[],col:[],code:[],div:[],em:[],hr:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],i:[],img:["src","srcset","alt","title","width","height"],li:[],ol:[],p:[],pre:[],s:[],small:[],span:[],sub:[],sup:[],strong:[],u:[],ul:[]},Kn=new Set(["background","cite","href","itemtype","longdesc","poster","src","xlink:href"]),Qn=/^(?!javascript:)(?:[a-z0-9+.-]+:|[^&:/?#]*(?:[/?#]|$))/i,Xn=(t,e)=>{const i=t.nodeName.toLowerCase();return e.includes(i)?!Kn.has(i)||Boolean(Qn.test(t.nodeValue)):e.filter((t=>t instanceof RegExp)).some((t=>t.test(i)))},Yn={allowList:Vn,content:{},extraClass:"",html:!1,sanitize:!0,sanitizeFn:null,template:"
"},Un={allowList:"object",content:"object",extraClass:"(string|function)",html:"boolean",sanitize:"boolean",sanitizeFn:"(null|function)",template:"string"},Gn={entry:"(string|element|function|null)",selector:"(string|element)"};class Jn extends H{constructor(t){super(),this._config=this._getConfig(t)}static get Default(){return Yn}static get DefaultType(){return Un}static get NAME(){return"TemplateFactory"}getContent(){return Object.values(this._config.content).map((t=>this._resolvePossibleFunction(t))).filter(Boolean)}hasContent(){return this.getContent().length>0}changeContent(t){return this._checkContent(t),this._config.content={...this._config.content,...t},this}toHtml(){const t=document.createElement("div");t.innerHTML=this._maybeSanitize(this._config.template);for(const[e,i]of Object.entries(this._config.content))this._setContent(t,i,e);const e=t.children[0],i=this._resolvePossibleFunction(this._config.extraClass);return i&&e.classList.add(...i.split(" ")),e}_typeCheckConfig(t){super._typeCheckConfig(t),this._checkContent(t.content)}_checkContent(t){for(const[e,i]of Object.entries(t))super._typeCheckConfig({selector:e,entry:i},Gn)}_setContent(t,e,i){const n=z.findOne(i,t);n&&((e=this._resolvePossibleFunction(e))?o(e)?this._putElementInTemplate(r(e),n):this._config.html?n.innerHTML=this._maybeSanitize(e):n.textContent=e:n.remove())}_maybeSanitize(t){return this._config.sanitize?function(t,e,i){if(!t.length)return t;if(i&&"function"==typeof i)return i(t);const n=(new window.DOMParser).parseFromString(t,"text/html"),s=[].concat(...n.body.querySelectorAll("*"));for(const t of s){const i=t.nodeName.toLowerCase();if(!Object.keys(e).includes(i)){t.remove();continue}const n=[].concat(...t.attributes),s=[].concat(e["*"]||[],e[i]||[]);for(const e of n)Xn(e,s)||t.removeAttribute(e.nodeName)}return n.body.innerHTML}(t,this._config.allowList,this._config.sanitizeFn):t}_resolvePossibleFunction(t){return g(t,[this])}_putElementInTemplate(t,e){if(this._config.html)return e.innerHTML="",void e.append(t);e.textContent=t.textContent}}const Zn=new Set(["sanitize","allowList","sanitizeFn"]),ts="fade",es="show",is=".modal",ns="hide.bs.modal",ss="hover",os="focus",rs={AUTO:"auto",TOP:"top",RIGHT:p()?"left":"right",BOTTOM:"bottom",LEFT:p()?"right":"left"},as={allowList:Vn,animation:!0,boundary:"clippingParents",container:!1,customClass:"",delay:0,fallbackPlacements:["top","right","bottom","left"],html:!1,offset:[0,6],placement:"top",popperConfig:null,sanitize:!0,sanitizeFn:null,selector:!1,template:'',title:"",trigger:"hover focus"},ls={allowList:"object",animation:"boolean",boundary:"(string|element)",container:"(string|element|boolean)",customClass:"(string|function)",delay:"(number|object)",fallbackPlacements:"array",html:"boolean",offset:"(array|string|function)",placement:"(string|function)",popperConfig:"(null|object|function)",sanitize:"boolean",sanitizeFn:"(null|function)",selector:"(string|boolean)",template:"string",title:"(string|element|function)",trigger:"string"};class cs extends W{constructor(t,e){if(void 0===vi)throw new TypeError("Bootstrap's tooltips require Popper (https://popper.js.org)");super(t,e),this._isEnabled=!0,this._timeout=0,this._isHovered=null,this._activeTrigger={},this._popper=null,this._templateFactory=null,this._newContent=null,this.tip=null,this._setListeners(),this._config.selector||this._fixTitle()}static get Default(){return as}static get DefaultType(){return ls}static get NAME(){return"tooltip"}enable(){this._isEnabled=!0}disable(){this._isEnabled=!1}toggleEnabled(){this._isEnabled=!this._isEnabled}toggle(){this._isEnabled&&(this._activeTrigger.click=!this._activeTrigger.click,this._isShown()?this._leave():this._enter())}dispose(){clearTimeout(this._timeout),N.off(this._element.closest(is),ns,this._hideModalHandler),this._element.getAttribute("data-bs-original-title")&&this._element.setAttribute("title",this._element.getAttribute("data-bs-original-title")),this._disposePopper(),super.dispose()}show(){if("none"===this._element.style.display)throw new Error("Please use show on visible elements");if(!this._isWithContent()||!this._isEnabled)return;const t=N.trigger(this._element,this.constructor.eventName("show")),e=(c(this._element)||this._element.ownerDocument.documentElement).contains(this._element);if(t.defaultPrevented||!e)return;this._disposePopper();const i=this._getTipElement();this._element.setAttribute("aria-describedby",i.getAttribute("id"));const{container:n}=this._config;if(this._element.ownerDocument.documentElement.contains(this.tip)||(n.append(i),N.trigger(this._element,this.constructor.eventName("inserted"))),this._popper=this._createPopper(i),i.classList.add(es),"ontouchstart"in document.documentElement)for(const t of[].concat(...document.body.children))N.on(t,"mouseover",h);this._queueCallback((()=>{N.trigger(this._element,this.constructor.eventName("shown")),!1===this._isHovered&&this._leave(),this._isHovered=!1}),this.tip,this._isAnimated())}hide(){if(this._isShown()&&!N.trigger(this._element,this.constructor.eventName("hide")).defaultPrevented){if(this._getTipElement().classList.remove(es),"ontouchstart"in document.documentElement)for(const t of[].concat(...document.body.children))N.off(t,"mouseover",h);this._activeTrigger.click=!1,this._activeTrigger[os]=!1,this._activeTrigger[ss]=!1,this._isHovered=null,this._queueCallback((()=>{this._isWithActiveTrigger()||(this._isHovered||this._disposePopper(),this._element.removeAttribute("aria-describedby"),N.trigger(this._element,this.constructor.eventName("hidden")))}),this.tip,this._isAnimated())}}update(){this._popper&&this._popper.update()}_isWithContent(){return Boolean(this._getTitle())}_getTipElement(){return this.tip||(this.tip=this._createTipElement(this._newContent||this._getContentForTemplate())),this.tip}_createTipElement(t){const e=this._getTemplateFactory(t).toHtml();if(!e)return null;e.classList.remove(ts,es),e.classList.add(`bs-${this.constructor.NAME}-auto`);const i=(t=>{do{t+=Math.floor(1e6*Math.random())}while(document.getElementById(t));return t})(this.constructor.NAME).toString();return e.setAttribute("id",i),this._isAnimated()&&e.classList.add(ts),e}setContent(t){this._newContent=t,this._isShown()&&(this._disposePopper(),this.show())}_getTemplateFactory(t){return this._templateFactory?this._templateFactory.changeContent(t):this._templateFactory=new Jn({...this._config,content:t,extraClass:this._resolvePossibleFunction(this._config.customClass)}),this._templateFactory}_getContentForTemplate(){return{".tooltip-inner":this._getTitle()}}_getTitle(){return this._resolvePossibleFunction(this._config.title)||this._element.getAttribute("data-bs-original-title")}_initializeOnDelegatedTarget(t){return this.constructor.getOrCreateInstance(t.delegateTarget,this._getDelegateConfig())}_isAnimated(){return this._config.animation||this.tip&&this.tip.classList.contains(ts)}_isShown(){return this.tip&&this.tip.classList.contains(es)}_createPopper(t){const e=g(this._config.placement,[this,t,this._element]),i=rs[e.toUpperCase()];return bi(this._element,t,this._getPopperConfig(i))}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map((t=>Number.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_resolvePossibleFunction(t){return g(t,[this._element])}_getPopperConfig(t){const e={placement:t,modifiers:[{name:"flip",options:{fallbackPlacements:this._config.fallbackPlacements}},{name:"offset",options:{offset:this._getOffset()}},{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"arrow",options:{element:`.${this.constructor.NAME}-arrow`}},{name:"preSetPlacement",enabled:!0,phase:"beforeMain",fn:t=>{this._getTipElement().setAttribute("data-popper-placement",t.state.placement)}}]};return{...e,...g(this._config.popperConfig,[e])}}_setListeners(){const t=this._config.trigger.split(" ");for(const e of t)if("click"===e)N.on(this._element,this.constructor.eventName("click"),this._config.selector,(t=>{this._initializeOnDelegatedTarget(t).toggle()}));else if("manual"!==e){const t=e===ss?this.constructor.eventName("mouseenter"):this.constructor.eventName("focusin"),i=e===ss?this.constructor.eventName("mouseleave"):this.constructor.eventName("focusout");N.on(this._element,t,this._config.selector,(t=>{const e=this._initializeOnDelegatedTarget(t);e._activeTrigger["focusin"===t.type?os:ss]=!0,e._enter()})),N.on(this._element,i,this._config.selector,(t=>{const e=this._initializeOnDelegatedTarget(t);e._activeTrigger["focusout"===t.type?os:ss]=e._element.contains(t.relatedTarget),e._leave()}))}this._hideModalHandler=()=>{this._element&&this.hide()},N.on(this._element.closest(is),ns,this._hideModalHandler)}_fixTitle(){const t=this._element.getAttribute("title");t&&(this._element.getAttribute("aria-label")||this._element.textContent.trim()||this._element.setAttribute("aria-label",t),this._element.setAttribute("data-bs-original-title",t),this._element.removeAttribute("title"))}_enter(){this._isShown()||this._isHovered?this._isHovered=!0:(this._isHovered=!0,this._setTimeout((()=>{this._isHovered&&this.show()}),this._config.delay.show))}_leave(){this._isWithActiveTrigger()||(this._isHovered=!1,this._setTimeout((()=>{this._isHovered||this.hide()}),this._config.delay.hide))}_setTimeout(t,e){clearTimeout(this._timeout),this._timeout=setTimeout(t,e)}_isWithActiveTrigger(){return Object.values(this._activeTrigger).includes(!0)}_getConfig(t){const e=F.getDataAttributes(this._element);for(const t of Object.keys(e))Zn.has(t)&&delete e[t];return t={...e,..."object"==typeof t&&t?t:{}},t=this._mergeConfigObj(t),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}_configAfterMerge(t){return t.container=!1===t.container?document.body:r(t.container),"number"==typeof t.delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),t}_getDelegateConfig(){const t={};for(const[e,i]of Object.entries(this._config))this.constructor.Default[e]!==i&&(t[e]=i);return t.selector=!1,t.trigger="manual",t}_disposePopper(){this._popper&&(this._popper.destroy(),this._popper=null),this.tip&&(this.tip.remove(),this.tip=null)}static jQueryInterface(t){return this.each((function(){const e=cs.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}m(cs);const hs={...cs.Default,content:"",offset:[0,8],placement:"right",template:'',trigger:"click"},ds={...cs.DefaultType,content:"(null|string|element|function)"};class us extends cs{static get Default(){return hs}static get DefaultType(){return ds}static get NAME(){return"popover"}_isWithContent(){return this._getTitle()||this._getContent()}_getContentForTemplate(){return{".popover-header":this._getTitle(),".popover-body":this._getContent()}}_getContent(){return this._resolvePossibleFunction(this._config.content)}static jQueryInterface(t){return this.each((function(){const e=us.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}m(us);const fs=".bs.scrollspy",ps=`activate${fs}`,ms=`click${fs}`,gs=`load${fs}.data-api`,_s="active",bs="[href]",vs=".nav-link",ys=`${vs}, .nav-item > ${vs}, .list-group-item`,ws={offset:null,rootMargin:"0px 0px -25%",smoothScroll:!1,target:null,threshold:[.1,.5,1]},As={offset:"(number|null)",rootMargin:"string",smoothScroll:"boolean",target:"element",threshold:"array"};class Es extends W{constructor(t,e){super(t,e),this._targetLinks=new Map,this._observableSections=new Map,this._rootElement="visible"===getComputedStyle(this._element).overflowY?null:this._element,this._activeTarget=null,this._observer=null,this._previousScrollData={visibleEntryTop:0,parentScrollTop:0},this.refresh()}static get Default(){return ws}static get DefaultType(){return As}static get NAME(){return"scrollspy"}refresh(){this._initializeTargetsAndObservables(),this._maybeEnableSmoothScroll(),this._observer?this._observer.disconnect():this._observer=this._getNewObserver();for(const t of this._observableSections.values())this._observer.observe(t)}dispose(){this._observer.disconnect(),super.dispose()}_configAfterMerge(t){return t.target=r(t.target)||document.body,t.rootMargin=t.offset?`${t.offset}px 0px -30%`:t.rootMargin,"string"==typeof t.threshold&&(t.threshold=t.threshold.split(",").map((t=>Number.parseFloat(t)))),t}_maybeEnableSmoothScroll(){this._config.smoothScroll&&(N.off(this._config.target,ms),N.on(this._config.target,ms,bs,(t=>{const e=this._observableSections.get(t.target.hash);if(e){t.preventDefault();const i=this._rootElement||window,n=e.offsetTop-this._element.offsetTop;if(i.scrollTo)return void i.scrollTo({top:n,behavior:"smooth"});i.scrollTop=n}})))}_getNewObserver(){const t={root:this._rootElement,threshold:this._config.threshold,rootMargin:this._config.rootMargin};return new IntersectionObserver((t=>this._observerCallback(t)),t)}_observerCallback(t){const e=t=>this._targetLinks.get(`#${t.target.id}`),i=t=>{this._previousScrollData.visibleEntryTop=t.target.offsetTop,this._process(e(t))},n=(this._rootElement||document.documentElement).scrollTop,s=n>=this._previousScrollData.parentScrollTop;this._previousScrollData.parentScrollTop=n;for(const o of t){if(!o.isIntersecting){this._activeTarget=null,this._clearActiveClass(e(o));continue}const t=o.target.offsetTop>=this._previousScrollData.visibleEntryTop;if(s&&t){if(i(o),!n)return}else s||t||i(o)}}_initializeTargetsAndObservables(){this._targetLinks=new Map,this._observableSections=new Map;const t=z.find(bs,this._config.target);for(const e of t){if(!e.hash||l(e))continue;const t=z.findOne(decodeURI(e.hash),this._element);a(t)&&(this._targetLinks.set(decodeURI(e.hash),e),this._observableSections.set(e.hash,t))}}_process(t){this._activeTarget!==t&&(this._clearActiveClass(this._config.target),this._activeTarget=t,t.classList.add(_s),this._activateParents(t),N.trigger(this._element,ps,{relatedTarget:t}))}_activateParents(t){if(t.classList.contains("dropdown-item"))z.findOne(".dropdown-toggle",t.closest(".dropdown")).classList.add(_s);else for(const e of z.parents(t,".nav, .list-group"))for(const t of z.prev(e,ys))t.classList.add(_s)}_clearActiveClass(t){t.classList.remove(_s);const e=z.find(`${bs}.${_s}`,t);for(const t of e)t.classList.remove(_s)}static jQueryInterface(t){return this.each((function(){const e=Es.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}))}}N.on(window,gs,(()=>{for(const t of z.find('[data-bs-spy="scroll"]'))Es.getOrCreateInstance(t)})),m(Es);const Ts=".bs.tab",Cs=`hide${Ts}`,Os=`hidden${Ts}`,xs=`show${Ts}`,ks=`shown${Ts}`,Ls=`click${Ts}`,Ss=`keydown${Ts}`,Ds=`load${Ts}`,$s="ArrowLeft",Is="ArrowRight",Ns="ArrowUp",Ps="ArrowDown",Ms="Home",js="End",Fs="active",Hs="fade",Ws="show",Bs=":not(.dropdown-toggle)",zs='[data-bs-toggle="tab"], [data-bs-toggle="pill"], [data-bs-toggle="list"]',Rs=`.nav-link${Bs}, .list-group-item${Bs}, [role="tab"]${Bs}, ${zs}`,qs=`.${Fs}[data-bs-toggle="tab"], .${Fs}[data-bs-toggle="pill"], .${Fs}[data-bs-toggle="list"]`;class Vs extends W{constructor(t){super(t),this._parent=this._element.closest('.list-group, .nav, [role="tablist"]'),this._parent&&(this._setInitialAttributes(this._parent,this._getChildren()),N.on(this._element,Ss,(t=>this._keydown(t))))}static get NAME(){return"tab"}show(){const t=this._element;if(this._elemIsActive(t))return;const e=this._getActiveElem(),i=e?N.trigger(e,Cs,{relatedTarget:t}):null;N.trigger(t,xs,{relatedTarget:e}).defaultPrevented||i&&i.defaultPrevented||(this._deactivate(e,t),this._activate(t,e))}_activate(t,e){t&&(t.classList.add(Fs),this._activate(z.getElementFromSelector(t)),this._queueCallback((()=>{"tab"===t.getAttribute("role")?(t.removeAttribute("tabindex"),t.setAttribute("aria-selected",!0),this._toggleDropDown(t,!0),N.trigger(t,ks,{relatedTarget:e})):t.classList.add(Ws)}),t,t.classList.contains(Hs)))}_deactivate(t,e){t&&(t.classList.remove(Fs),t.blur(),this._deactivate(z.getElementFromSelector(t)),this._queueCallback((()=>{"tab"===t.getAttribute("role")?(t.setAttribute("aria-selected",!1),t.setAttribute("tabindex","-1"),this._toggleDropDown(t,!1),N.trigger(t,Os,{relatedTarget:e})):t.classList.remove(Ws)}),t,t.classList.contains(Hs)))}_keydown(t){if(![$s,Is,Ns,Ps,Ms,js].includes(t.key))return;t.stopPropagation(),t.preventDefault();const e=this._getChildren().filter((t=>!l(t)));let i;if([Ms,js].includes(t.key))i=e[t.key===Ms?0:e.length-1];else{const n=[Is,Ps].includes(t.key);i=b(e,t.target,n,!0)}i&&(i.focus({preventScroll:!0}),Vs.getOrCreateInstance(i).show())}_getChildren(){return z.find(Rs,this._parent)}_getActiveElem(){return this._getChildren().find((t=>this._elemIsActive(t)))||null}_setInitialAttributes(t,e){this._setAttributeIfNotExists(t,"role","tablist");for(const t of e)this._setInitialAttributesOnChild(t)}_setInitialAttributesOnChild(t){t=this._getInnerElement(t);const e=this._elemIsActive(t),i=this._getOuterElement(t);t.setAttribute("aria-selected",e),i!==t&&this._setAttributeIfNotExists(i,"role","presentation"),e||t.setAttribute("tabindex","-1"),this._setAttributeIfNotExists(t,"role","tab"),this._setInitialAttributesOnTargetPanel(t)}_setInitialAttributesOnTargetPanel(t){const e=z.getElementFromSelector(t);e&&(this._setAttributeIfNotExists(e,"role","tabpanel"),t.id&&this._setAttributeIfNotExists(e,"aria-labelledby",`${t.id}`))}_toggleDropDown(t,e){const i=this._getOuterElement(t);if(!i.classList.contains("dropdown"))return;const n=(t,n)=>{const s=z.findOne(t,i);s&&s.classList.toggle(n,e)};n(".dropdown-toggle",Fs),n(".dropdown-menu",Ws),i.setAttribute("aria-expanded",e)}_setAttributeIfNotExists(t,e,i){t.hasAttribute(e)||t.setAttribute(e,i)}_elemIsActive(t){return t.classList.contains(Fs)}_getInnerElement(t){return t.matches(Rs)?t:z.findOne(Rs,t)}_getOuterElement(t){return t.closest(".nav-item, .list-group-item")||t}static jQueryInterface(t){return this.each((function(){const e=Vs.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}))}}N.on(document,Ls,zs,(function(t){["A","AREA"].includes(this.tagName)&&t.preventDefault(),l(this)||Vs.getOrCreateInstance(this).show()})),N.on(window,Ds,(()=>{for(const t of z.find(qs))Vs.getOrCreateInstance(t)})),m(Vs);const Ks=".bs.toast",Qs=`mouseover${Ks}`,Xs=`mouseout${Ks}`,Ys=`focusin${Ks}`,Us=`focusout${Ks}`,Gs=`hide${Ks}`,Js=`hidden${Ks}`,Zs=`show${Ks}`,to=`shown${Ks}`,eo="hide",io="show",no="showing",so={animation:"boolean",autohide:"boolean",delay:"number"},oo={animation:!0,autohide:!0,delay:5e3};class ro extends W{constructor(t,e){super(t,e),this._timeout=null,this._hasMouseInteraction=!1,this._hasKeyboardInteraction=!1,this._setListeners()}static get Default(){return oo}static get DefaultType(){return so}static get NAME(){return"toast"}show(){N.trigger(this._element,Zs).defaultPrevented||(this._clearTimeout(),this._config.animation&&this._element.classList.add("fade"),this._element.classList.remove(eo),d(this._element),this._element.classList.add(io,no),this._queueCallback((()=>{this._element.classList.remove(no),N.trigger(this._element,to),this._maybeScheduleHide()}),this._element,this._config.animation))}hide(){this.isShown()&&(N.trigger(this._element,Gs).defaultPrevented||(this._element.classList.add(no),this._queueCallback((()=>{this._element.classList.add(eo),this._element.classList.remove(no,io),N.trigger(this._element,Js)}),this._element,this._config.animation)))}dispose(){this._clearTimeout(),this.isShown()&&this._element.classList.remove(io),super.dispose()}isShown(){return this._element.classList.contains(io)}_maybeScheduleHide(){this._config.autohide&&(this._hasMouseInteraction||this._hasKeyboardInteraction||(this._timeout=setTimeout((()=>{this.hide()}),this._config.delay)))}_onInteraction(t,e){switch(t.type){case"mouseover":case"mouseout":this._hasMouseInteraction=e;break;case"focusin":case"focusout":this._hasKeyboardInteraction=e}if(e)return void this._clearTimeout();const i=t.relatedTarget;this._element===i||this._element.contains(i)||this._maybeScheduleHide()}_setListeners(){N.on(this._element,Qs,(t=>this._onInteraction(t,!0))),N.on(this._element,Xs,(t=>this._onInteraction(t,!1))),N.on(this._element,Ys,(t=>this._onInteraction(t,!0))),N.on(this._element,Us,(t=>this._onInteraction(t,!1)))}_clearTimeout(){clearTimeout(this._timeout),this._timeout=null}static jQueryInterface(t){return this.each((function(){const e=ro.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}return R(ro),m(ro),{Alert:Q,Button:Y,Carousel:xt,Collapse:Bt,Dropdown:qi,Modal:On,Offcanvas:qn,Popover:us,ScrollSpy:Es,Tab:Vs,Toast:ro,Tooltip:cs}})); -//# sourceMappingURL=bootstrap.bundle.min.js.map \ No newline at end of file diff --git a/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/run_pecan_files/libs/clipboard/clipboard.min.js b/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/run_pecan_files/libs/clipboard/clipboard.min.js deleted file mode 100644 index 1103f811e..000000000 --- a/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/run_pecan_files/libs/clipboard/clipboard.min.js +++ /dev/null @@ -1,7 +0,0 @@ -/*! - * clipboard.js v2.0.11 - * https://clipboardjs.com/ - * - * Licensed MIT © Zeno Rocha - */ -!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ClipboardJS=e():t.ClipboardJS=e()}(this,function(){return n={686:function(t,e,n){"use strict";n.d(e,{default:function(){return b}});var e=n(279),i=n.n(e),e=n(370),u=n.n(e),e=n(817),r=n.n(e);function c(t){try{return document.execCommand(t)}catch(t){return}}var a=function(t){t=r()(t);return c("cut"),t};function o(t,e){var n,o,t=(n=t,o="rtl"===document.documentElement.getAttribute("dir"),(t=document.createElement("textarea")).style.fontSize="12pt",t.style.border="0",t.style.padding="0",t.style.margin="0",t.style.position="absolute",t.style[o?"right":"left"]="-9999px",o=window.pageYOffset||document.documentElement.scrollTop,t.style.top="".concat(o,"px"),t.setAttribute("readonly",""),t.value=n,t);return e.container.appendChild(t),e=r()(t),c("copy"),t.remove(),e}var f=function(t){var e=1.anchorjs-link,.anchorjs-link:focus{opacity:1}",A.sheet.cssRules.length),A.sheet.insertRule("[data-anchorjs-icon]::after{content:attr(data-anchorjs-icon)}",A.sheet.cssRules.length),A.sheet.insertRule('@font-face{font-family:anchorjs-icons;src:url(data:n/a;base64,AAEAAAALAIAAAwAwT1MvMg8yG2cAAAE4AAAAYGNtYXDp3gC3AAABpAAAAExnYXNwAAAAEAAAA9wAAAAIZ2x5ZlQCcfwAAAH4AAABCGhlYWQHFvHyAAAAvAAAADZoaGVhBnACFwAAAPQAAAAkaG10eASAADEAAAGYAAAADGxvY2EACACEAAAB8AAAAAhtYXhwAAYAVwAAARgAAAAgbmFtZQGOH9cAAAMAAAAAunBvc3QAAwAAAAADvAAAACAAAQAAAAEAAHzE2p9fDzz1AAkEAAAAAADRecUWAAAAANQA6R8AAAAAAoACwAAAAAgAAgAAAAAAAAABAAADwP/AAAACgAAA/9MCrQABAAAAAAAAAAAAAAAAAAAAAwABAAAAAwBVAAIAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAMCQAGQAAUAAAKZAswAAACPApkCzAAAAesAMwEJAAAAAAAAAAAAAAAAAAAAARAAAAAAAAAAAAAAAAAAAAAAQAAg//0DwP/AAEADwABAAAAAAQAAAAAAAAAAAAAAIAAAAAAAAAIAAAACgAAxAAAAAwAAAAMAAAAcAAEAAwAAABwAAwABAAAAHAAEADAAAAAIAAgAAgAAACDpy//9//8AAAAg6cv//f///+EWNwADAAEAAAAAAAAAAAAAAAAACACEAAEAAAAAAAAAAAAAAAAxAAACAAQARAKAAsAAKwBUAAABIiYnJjQ3NzY2MzIWFxYUBwcGIicmNDc3NjQnJiYjIgYHBwYUFxYUBwYGIwciJicmNDc3NjIXFhQHBwYUFxYWMzI2Nzc2NCcmNDc2MhcWFAcHBgYjARQGDAUtLXoWOR8fORYtLTgKGwoKCjgaGg0gEhIgDXoaGgkJBQwHdR85Fi0tOAobCgoKOBoaDSASEiANehoaCQkKGwotLXoWOR8BMwUFLYEuehYXFxYugC44CQkKGwo4GkoaDQ0NDXoaShoKGwoFBe8XFi6ALjgJCQobCjgaShoNDQ0NehpKGgobCgoKLYEuehYXAAAADACWAAEAAAAAAAEACAAAAAEAAAAAAAIAAwAIAAEAAAAAAAMACAAAAAEAAAAAAAQACAAAAAEAAAAAAAUAAQALAAEAAAAAAAYACAAAAAMAAQQJAAEAEAAMAAMAAQQJAAIABgAcAAMAAQQJAAMAEAAMAAMAAQQJAAQAEAAMAAMAAQQJAAUAAgAiAAMAAQQJAAYAEAAMYW5jaG9yanM0MDBAAGEAbgBjAGgAbwByAGoAcwA0ADAAMABAAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAH//wAP) format("truetype")}',A.sheet.cssRules.length)),h=document.querySelectorAll("[id]"),t=[].map.call(h,function(A){return A.id}),i=0;i\]./()*\\\n\t\b\v\u00A0]/g,"-").replace(/-{2,}/g,"-").substring(0,this.options.truncate).replace(/^-+|-+$/gm,"").toLowerCase()},this.hasAnchorJSLink=function(A){var e=A.firstChild&&-1<(" "+A.firstChild.className+" ").indexOf(" anchorjs-link "),A=A.lastChild&&-1<(" "+A.lastChild.className+" ").indexOf(" anchorjs-link ");return e||A||!1}}}); -// @license-end \ No newline at end of file diff --git a/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/run_pecan_files/libs/quarto-html/popper.min.js b/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/run_pecan_files/libs/quarto-html/popper.min.js deleted file mode 100644 index e3726d728..000000000 --- a/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/run_pecan_files/libs/quarto-html/popper.min.js +++ /dev/null @@ -1,6 +0,0 @@ -/** - * @popperjs/core v2.11.7 - MIT License - */ - -!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).Popper={})}(this,(function(e){"use strict";function t(e){if(null==e)return window;if("[object Window]"!==e.toString()){var t=e.ownerDocument;return t&&t.defaultView||window}return e}function n(e){return e instanceof t(e).Element||e instanceof Element}function r(e){return e instanceof t(e).HTMLElement||e instanceof HTMLElement}function o(e){return"undefined"!=typeof ShadowRoot&&(e instanceof t(e).ShadowRoot||e instanceof ShadowRoot)}var i=Math.max,a=Math.min,s=Math.round;function f(){var e=navigator.userAgentData;return null!=e&&e.brands&&Array.isArray(e.brands)?e.brands.map((function(e){return e.brand+"/"+e.version})).join(" "):navigator.userAgent}function c(){return!/^((?!chrome|android).)*safari/i.test(f())}function p(e,o,i){void 0===o&&(o=!1),void 0===i&&(i=!1);var a=e.getBoundingClientRect(),f=1,p=1;o&&r(e)&&(f=e.offsetWidth>0&&s(a.width)/e.offsetWidth||1,p=e.offsetHeight>0&&s(a.height)/e.offsetHeight||1);var u=(n(e)?t(e):window).visualViewport,l=!c()&&i,d=(a.left+(l&&u?u.offsetLeft:0))/f,h=(a.top+(l&&u?u.offsetTop:0))/p,m=a.width/f,v=a.height/p;return{width:m,height:v,top:h,right:d+m,bottom:h+v,left:d,x:d,y:h}}function u(e){var n=t(e);return{scrollLeft:n.pageXOffset,scrollTop:n.pageYOffset}}function l(e){return e?(e.nodeName||"").toLowerCase():null}function d(e){return((n(e)?e.ownerDocument:e.document)||window.document).documentElement}function h(e){return p(d(e)).left+u(e).scrollLeft}function m(e){return t(e).getComputedStyle(e)}function v(e){var t=m(e),n=t.overflow,r=t.overflowX,o=t.overflowY;return/auto|scroll|overlay|hidden/.test(n+o+r)}function y(e,n,o){void 0===o&&(o=!1);var i,a,f=r(n),c=r(n)&&function(e){var t=e.getBoundingClientRect(),n=s(t.width)/e.offsetWidth||1,r=s(t.height)/e.offsetHeight||1;return 1!==n||1!==r}(n),m=d(n),y=p(e,c,o),g={scrollLeft:0,scrollTop:0},b={x:0,y:0};return(f||!f&&!o)&&(("body"!==l(n)||v(m))&&(g=(i=n)!==t(i)&&r(i)?{scrollLeft:(a=i).scrollLeft,scrollTop:a.scrollTop}:u(i)),r(n)?((b=p(n,!0)).x+=n.clientLeft,b.y+=n.clientTop):m&&(b.x=h(m))),{x:y.left+g.scrollLeft-b.x,y:y.top+g.scrollTop-b.y,width:y.width,height:y.height}}function g(e){var t=p(e),n=e.offsetWidth,r=e.offsetHeight;return Math.abs(t.width-n)<=1&&(n=t.width),Math.abs(t.height-r)<=1&&(r=t.height),{x:e.offsetLeft,y:e.offsetTop,width:n,height:r}}function b(e){return"html"===l(e)?e:e.assignedSlot||e.parentNode||(o(e)?e.host:null)||d(e)}function x(e){return["html","body","#document"].indexOf(l(e))>=0?e.ownerDocument.body:r(e)&&v(e)?e:x(b(e))}function w(e,n){var r;void 0===n&&(n=[]);var o=x(e),i=o===(null==(r=e.ownerDocument)?void 0:r.body),a=t(o),s=i?[a].concat(a.visualViewport||[],v(o)?o:[]):o,f=n.concat(s);return i?f:f.concat(w(b(s)))}function O(e){return["table","td","th"].indexOf(l(e))>=0}function j(e){return r(e)&&"fixed"!==m(e).position?e.offsetParent:null}function E(e){for(var n=t(e),i=j(e);i&&O(i)&&"static"===m(i).position;)i=j(i);return i&&("html"===l(i)||"body"===l(i)&&"static"===m(i).position)?n:i||function(e){var t=/firefox/i.test(f());if(/Trident/i.test(f())&&r(e)&&"fixed"===m(e).position)return null;var n=b(e);for(o(n)&&(n=n.host);r(n)&&["html","body"].indexOf(l(n))<0;){var i=m(n);if("none"!==i.transform||"none"!==i.perspective||"paint"===i.contain||-1!==["transform","perspective"].indexOf(i.willChange)||t&&"filter"===i.willChange||t&&i.filter&&"none"!==i.filter)return n;n=n.parentNode}return null}(e)||n}var D="top",A="bottom",L="right",P="left",M="auto",k=[D,A,L,P],W="start",B="end",H="viewport",T="popper",R=k.reduce((function(e,t){return e.concat([t+"-"+W,t+"-"+B])}),[]),S=[].concat(k,[M]).reduce((function(e,t){return e.concat([t,t+"-"+W,t+"-"+B])}),[]),V=["beforeRead","read","afterRead","beforeMain","main","afterMain","beforeWrite","write","afterWrite"];function q(e){var t=new Map,n=new Set,r=[];function o(e){n.add(e.name),[].concat(e.requires||[],e.requiresIfExists||[]).forEach((function(e){if(!n.has(e)){var r=t.get(e);r&&o(r)}})),r.push(e)}return e.forEach((function(e){t.set(e.name,e)})),e.forEach((function(e){n.has(e.name)||o(e)})),r}function C(e){return e.split("-")[0]}function N(e,t){var n=t.getRootNode&&t.getRootNode();if(e.contains(t))return!0;if(n&&o(n)){var r=t;do{if(r&&e.isSameNode(r))return!0;r=r.parentNode||r.host}while(r)}return!1}function I(e){return Object.assign({},e,{left:e.x,top:e.y,right:e.x+e.width,bottom:e.y+e.height})}function _(e,r,o){return r===H?I(function(e,n){var r=t(e),o=d(e),i=r.visualViewport,a=o.clientWidth,s=o.clientHeight,f=0,p=0;if(i){a=i.width,s=i.height;var u=c();(u||!u&&"fixed"===n)&&(f=i.offsetLeft,p=i.offsetTop)}return{width:a,height:s,x:f+h(e),y:p}}(e,o)):n(r)?function(e,t){var n=p(e,!1,"fixed"===t);return n.top=n.top+e.clientTop,n.left=n.left+e.clientLeft,n.bottom=n.top+e.clientHeight,n.right=n.left+e.clientWidth,n.width=e.clientWidth,n.height=e.clientHeight,n.x=n.left,n.y=n.top,n}(r,o):I(function(e){var t,n=d(e),r=u(e),o=null==(t=e.ownerDocument)?void 0:t.body,a=i(n.scrollWidth,n.clientWidth,o?o.scrollWidth:0,o?o.clientWidth:0),s=i(n.scrollHeight,n.clientHeight,o?o.scrollHeight:0,o?o.clientHeight:0),f=-r.scrollLeft+h(e),c=-r.scrollTop;return"rtl"===m(o||n).direction&&(f+=i(n.clientWidth,o?o.clientWidth:0)-a),{width:a,height:s,x:f,y:c}}(d(e)))}function F(e,t,o,s){var f="clippingParents"===t?function(e){var t=w(b(e)),o=["absolute","fixed"].indexOf(m(e).position)>=0&&r(e)?E(e):e;return n(o)?t.filter((function(e){return n(e)&&N(e,o)&&"body"!==l(e)})):[]}(e):[].concat(t),c=[].concat(f,[o]),p=c[0],u=c.reduce((function(t,n){var r=_(e,n,s);return t.top=i(r.top,t.top),t.right=a(r.right,t.right),t.bottom=a(r.bottom,t.bottom),t.left=i(r.left,t.left),t}),_(e,p,s));return u.width=u.right-u.left,u.height=u.bottom-u.top,u.x=u.left,u.y=u.top,u}function U(e){return e.split("-")[1]}function z(e){return["top","bottom"].indexOf(e)>=0?"x":"y"}function X(e){var t,n=e.reference,r=e.element,o=e.placement,i=o?C(o):null,a=o?U(o):null,s=n.x+n.width/2-r.width/2,f=n.y+n.height/2-r.height/2;switch(i){case D:t={x:s,y:n.y-r.height};break;case A:t={x:s,y:n.y+n.height};break;case L:t={x:n.x+n.width,y:f};break;case P:t={x:n.x-r.width,y:f};break;default:t={x:n.x,y:n.y}}var c=i?z(i):null;if(null!=c){var p="y"===c?"height":"width";switch(a){case W:t[c]=t[c]-(n[p]/2-r[p]/2);break;case B:t[c]=t[c]+(n[p]/2-r[p]/2)}}return t}function Y(e){return Object.assign({},{top:0,right:0,bottom:0,left:0},e)}function G(e,t){return t.reduce((function(t,n){return t[n]=e,t}),{})}function J(e,t){void 0===t&&(t={});var r=t,o=r.placement,i=void 0===o?e.placement:o,a=r.strategy,s=void 0===a?e.strategy:a,f=r.boundary,c=void 0===f?"clippingParents":f,u=r.rootBoundary,l=void 0===u?H:u,h=r.elementContext,m=void 0===h?T:h,v=r.altBoundary,y=void 0!==v&&v,g=r.padding,b=void 0===g?0:g,x=Y("number"!=typeof b?b:G(b,k)),w=m===T?"reference":T,O=e.rects.popper,j=e.elements[y?w:m],E=F(n(j)?j:j.contextElement||d(e.elements.popper),c,l,s),P=p(e.elements.reference),M=X({reference:P,element:O,strategy:"absolute",placement:i}),W=I(Object.assign({},O,M)),B=m===T?W:P,R={top:E.top-B.top+x.top,bottom:B.bottom-E.bottom+x.bottom,left:E.left-B.left+x.left,right:B.right-E.right+x.right},S=e.modifiersData.offset;if(m===T&&S){var V=S[i];Object.keys(R).forEach((function(e){var t=[L,A].indexOf(e)>=0?1:-1,n=[D,A].indexOf(e)>=0?"y":"x";R[e]+=V[n]*t}))}return R}var K={placement:"bottom",modifiers:[],strategy:"absolute"};function Q(){for(var e=arguments.length,t=new Array(e),n=0;n=0?-1:1,i="function"==typeof n?n(Object.assign({},t,{placement:e})):n,a=i[0],s=i[1];return a=a||0,s=(s||0)*o,[P,L].indexOf(r)>=0?{x:s,y:a}:{x:a,y:s}}(n,t.rects,i),e}),{}),s=a[t.placement],f=s.x,c=s.y;null!=t.modifiersData.popperOffsets&&(t.modifiersData.popperOffsets.x+=f,t.modifiersData.popperOffsets.y+=c),t.modifiersData[r]=a}},se={left:"right",right:"left",bottom:"top",top:"bottom"};function fe(e){return e.replace(/left|right|bottom|top/g,(function(e){return se[e]}))}var ce={start:"end",end:"start"};function pe(e){return e.replace(/start|end/g,(function(e){return ce[e]}))}function ue(e,t){void 0===t&&(t={});var n=t,r=n.placement,o=n.boundary,i=n.rootBoundary,a=n.padding,s=n.flipVariations,f=n.allowedAutoPlacements,c=void 0===f?S:f,p=U(r),u=p?s?R:R.filter((function(e){return U(e)===p})):k,l=u.filter((function(e){return c.indexOf(e)>=0}));0===l.length&&(l=u);var d=l.reduce((function(t,n){return t[n]=J(e,{placement:n,boundary:o,rootBoundary:i,padding:a})[C(n)],t}),{});return Object.keys(d).sort((function(e,t){return d[e]-d[t]}))}var le={name:"flip",enabled:!0,phase:"main",fn:function(e){var t=e.state,n=e.options,r=e.name;if(!t.modifiersData[r]._skip){for(var o=n.mainAxis,i=void 0===o||o,a=n.altAxis,s=void 0===a||a,f=n.fallbackPlacements,c=n.padding,p=n.boundary,u=n.rootBoundary,l=n.altBoundary,d=n.flipVariations,h=void 0===d||d,m=n.allowedAutoPlacements,v=t.options.placement,y=C(v),g=f||(y===v||!h?[fe(v)]:function(e){if(C(e)===M)return[];var t=fe(e);return[pe(e),t,pe(t)]}(v)),b=[v].concat(g).reduce((function(e,n){return e.concat(C(n)===M?ue(t,{placement:n,boundary:p,rootBoundary:u,padding:c,flipVariations:h,allowedAutoPlacements:m}):n)}),[]),x=t.rects.reference,w=t.rects.popper,O=new Map,j=!0,E=b[0],k=0;k=0,S=R?"width":"height",V=J(t,{placement:B,boundary:p,rootBoundary:u,altBoundary:l,padding:c}),q=R?T?L:P:T?A:D;x[S]>w[S]&&(q=fe(q));var N=fe(q),I=[];if(i&&I.push(V[H]<=0),s&&I.push(V[q]<=0,V[N]<=0),I.every((function(e){return e}))){E=B,j=!1;break}O.set(B,I)}if(j)for(var _=function(e){var t=b.find((function(t){var n=O.get(t);if(n)return n.slice(0,e).every((function(e){return e}))}));if(t)return E=t,"break"},F=h?3:1;F>0;F--){if("break"===_(F))break}t.placement!==E&&(t.modifiersData[r]._skip=!0,t.placement=E,t.reset=!0)}},requiresIfExists:["offset"],data:{_skip:!1}};function de(e,t,n){return i(e,a(t,n))}var he={name:"preventOverflow",enabled:!0,phase:"main",fn:function(e){var t=e.state,n=e.options,r=e.name,o=n.mainAxis,s=void 0===o||o,f=n.altAxis,c=void 0!==f&&f,p=n.boundary,u=n.rootBoundary,l=n.altBoundary,d=n.padding,h=n.tether,m=void 0===h||h,v=n.tetherOffset,y=void 0===v?0:v,b=J(t,{boundary:p,rootBoundary:u,padding:d,altBoundary:l}),x=C(t.placement),w=U(t.placement),O=!w,j=z(x),M="x"===j?"y":"x",k=t.modifiersData.popperOffsets,B=t.rects.reference,H=t.rects.popper,T="function"==typeof y?y(Object.assign({},t.rects,{placement:t.placement})):y,R="number"==typeof T?{mainAxis:T,altAxis:T}:Object.assign({mainAxis:0,altAxis:0},T),S=t.modifiersData.offset?t.modifiersData.offset[t.placement]:null,V={x:0,y:0};if(k){if(s){var q,N="y"===j?D:P,I="y"===j?A:L,_="y"===j?"height":"width",F=k[j],X=F+b[N],Y=F-b[I],G=m?-H[_]/2:0,K=w===W?B[_]:H[_],Q=w===W?-H[_]:-B[_],Z=t.elements.arrow,$=m&&Z?g(Z):{width:0,height:0},ee=t.modifiersData["arrow#persistent"]?t.modifiersData["arrow#persistent"].padding:{top:0,right:0,bottom:0,left:0},te=ee[N],ne=ee[I],re=de(0,B[_],$[_]),oe=O?B[_]/2-G-re-te-R.mainAxis:K-re-te-R.mainAxis,ie=O?-B[_]/2+G+re+ne+R.mainAxis:Q+re+ne+R.mainAxis,ae=t.elements.arrow&&E(t.elements.arrow),se=ae?"y"===j?ae.clientTop||0:ae.clientLeft||0:0,fe=null!=(q=null==S?void 0:S[j])?q:0,ce=F+ie-fe,pe=de(m?a(X,F+oe-fe-se):X,F,m?i(Y,ce):Y);k[j]=pe,V[j]=pe-F}if(c){var ue,le="x"===j?D:P,he="x"===j?A:L,me=k[M],ve="y"===M?"height":"width",ye=me+b[le],ge=me-b[he],be=-1!==[D,P].indexOf(x),xe=null!=(ue=null==S?void 0:S[M])?ue:0,we=be?ye:me-B[ve]-H[ve]-xe+R.altAxis,Oe=be?me+B[ve]+H[ve]-xe-R.altAxis:ge,je=m&&be?function(e,t,n){var r=de(e,t,n);return r>n?n:r}(we,me,Oe):de(m?we:ye,me,m?Oe:ge);k[M]=je,V[M]=je-me}t.modifiersData[r]=V}},requiresIfExists:["offset"]};var me={name:"arrow",enabled:!0,phase:"main",fn:function(e){var t,n=e.state,r=e.name,o=e.options,i=n.elements.arrow,a=n.modifiersData.popperOffsets,s=C(n.placement),f=z(s),c=[P,L].indexOf(s)>=0?"height":"width";if(i&&a){var p=function(e,t){return Y("number"!=typeof(e="function"==typeof e?e(Object.assign({},t.rects,{placement:t.placement})):e)?e:G(e,k))}(o.padding,n),u=g(i),l="y"===f?D:P,d="y"===f?A:L,h=n.rects.reference[c]+n.rects.reference[f]-a[f]-n.rects.popper[c],m=a[f]-n.rects.reference[f],v=E(i),y=v?"y"===f?v.clientHeight||0:v.clientWidth||0:0,b=h/2-m/2,x=p[l],w=y-u[c]-p[d],O=y/2-u[c]/2+b,j=de(x,O,w),M=f;n.modifiersData[r]=((t={})[M]=j,t.centerOffset=j-O,t)}},effect:function(e){var t=e.state,n=e.options.element,r=void 0===n?"[data-popper-arrow]":n;null!=r&&("string"!=typeof r||(r=t.elements.popper.querySelector(r)))&&N(t.elements.popper,r)&&(t.elements.arrow=r)},requires:["popperOffsets"],requiresIfExists:["preventOverflow"]};function ve(e,t,n){return void 0===n&&(n={x:0,y:0}),{top:e.top-t.height-n.y,right:e.right-t.width+n.x,bottom:e.bottom-t.height+n.y,left:e.left-t.width-n.x}}function ye(e){return[D,L,A,P].some((function(t){return e[t]>=0}))}var ge={name:"hide",enabled:!0,phase:"main",requiresIfExists:["preventOverflow"],fn:function(e){var t=e.state,n=e.name,r=t.rects.reference,o=t.rects.popper,i=t.modifiersData.preventOverflow,a=J(t,{elementContext:"reference"}),s=J(t,{altBoundary:!0}),f=ve(a,r),c=ve(s,o,i),p=ye(f),u=ye(c);t.modifiersData[n]={referenceClippingOffsets:f,popperEscapeOffsets:c,isReferenceHidden:p,hasPopperEscaped:u},t.attributes.popper=Object.assign({},t.attributes.popper,{"data-popper-reference-hidden":p,"data-popper-escaped":u})}},be=Z({defaultModifiers:[ee,te,oe,ie]}),xe=[ee,te,oe,ie,ae,le,he,me,ge],we=Z({defaultModifiers:xe});e.applyStyles=ie,e.arrow=me,e.computeStyles=oe,e.createPopper=we,e.createPopperLite=be,e.defaultModifiers=xe,e.detectOverflow=J,e.eventListeners=ee,e.flip=le,e.hide=ge,e.offset=ae,e.popperGenerator=Z,e.popperOffsets=te,e.preventOverflow=he,Object.defineProperty(e,"__esModule",{value:!0})})); - diff --git a/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/run_pecan_files/libs/quarto-html/quarto-syntax-highlighting.css b/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/run_pecan_files/libs/quarto-html/quarto-syntax-highlighting.css deleted file mode 100644 index b30ce5766..000000000 --- a/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/run_pecan_files/libs/quarto-html/quarto-syntax-highlighting.css +++ /dev/null @@ -1,205 +0,0 @@ -/* quarto syntax highlight colors */ -:root { - --quarto-hl-ot-color: #003B4F; - --quarto-hl-at-color: #657422; - --quarto-hl-ss-color: #20794D; - --quarto-hl-an-color: #5E5E5E; - --quarto-hl-fu-color: #4758AB; - --quarto-hl-st-color: #20794D; - --quarto-hl-cf-color: #003B4F; - --quarto-hl-op-color: #5E5E5E; - --quarto-hl-er-color: #AD0000; - --quarto-hl-bn-color: #AD0000; - --quarto-hl-al-color: #AD0000; - --quarto-hl-va-color: #111111; - --quarto-hl-bu-color: inherit; - --quarto-hl-ex-color: inherit; - --quarto-hl-pp-color: #AD0000; - --quarto-hl-in-color: #5E5E5E; - --quarto-hl-vs-color: #20794D; - --quarto-hl-wa-color: #5E5E5E; - --quarto-hl-do-color: #5E5E5E; - --quarto-hl-im-color: #00769E; - --quarto-hl-ch-color: #20794D; - --quarto-hl-dt-color: #AD0000; - --quarto-hl-fl-color: #AD0000; - --quarto-hl-co-color: #5E5E5E; - --quarto-hl-cv-color: #5E5E5E; - --quarto-hl-cn-color: #8f5902; - --quarto-hl-sc-color: #5E5E5E; - --quarto-hl-dv-color: #AD0000; - --quarto-hl-kw-color: #003B4F; -} - -/* other quarto variables */ -:root { - --quarto-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; -} - -pre > code.sourceCode > span { - color: #003B4F; -} - -code span { - color: #003B4F; -} - -code.sourceCode > span { - color: #003B4F; -} - -div.sourceCode, -div.sourceCode pre.sourceCode { - color: #003B4F; -} - -code span.ot { - color: #003B4F; - font-style: inherit; -} - -code span.at { - color: #657422; - font-style: inherit; -} - -code span.ss { - color: #20794D; - font-style: inherit; -} - -code span.an { - color: #5E5E5E; - font-style: inherit; -} - -code span.fu { - color: #4758AB; - font-style: inherit; -} - -code span.st { - color: #20794D; - font-style: inherit; -} - -code span.cf { - color: #003B4F; - font-weight: bold; - font-style: inherit; -} - -code span.op { - color: #5E5E5E; - font-style: inherit; -} - -code span.er { - color: #AD0000; - font-style: inherit; -} - -code span.bn { - color: #AD0000; - font-style: inherit; -} - -code span.al { - color: #AD0000; - font-style: inherit; -} - -code span.va { - color: #111111; - font-style: inherit; -} - -code span.bu { - font-style: inherit; -} - -code span.ex { - font-style: inherit; -} - -code span.pp { - color: #AD0000; - font-style: inherit; -} - -code span.in { - color: #5E5E5E; - font-style: inherit; -} - -code span.vs { - color: #20794D; - font-style: inherit; -} - -code span.wa { - color: #5E5E5E; - font-style: italic; -} - -code span.do { - color: #5E5E5E; - font-style: italic; -} - -code span.im { - color: #00769E; - font-style: inherit; -} - -code span.ch { - color: #20794D; - font-style: inherit; -} - -code span.dt { - color: #AD0000; - font-style: inherit; -} - -code span.fl { - color: #AD0000; - font-style: inherit; -} - -code span.co { - color: #5E5E5E; - font-style: inherit; -} - -code span.cv { - color: #5E5E5E; - font-style: italic; -} - -code span.cn { - color: #8f5902; - font-style: inherit; -} - -code span.sc { - color: #5E5E5E; - font-style: inherit; -} - -code span.dv { - color: #AD0000; - font-style: inherit; -} - -code span.kw { - color: #003B4F; - font-weight: bold; - font-style: inherit; -} - -.prevent-inlining { - content: " { - // Find any conflicting margin elements and add margins to the - // top to prevent overlap - const marginChildren = window.document.querySelectorAll( - ".column-margin.column-container > *, .margin-caption, .aside" - ); - - let lastBottom = 0; - for (const marginChild of marginChildren) { - if (marginChild.offsetParent !== null) { - // clear the top margin so we recompute it - marginChild.style.marginTop = null; - const top = marginChild.getBoundingClientRect().top + window.scrollY; - if (top < lastBottom) { - const marginChildStyle = window.getComputedStyle(marginChild); - const marginBottom = parseFloat(marginChildStyle["marginBottom"]); - const margin = lastBottom - top + marginBottom; - marginChild.style.marginTop = `${margin}px`; - } - const styles = window.getComputedStyle(marginChild); - const marginTop = parseFloat(styles["marginTop"]); - lastBottom = top + marginChild.getBoundingClientRect().height + marginTop; - } - } -}; - -window.document.addEventListener("DOMContentLoaded", function (_event) { - // Recompute the position of margin elements anytime the body size changes - if (window.ResizeObserver) { - const resizeObserver = new window.ResizeObserver( - throttle(() => { - layoutMarginEls(); - if ( - window.document.body.getBoundingClientRect().width < 990 && - isReaderMode() - ) { - quartoToggleReader(); - } - }, 50) - ); - resizeObserver.observe(window.document.body); - } - - const tocEl = window.document.querySelector('nav.toc-active[role="doc-toc"]'); - const sidebarEl = window.document.getElementById("quarto-sidebar"); - const leftTocEl = window.document.getElementById("quarto-sidebar-toc-left"); - const marginSidebarEl = window.document.getElementById( - "quarto-margin-sidebar" - ); - // function to determine whether the element has a previous sibling that is active - const prevSiblingIsActiveLink = (el) => { - const sibling = el.previousElementSibling; - if (sibling && sibling.tagName === "A") { - return sibling.classList.contains("active"); - } else { - return false; - } - }; - - // fire slideEnter for bootstrap tab activations (for htmlwidget resize behavior) - function fireSlideEnter(e) { - const event = window.document.createEvent("Event"); - event.initEvent("slideenter", true, true); - window.document.dispatchEvent(event); - } - const tabs = window.document.querySelectorAll('a[data-bs-toggle="tab"]'); - tabs.forEach((tab) => { - tab.addEventListener("shown.bs.tab", fireSlideEnter); - }); - - // fire slideEnter for tabby tab activations (for htmlwidget resize behavior) - document.addEventListener("tabby", fireSlideEnter, false); - - // Track scrolling and mark TOC links as active - // get table of contents and sidebar (bail if we don't have at least one) - const tocLinks = tocEl - ? [...tocEl.querySelectorAll("a[data-scroll-target]")] - : []; - const makeActive = (link) => tocLinks[link].classList.add("active"); - const removeActive = (link) => tocLinks[link].classList.remove("active"); - const removeAllActive = () => - [...Array(tocLinks.length).keys()].forEach((link) => removeActive(link)); - - // activate the anchor for a section associated with this TOC entry - tocLinks.forEach((link) => { - link.addEventListener("click", () => { - if (link.href.indexOf("#") !== -1) { - const anchor = link.href.split("#")[1]; - const heading = window.document.querySelector( - `[data-anchor-id="${anchor}"]` - ); - if (heading) { - // Add the class - heading.classList.add("reveal-anchorjs-link"); - - // function to show the anchor - const handleMouseout = () => { - heading.classList.remove("reveal-anchorjs-link"); - heading.removeEventListener("mouseout", handleMouseout); - }; - - // add a function to clear the anchor when the user mouses out of it - heading.addEventListener("mouseout", handleMouseout); - } - } - }); - }); - - const sections = tocLinks.map((link) => { - const target = link.getAttribute("data-scroll-target"); - if (target.startsWith("#")) { - return window.document.getElementById(decodeURI(`${target.slice(1)}`)); - } else { - return window.document.querySelector(decodeURI(`${target}`)); - } - }); - - const sectionMargin = 200; - let currentActive = 0; - // track whether we've initialized state the first time - let init = false; - - const updateActiveLink = () => { - // The index from bottom to top (e.g. reversed list) - let sectionIndex = -1; - if ( - window.innerHeight + window.pageYOffset >= - window.document.body.offsetHeight - ) { - // This is the no-scroll case where last section should be the active one - sectionIndex = 0; - } else { - // This finds the last section visible on screen that should be made active - sectionIndex = [...sections].reverse().findIndex((section) => { - if (section) { - return window.pageYOffset >= section.offsetTop - sectionMargin; - } else { - return false; - } - }); - } - if (sectionIndex > -1) { - const current = sections.length - sectionIndex - 1; - if (current !== currentActive) { - removeAllActive(); - currentActive = current; - makeActive(current); - if (init) { - window.dispatchEvent(sectionChanged); - } - init = true; - } - } - }; - - const inHiddenRegion = (top, bottom, hiddenRegions) => { - for (const region of hiddenRegions) { - if (top <= region.bottom && bottom >= region.top) { - return true; - } - } - return false; - }; - - const categorySelector = "header.quarto-title-block .quarto-category"; - const activateCategories = (href) => { - // Find any categories - // Surround them with a link pointing back to: - // #category=Authoring - try { - const categoryEls = window.document.querySelectorAll(categorySelector); - for (const categoryEl of categoryEls) { - const categoryText = categoryEl.textContent; - if (categoryText) { - const link = `${href}#category=${encodeURIComponent(categoryText)}`; - const linkEl = window.document.createElement("a"); - linkEl.setAttribute("href", link); - for (const child of categoryEl.childNodes) { - linkEl.append(child); - } - categoryEl.appendChild(linkEl); - } - } - } catch { - // Ignore errors - } - }; - function hasTitleCategories() { - return window.document.querySelector(categorySelector) !== null; - } - - function offsetRelativeUrl(url) { - const offset = getMeta("quarto:offset"); - return offset ? offset + url : url; - } - - function offsetAbsoluteUrl(url) { - const offset = getMeta("quarto:offset"); - const baseUrl = new URL(offset, window.location); - - const projRelativeUrl = url.replace(baseUrl, ""); - if (projRelativeUrl.startsWith("/")) { - return projRelativeUrl; - } else { - return "/" + projRelativeUrl; - } - } - - // read a meta tag value - function getMeta(metaName) { - const metas = window.document.getElementsByTagName("meta"); - for (let i = 0; i < metas.length; i++) { - if (metas[i].getAttribute("name") === metaName) { - return metas[i].getAttribute("content"); - } - } - return ""; - } - - async function findAndActivateCategories() { - const currentPagePath = offsetAbsoluteUrl(window.location.href); - const response = await fetch(offsetRelativeUrl("listings.json")); - if (response.status == 200) { - return response.json().then(function (listingPaths) { - const listingHrefs = []; - for (const listingPath of listingPaths) { - const pathWithoutLeadingSlash = listingPath.listing.substring(1); - for (const item of listingPath.items) { - if ( - item === currentPagePath || - item === currentPagePath + "index.html" - ) { - // Resolve this path against the offset to be sure - // we already are using the correct path to the listing - // (this adjusts the listing urls to be rooted against - // whatever root the page is actually running against) - const relative = offsetRelativeUrl(pathWithoutLeadingSlash); - const baseUrl = window.location; - const resolvedPath = new URL(relative, baseUrl); - listingHrefs.push(resolvedPath.pathname); - break; - } - } - } - - // Look up the tree for a nearby linting and use that if we find one - const nearestListing = findNearestParentListing( - offsetAbsoluteUrl(window.location.pathname), - listingHrefs - ); - if (nearestListing) { - activateCategories(nearestListing); - } else { - // See if the referrer is a listing page for this item - const referredRelativePath = offsetAbsoluteUrl(document.referrer); - const referrerListing = listingHrefs.find((listingHref) => { - const isListingReferrer = - listingHref === referredRelativePath || - listingHref === referredRelativePath + "index.html"; - return isListingReferrer; - }); - - if (referrerListing) { - // Try to use the referrer if possible - activateCategories(referrerListing); - } else if (listingHrefs.length > 0) { - // Otherwise, just fall back to the first listing - activateCategories(listingHrefs[0]); - } - } - }); - } - } - if (hasTitleCategories()) { - findAndActivateCategories(); - } - - const findNearestParentListing = (href, listingHrefs) => { - if (!href || !listingHrefs) { - return undefined; - } - // Look up the tree for a nearby linting and use that if we find one - const relativeParts = href.substring(1).split("/"); - while (relativeParts.length > 0) { - const path = relativeParts.join("/"); - for (const listingHref of listingHrefs) { - if (listingHref.startsWith(path)) { - return listingHref; - } - } - relativeParts.pop(); - } - - return undefined; - }; - - const manageSidebarVisiblity = (el, placeholderDescriptor) => { - let isVisible = true; - let elRect; - - return (hiddenRegions) => { - if (el === null) { - return; - } - - // Find the last element of the TOC - const lastChildEl = el.lastElementChild; - - if (lastChildEl) { - // Converts the sidebar to a menu - const convertToMenu = () => { - for (const child of el.children) { - child.style.opacity = 0; - child.style.overflow = "hidden"; - child.style.pointerEvents = "none"; - } - - nexttick(() => { - const toggleContainer = window.document.createElement("div"); - toggleContainer.style.width = "100%"; - toggleContainer.classList.add("zindex-over-content"); - toggleContainer.classList.add("quarto-sidebar-toggle"); - toggleContainer.classList.add("headroom-target"); // Marks this to be managed by headeroom - toggleContainer.id = placeholderDescriptor.id; - toggleContainer.style.position = "fixed"; - - const toggleIcon = window.document.createElement("i"); - toggleIcon.classList.add("quarto-sidebar-toggle-icon"); - toggleIcon.classList.add("bi"); - toggleIcon.classList.add("bi-caret-down-fill"); - - const toggleTitle = window.document.createElement("div"); - const titleEl = window.document.body.querySelector( - placeholderDescriptor.titleSelector - ); - if (titleEl) { - toggleTitle.append( - titleEl.textContent || titleEl.innerText, - toggleIcon - ); - } - toggleTitle.classList.add("zindex-over-content"); - toggleTitle.classList.add("quarto-sidebar-toggle-title"); - toggleContainer.append(toggleTitle); - - const toggleContents = window.document.createElement("div"); - toggleContents.classList = el.classList; - toggleContents.classList.add("zindex-over-content"); - toggleContents.classList.add("quarto-sidebar-toggle-contents"); - for (const child of el.children) { - if (child.id === "toc-title") { - continue; - } - - const clone = child.cloneNode(true); - clone.style.opacity = 1; - clone.style.pointerEvents = null; - clone.style.display = null; - toggleContents.append(clone); - } - toggleContents.style.height = "0px"; - const positionToggle = () => { - // position the element (top left of parent, same width as parent) - if (!elRect) { - elRect = el.getBoundingClientRect(); - } - toggleContainer.style.left = `${elRect.left}px`; - toggleContainer.style.top = `${elRect.top}px`; - toggleContainer.style.width = `${elRect.width}px`; - }; - positionToggle(); - - toggleContainer.append(toggleContents); - el.parentElement.prepend(toggleContainer); - - // Process clicks - let tocShowing = false; - // Allow the caller to control whether this is dismissed - // when it is clicked (e.g. sidebar navigation supports - // opening and closing the nav tree, so don't dismiss on click) - const clickEl = placeholderDescriptor.dismissOnClick - ? toggleContainer - : toggleTitle; - - const closeToggle = () => { - if (tocShowing) { - toggleContainer.classList.remove("expanded"); - toggleContents.style.height = "0px"; - tocShowing = false; - } - }; - - // Get rid of any expanded toggle if the user scrolls - window.document.addEventListener( - "scroll", - throttle(() => { - closeToggle(); - }, 50) - ); - - // Handle positioning of the toggle - window.addEventListener( - "resize", - throttle(() => { - elRect = undefined; - positionToggle(); - }, 50) - ); - - window.addEventListener("quarto-hrChanged", () => { - elRect = undefined; - }); - - // Process the click - clickEl.onclick = () => { - if (!tocShowing) { - toggleContainer.classList.add("expanded"); - toggleContents.style.height = null; - tocShowing = true; - } else { - closeToggle(); - } - }; - }); - }; - - // Converts a sidebar from a menu back to a sidebar - const convertToSidebar = () => { - for (const child of el.children) { - child.style.opacity = 1; - child.style.overflow = null; - child.style.pointerEvents = null; - } - - const placeholderEl = window.document.getElementById( - placeholderDescriptor.id - ); - if (placeholderEl) { - placeholderEl.remove(); - } - - el.classList.remove("rollup"); - }; - - if (isReaderMode()) { - convertToMenu(); - isVisible = false; - } else { - // Find the top and bottom o the element that is being managed - const elTop = el.offsetTop; - const elBottom = - elTop + lastChildEl.offsetTop + lastChildEl.offsetHeight; - - if (!isVisible) { - // If the element is current not visible reveal if there are - // no conflicts with overlay regions - if (!inHiddenRegion(elTop, elBottom, hiddenRegions)) { - convertToSidebar(); - isVisible = true; - } - } else { - // If the element is visible, hide it if it conflicts with overlay regions - // and insert a placeholder toggle (or if we're in reader mode) - if (inHiddenRegion(elTop, elBottom, hiddenRegions)) { - convertToMenu(); - isVisible = false; - } - } - } - } - }; - }; - - const tabEls = document.querySelectorAll('a[data-bs-toggle="tab"]'); - for (const tabEl of tabEls) { - const id = tabEl.getAttribute("data-bs-target"); - if (id) { - const columnEl = document.querySelector( - `${id} .column-margin, .tabset-margin-content` - ); - if (columnEl) - tabEl.addEventListener("shown.bs.tab", function (event) { - const el = event.srcElement; - if (el) { - const visibleCls = `${el.id}-margin-content`; - // walk up until we find a parent tabset - let panelTabsetEl = el.parentElement; - while (panelTabsetEl) { - if (panelTabsetEl.classList.contains("panel-tabset")) { - break; - } - panelTabsetEl = panelTabsetEl.parentElement; - } - - if (panelTabsetEl) { - const prevSib = panelTabsetEl.previousElementSibling; - if ( - prevSib && - prevSib.classList.contains("tabset-margin-container") - ) { - const childNodes = prevSib.querySelectorAll( - ".tabset-margin-content" - ); - for (const childEl of childNodes) { - if (childEl.classList.contains(visibleCls)) { - childEl.classList.remove("collapse"); - } else { - childEl.classList.add("collapse"); - } - } - } - } - } - - layoutMarginEls(); - }); - } - } - - // Manage the visibility of the toc and the sidebar - const marginScrollVisibility = manageSidebarVisiblity(marginSidebarEl, { - id: "quarto-toc-toggle", - titleSelector: "#toc-title", - dismissOnClick: true, - }); - const sidebarScrollVisiblity = manageSidebarVisiblity(sidebarEl, { - id: "quarto-sidebarnav-toggle", - titleSelector: ".title", - dismissOnClick: false, - }); - let tocLeftScrollVisibility; - if (leftTocEl) { - tocLeftScrollVisibility = manageSidebarVisiblity(leftTocEl, { - id: "quarto-lefttoc-toggle", - titleSelector: "#toc-title", - dismissOnClick: true, - }); - } - - // Find the first element that uses formatting in special columns - const conflictingEls = window.document.body.querySelectorAll( - '[class^="column-"], [class*=" column-"], aside, [class*="margin-caption"], [class*=" margin-caption"], [class*="margin-ref"], [class*=" margin-ref"]' - ); - - // Filter all the possibly conflicting elements into ones - // the do conflict on the left or ride side - const arrConflictingEls = Array.from(conflictingEls); - const leftSideConflictEls = arrConflictingEls.filter((el) => { - if (el.tagName === "ASIDE") { - return false; - } - return Array.from(el.classList).find((className) => { - return ( - className !== "column-body" && - className.startsWith("column-") && - !className.endsWith("right") && - !className.endsWith("container") && - className !== "column-margin" - ); - }); - }); - const rightSideConflictEls = arrConflictingEls.filter((el) => { - if (el.tagName === "ASIDE") { - return true; - } - - const hasMarginCaption = Array.from(el.classList).find((className) => { - return className == "margin-caption"; - }); - if (hasMarginCaption) { - return true; - } - - return Array.from(el.classList).find((className) => { - return ( - className !== "column-body" && - !className.endsWith("container") && - className.startsWith("column-") && - !className.endsWith("left") - ); - }); - }); - - const kOverlapPaddingSize = 10; - function toRegions(els) { - return els.map((el) => { - const boundRect = el.getBoundingClientRect(); - const top = - boundRect.top + - document.documentElement.scrollTop - - kOverlapPaddingSize; - return { - top, - bottom: top + el.scrollHeight + 2 * kOverlapPaddingSize, - }; - }); - } - - let hasObserved = false; - const visibleItemObserver = (els) => { - let visibleElements = [...els]; - const intersectionObserver = new IntersectionObserver( - (entries, _observer) => { - entries.forEach((entry) => { - if (entry.isIntersecting) { - if (visibleElements.indexOf(entry.target) === -1) { - visibleElements.push(entry.target); - } - } else { - visibleElements = visibleElements.filter((visibleEntry) => { - return visibleEntry !== entry; - }); - } - }); - - if (!hasObserved) { - hideOverlappedSidebars(); - } - hasObserved = true; - }, - {} - ); - els.forEach((el) => { - intersectionObserver.observe(el); - }); - - return { - getVisibleEntries: () => { - return visibleElements; - }, - }; - }; - - const rightElementObserver = visibleItemObserver(rightSideConflictEls); - const leftElementObserver = visibleItemObserver(leftSideConflictEls); - - const hideOverlappedSidebars = () => { - marginScrollVisibility(toRegions(rightElementObserver.getVisibleEntries())); - sidebarScrollVisiblity(toRegions(leftElementObserver.getVisibleEntries())); - if (tocLeftScrollVisibility) { - tocLeftScrollVisibility( - toRegions(leftElementObserver.getVisibleEntries()) - ); - } - }; - - window.quartoToggleReader = () => { - // Applies a slow class (or removes it) - // to update the transition speed - const slowTransition = (slow) => { - const manageTransition = (id, slow) => { - const el = document.getElementById(id); - if (el) { - if (slow) { - el.classList.add("slow"); - } else { - el.classList.remove("slow"); - } - } - }; - - manageTransition("TOC", slow); - manageTransition("quarto-sidebar", slow); - }; - const readerMode = !isReaderMode(); - setReaderModeValue(readerMode); - - // If we're entering reader mode, slow the transition - if (readerMode) { - slowTransition(readerMode); - } - highlightReaderToggle(readerMode); - hideOverlappedSidebars(); - - // If we're exiting reader mode, restore the non-slow transition - if (!readerMode) { - slowTransition(!readerMode); - } - }; - - const highlightReaderToggle = (readerMode) => { - const els = document.querySelectorAll(".quarto-reader-toggle"); - if (els) { - els.forEach((el) => { - if (readerMode) { - el.classList.add("reader"); - } else { - el.classList.remove("reader"); - } - }); - } - }; - - const setReaderModeValue = (val) => { - if (window.location.protocol !== "file:") { - window.localStorage.setItem("quarto-reader-mode", val); - } else { - localReaderMode = val; - } - }; - - const isReaderMode = () => { - if (window.location.protocol !== "file:") { - return window.localStorage.getItem("quarto-reader-mode") === "true"; - } else { - return localReaderMode; - } - }; - let localReaderMode = null; - - const tocOpenDepthStr = tocEl?.getAttribute("data-toc-expanded"); - const tocOpenDepth = tocOpenDepthStr ? Number(tocOpenDepthStr) : 1; - - // Walk the TOC and collapse/expand nodes - // Nodes are expanded if: - // - they are top level - // - they have children that are 'active' links - // - they are directly below an link that is 'active' - const walk = (el, depth) => { - // Tick depth when we enter a UL - if (el.tagName === "UL") { - depth = depth + 1; - } - - // It this is active link - let isActiveNode = false; - if (el.tagName === "A" && el.classList.contains("active")) { - isActiveNode = true; - } - - // See if there is an active child to this element - let hasActiveChild = false; - for (child of el.children) { - hasActiveChild = walk(child, depth) || hasActiveChild; - } - - // Process the collapse state if this is an UL - if (el.tagName === "UL") { - if (tocOpenDepth === -1 && depth > 1) { - // toc-expand: false - el.classList.add("collapse"); - } else if ( - depth <= tocOpenDepth || - hasActiveChild || - prevSiblingIsActiveLink(el) - ) { - el.classList.remove("collapse"); - } else { - el.classList.add("collapse"); - } - - // untick depth when we leave a UL - depth = depth - 1; - } - return hasActiveChild || isActiveNode; - }; - - // walk the TOC and expand / collapse any items that should be shown - if (tocEl) { - updateActiveLink(); - walk(tocEl, 0); - } - - // Throttle the scroll event and walk peridiocally - window.document.addEventListener( - "scroll", - throttle(() => { - if (tocEl) { - updateActiveLink(); - walk(tocEl, 0); - } - if (!isReaderMode()) { - hideOverlappedSidebars(); - } - }, 5) - ); - window.addEventListener( - "resize", - throttle(() => { - if (tocEl) { - updateActiveLink(); - walk(tocEl, 0); - } - if (!isReaderMode()) { - hideOverlappedSidebars(); - } - }, 10) - ); - hideOverlappedSidebars(); - highlightReaderToggle(isReaderMode()); -}); - -// grouped tabsets -window.addEventListener("pageshow", (_event) => { - function getTabSettings() { - const data = localStorage.getItem("quarto-persistent-tabsets-data"); - if (!data) { - localStorage.setItem("quarto-persistent-tabsets-data", "{}"); - return {}; - } - if (data) { - return JSON.parse(data); - } - } - - function setTabSettings(data) { - localStorage.setItem( - "quarto-persistent-tabsets-data", - JSON.stringify(data) - ); - } - - function setTabState(groupName, groupValue) { - const data = getTabSettings(); - data[groupName] = groupValue; - setTabSettings(data); - } - - function toggleTab(tab, active) { - const tabPanelId = tab.getAttribute("aria-controls"); - const tabPanel = document.getElementById(tabPanelId); - if (active) { - tab.classList.add("active"); - tabPanel.classList.add("active"); - } else { - tab.classList.remove("active"); - tabPanel.classList.remove("active"); - } - } - - function toggleAll(selectedGroup, selectorsToSync) { - for (const [thisGroup, tabs] of Object.entries(selectorsToSync)) { - const active = selectedGroup === thisGroup; - for (const tab of tabs) { - toggleTab(tab, active); - } - } - } - - function findSelectorsToSyncByLanguage() { - const result = {}; - const tabs = Array.from( - document.querySelectorAll(`div[data-group] a[id^='tabset-']`) - ); - for (const item of tabs) { - const div = item.parentElement.parentElement.parentElement; - const group = div.getAttribute("data-group"); - if (!result[group]) { - result[group] = {}; - } - const selectorsToSync = result[group]; - const value = item.innerHTML; - if (!selectorsToSync[value]) { - selectorsToSync[value] = []; - } - selectorsToSync[value].push(item); - } - return result; - } - - function setupSelectorSync() { - const selectorsToSync = findSelectorsToSyncByLanguage(); - Object.entries(selectorsToSync).forEach(([group, tabSetsByValue]) => { - Object.entries(tabSetsByValue).forEach(([value, items]) => { - items.forEach((item) => { - item.addEventListener("click", (_event) => { - setTabState(group, value); - toggleAll(value, selectorsToSync[group]); - }); - }); - }); - }); - return selectorsToSync; - } - - const selectorsToSync = setupSelectorSync(); - for (const [group, selectedName] of Object.entries(getTabSettings())) { - const selectors = selectorsToSync[group]; - // it's possible that stale state gives us empty selections, so we explicitly check here. - if (selectors) { - toggleAll(selectedName, selectors); - } - } -}); - -function throttle(func, wait) { - let waiting = false; - return function () { - if (!waiting) { - func.apply(this, arguments); - waiting = true; - setTimeout(function () { - waiting = false; - }, wait); - } - }; -} - -function nexttick(func) { - return setTimeout(func, 0); -} diff --git a/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/run_pecan_files/libs/quarto-html/tippy.css b/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/run_pecan_files/libs/quarto-html/tippy.css deleted file mode 100644 index e6ae635cb..000000000 --- a/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/run_pecan_files/libs/quarto-html/tippy.css +++ /dev/null @@ -1 +0,0 @@ -.tippy-box[data-animation=fade][data-state=hidden]{opacity:0}[data-tippy-root]{max-width:calc(100vw - 10px)}.tippy-box{position:relative;background-color:#333;color:#fff;border-radius:4px;font-size:14px;line-height:1.4;white-space:normal;outline:0;transition-property:transform,visibility,opacity}.tippy-box[data-placement^=top]>.tippy-arrow{bottom:0}.tippy-box[data-placement^=top]>.tippy-arrow:before{bottom:-7px;left:0;border-width:8px 8px 0;border-top-color:initial;transform-origin:center top}.tippy-box[data-placement^=bottom]>.tippy-arrow{top:0}.tippy-box[data-placement^=bottom]>.tippy-arrow:before{top:-7px;left:0;border-width:0 8px 8px;border-bottom-color:initial;transform-origin:center bottom}.tippy-box[data-placement^=left]>.tippy-arrow{right:0}.tippy-box[data-placement^=left]>.tippy-arrow:before{border-width:8px 0 8px 8px;border-left-color:initial;right:-7px;transform-origin:center left}.tippy-box[data-placement^=right]>.tippy-arrow{left:0}.tippy-box[data-placement^=right]>.tippy-arrow:before{left:-7px;border-width:8px 8px 8px 0;border-right-color:initial;transform-origin:center right}.tippy-box[data-inertia][data-state=visible]{transition-timing-function:cubic-bezier(.54,1.5,.38,1.11)}.tippy-arrow{width:16px;height:16px;color:#333}.tippy-arrow:before{content:"";position:absolute;border-color:transparent;border-style:solid}.tippy-content{position:relative;padding:5px 9px;z-index:1} \ No newline at end of file diff --git a/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/run_pecan_files/libs/quarto-html/tippy.umd.min.js b/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/run_pecan_files/libs/quarto-html/tippy.umd.min.js deleted file mode 100644 index ca292be32..000000000 --- a/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/run_pecan_files/libs/quarto-html/tippy.umd.min.js +++ /dev/null @@ -1,2 +0,0 @@ -!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t(require("@popperjs/core")):"function"==typeof define&&define.amd?define(["@popperjs/core"],t):(e=e||self).tippy=t(e.Popper)}(this,(function(e){"use strict";var t={passive:!0,capture:!0},n=function(){return document.body};function r(e,t,n){if(Array.isArray(e)){var r=e[t];return null==r?Array.isArray(n)?n[t]:n:r}return e}function o(e,t){var n={}.toString.call(e);return 0===n.indexOf("[object")&&n.indexOf(t+"]")>-1}function i(e,t){return"function"==typeof e?e.apply(void 0,t):e}function a(e,t){return 0===t?e:function(r){clearTimeout(n),n=setTimeout((function(){e(r)}),t)};var n}function s(e,t){var n=Object.assign({},e);return t.forEach((function(e){delete n[e]})),n}function u(e){return[].concat(e)}function c(e,t){-1===e.indexOf(t)&&e.push(t)}function p(e){return e.split("-")[0]}function f(e){return[].slice.call(e)}function l(e){return Object.keys(e).reduce((function(t,n){return void 0!==e[n]&&(t[n]=e[n]),t}),{})}function d(){return document.createElement("div")}function v(e){return["Element","Fragment"].some((function(t){return o(e,t)}))}function m(e){return o(e,"MouseEvent")}function g(e){return!(!e||!e._tippy||e._tippy.reference!==e)}function h(e){return v(e)?[e]:function(e){return o(e,"NodeList")}(e)?f(e):Array.isArray(e)?e:f(document.querySelectorAll(e))}function b(e,t){e.forEach((function(e){e&&(e.style.transitionDuration=t+"ms")}))}function y(e,t){e.forEach((function(e){e&&e.setAttribute("data-state",t)}))}function w(e){var t,n=u(e)[0];return null!=n&&null!=(t=n.ownerDocument)&&t.body?n.ownerDocument:document}function E(e,t,n){var r=t+"EventListener";["transitionend","webkitTransitionEnd"].forEach((function(t){e[r](t,n)}))}function O(e,t){for(var n=t;n;){var r;if(e.contains(n))return!0;n=null==n.getRootNode||null==(r=n.getRootNode())?void 0:r.host}return!1}var x={isTouch:!1},C=0;function T(){x.isTouch||(x.isTouch=!0,window.performance&&document.addEventListener("mousemove",A))}function A(){var e=performance.now();e-C<20&&(x.isTouch=!1,document.removeEventListener("mousemove",A)),C=e}function L(){var e=document.activeElement;if(g(e)){var t=e._tippy;e.blur&&!t.state.isVisible&&e.blur()}}var D=!!("undefined"!=typeof window&&"undefined"!=typeof document)&&!!window.msCrypto,R=Object.assign({appendTo:n,aria:{content:"auto",expanded:"auto"},delay:0,duration:[300,250],getReferenceClientRect:null,hideOnClick:!0,ignoreAttributes:!1,interactive:!1,interactiveBorder:2,interactiveDebounce:0,moveTransition:"",offset:[0,10],onAfterUpdate:function(){},onBeforeUpdate:function(){},onCreate:function(){},onDestroy:function(){},onHidden:function(){},onHide:function(){},onMount:function(){},onShow:function(){},onShown:function(){},onTrigger:function(){},onUntrigger:function(){},onClickOutside:function(){},placement:"top",plugins:[],popperOptions:{},render:null,showOnCreate:!1,touch:!0,trigger:"mouseenter focus",triggerTarget:null},{animateFill:!1,followCursor:!1,inlinePositioning:!1,sticky:!1},{allowHTML:!1,animation:"fade",arrow:!0,content:"",inertia:!1,maxWidth:350,role:"tooltip",theme:"",zIndex:9999}),k=Object.keys(R);function P(e){var t=(e.plugins||[]).reduce((function(t,n){var r,o=n.name,i=n.defaultValue;o&&(t[o]=void 0!==e[o]?e[o]:null!=(r=R[o])?r:i);return t}),{});return Object.assign({},e,t)}function j(e,t){var n=Object.assign({},t,{content:i(t.content,[e])},t.ignoreAttributes?{}:function(e,t){return(t?Object.keys(P(Object.assign({},R,{plugins:t}))):k).reduce((function(t,n){var r=(e.getAttribute("data-tippy-"+n)||"").trim();if(!r)return t;if("content"===n)t[n]=r;else try{t[n]=JSON.parse(r)}catch(e){t[n]=r}return t}),{})}(e,t.plugins));return n.aria=Object.assign({},R.aria,n.aria),n.aria={expanded:"auto"===n.aria.expanded?t.interactive:n.aria.expanded,content:"auto"===n.aria.content?t.interactive?null:"describedby":n.aria.content},n}function M(e,t){e.innerHTML=t}function V(e){var t=d();return!0===e?t.className="tippy-arrow":(t.className="tippy-svg-arrow",v(e)?t.appendChild(e):M(t,e)),t}function I(e,t){v(t.content)?(M(e,""),e.appendChild(t.content)):"function"!=typeof t.content&&(t.allowHTML?M(e,t.content):e.textContent=t.content)}function S(e){var t=e.firstElementChild,n=f(t.children);return{box:t,content:n.find((function(e){return e.classList.contains("tippy-content")})),arrow:n.find((function(e){return e.classList.contains("tippy-arrow")||e.classList.contains("tippy-svg-arrow")})),backdrop:n.find((function(e){return e.classList.contains("tippy-backdrop")}))}}function N(e){var t=d(),n=d();n.className="tippy-box",n.setAttribute("data-state","hidden"),n.setAttribute("tabindex","-1");var r=d();function o(n,r){var o=S(t),i=o.box,a=o.content,s=o.arrow;r.theme?i.setAttribute("data-theme",r.theme):i.removeAttribute("data-theme"),"string"==typeof r.animation?i.setAttribute("data-animation",r.animation):i.removeAttribute("data-animation"),r.inertia?i.setAttribute("data-inertia",""):i.removeAttribute("data-inertia"),i.style.maxWidth="number"==typeof r.maxWidth?r.maxWidth+"px":r.maxWidth,r.role?i.setAttribute("role",r.role):i.removeAttribute("role"),n.content===r.content&&n.allowHTML===r.allowHTML||I(a,e.props),r.arrow?s?n.arrow!==r.arrow&&(i.removeChild(s),i.appendChild(V(r.arrow))):i.appendChild(V(r.arrow)):s&&i.removeChild(s)}return r.className="tippy-content",r.setAttribute("data-state","hidden"),I(r,e.props),t.appendChild(n),n.appendChild(r),o(e.props,e.props),{popper:t,onUpdate:o}}N.$$tippy=!0;var B=1,H=[],U=[];function _(o,s){var v,g,h,C,T,A,L,k,M=j(o,Object.assign({},R,P(l(s)))),V=!1,I=!1,N=!1,_=!1,F=[],W=a(we,M.interactiveDebounce),X=B++,Y=(k=M.plugins).filter((function(e,t){return k.indexOf(e)===t})),$={id:X,reference:o,popper:d(),popperInstance:null,props:M,state:{isEnabled:!0,isVisible:!1,isDestroyed:!1,isMounted:!1,isShown:!1},plugins:Y,clearDelayTimeouts:function(){clearTimeout(v),clearTimeout(g),cancelAnimationFrame(h)},setProps:function(e){if($.state.isDestroyed)return;ae("onBeforeUpdate",[$,e]),be();var t=$.props,n=j(o,Object.assign({},t,l(e),{ignoreAttributes:!0}));$.props=n,he(),t.interactiveDebounce!==n.interactiveDebounce&&(ce(),W=a(we,n.interactiveDebounce));t.triggerTarget&&!n.triggerTarget?u(t.triggerTarget).forEach((function(e){e.removeAttribute("aria-expanded")})):n.triggerTarget&&o.removeAttribute("aria-expanded");ue(),ie(),J&&J(t,n);$.popperInstance&&(Ce(),Ae().forEach((function(e){requestAnimationFrame(e._tippy.popperInstance.forceUpdate)})));ae("onAfterUpdate",[$,e])},setContent:function(e){$.setProps({content:e})},show:function(){var e=$.state.isVisible,t=$.state.isDestroyed,o=!$.state.isEnabled,a=x.isTouch&&!$.props.touch,s=r($.props.duration,0,R.duration);if(e||t||o||a)return;if(te().hasAttribute("disabled"))return;if(ae("onShow",[$],!1),!1===$.props.onShow($))return;$.state.isVisible=!0,ee()&&(z.style.visibility="visible");ie(),de(),$.state.isMounted||(z.style.transition="none");if(ee()){var u=re(),p=u.box,f=u.content;b([p,f],0)}A=function(){var e;if($.state.isVisible&&!_){if(_=!0,z.offsetHeight,z.style.transition=$.props.moveTransition,ee()&&$.props.animation){var t=re(),n=t.box,r=t.content;b([n,r],s),y([n,r],"visible")}se(),ue(),c(U,$),null==(e=$.popperInstance)||e.forceUpdate(),ae("onMount",[$]),$.props.animation&&ee()&&function(e,t){me(e,t)}(s,(function(){$.state.isShown=!0,ae("onShown",[$])}))}},function(){var e,t=$.props.appendTo,r=te();e=$.props.interactive&&t===n||"parent"===t?r.parentNode:i(t,[r]);e.contains(z)||e.appendChild(z);$.state.isMounted=!0,Ce()}()},hide:function(){var e=!$.state.isVisible,t=$.state.isDestroyed,n=!$.state.isEnabled,o=r($.props.duration,1,R.duration);if(e||t||n)return;if(ae("onHide",[$],!1),!1===$.props.onHide($))return;$.state.isVisible=!1,$.state.isShown=!1,_=!1,V=!1,ee()&&(z.style.visibility="hidden");if(ce(),ve(),ie(!0),ee()){var i=re(),a=i.box,s=i.content;$.props.animation&&(b([a,s],o),y([a,s],"hidden"))}se(),ue(),$.props.animation?ee()&&function(e,t){me(e,(function(){!$.state.isVisible&&z.parentNode&&z.parentNode.contains(z)&&t()}))}(o,$.unmount):$.unmount()},hideWithInteractivity:function(e){ne().addEventListener("mousemove",W),c(H,W),W(e)},enable:function(){$.state.isEnabled=!0},disable:function(){$.hide(),$.state.isEnabled=!1},unmount:function(){$.state.isVisible&&$.hide();if(!$.state.isMounted)return;Te(),Ae().forEach((function(e){e._tippy.unmount()})),z.parentNode&&z.parentNode.removeChild(z);U=U.filter((function(e){return e!==$})),$.state.isMounted=!1,ae("onHidden",[$])},destroy:function(){if($.state.isDestroyed)return;$.clearDelayTimeouts(),$.unmount(),be(),delete o._tippy,$.state.isDestroyed=!0,ae("onDestroy",[$])}};if(!M.render)return $;var q=M.render($),z=q.popper,J=q.onUpdate;z.setAttribute("data-tippy-root",""),z.id="tippy-"+$.id,$.popper=z,o._tippy=$,z._tippy=$;var G=Y.map((function(e){return e.fn($)})),K=o.hasAttribute("aria-expanded");return he(),ue(),ie(),ae("onCreate",[$]),M.showOnCreate&&Le(),z.addEventListener("mouseenter",(function(){$.props.interactive&&$.state.isVisible&&$.clearDelayTimeouts()})),z.addEventListener("mouseleave",(function(){$.props.interactive&&$.props.trigger.indexOf("mouseenter")>=0&&ne().addEventListener("mousemove",W)})),$;function Q(){var e=$.props.touch;return Array.isArray(e)?e:[e,0]}function Z(){return"hold"===Q()[0]}function ee(){var e;return!(null==(e=$.props.render)||!e.$$tippy)}function te(){return L||o}function ne(){var e=te().parentNode;return e?w(e):document}function re(){return S(z)}function oe(e){return $.state.isMounted&&!$.state.isVisible||x.isTouch||C&&"focus"===C.type?0:r($.props.delay,e?0:1,R.delay)}function ie(e){void 0===e&&(e=!1),z.style.pointerEvents=$.props.interactive&&!e?"":"none",z.style.zIndex=""+$.props.zIndex}function ae(e,t,n){var r;(void 0===n&&(n=!0),G.forEach((function(n){n[e]&&n[e].apply(n,t)})),n)&&(r=$.props)[e].apply(r,t)}function se(){var e=$.props.aria;if(e.content){var t="aria-"+e.content,n=z.id;u($.props.triggerTarget||o).forEach((function(e){var r=e.getAttribute(t);if($.state.isVisible)e.setAttribute(t,r?r+" "+n:n);else{var o=r&&r.replace(n,"").trim();o?e.setAttribute(t,o):e.removeAttribute(t)}}))}}function ue(){!K&&$.props.aria.expanded&&u($.props.triggerTarget||o).forEach((function(e){$.props.interactive?e.setAttribute("aria-expanded",$.state.isVisible&&e===te()?"true":"false"):e.removeAttribute("aria-expanded")}))}function ce(){ne().removeEventListener("mousemove",W),H=H.filter((function(e){return e!==W}))}function pe(e){if(!x.isTouch||!N&&"mousedown"!==e.type){var t=e.composedPath&&e.composedPath()[0]||e.target;if(!$.props.interactive||!O(z,t)){if(u($.props.triggerTarget||o).some((function(e){return O(e,t)}))){if(x.isTouch)return;if($.state.isVisible&&$.props.trigger.indexOf("click")>=0)return}else ae("onClickOutside",[$,e]);!0===$.props.hideOnClick&&($.clearDelayTimeouts(),$.hide(),I=!0,setTimeout((function(){I=!1})),$.state.isMounted||ve())}}}function fe(){N=!0}function le(){N=!1}function de(){var e=ne();e.addEventListener("mousedown",pe,!0),e.addEventListener("touchend",pe,t),e.addEventListener("touchstart",le,t),e.addEventListener("touchmove",fe,t)}function ve(){var e=ne();e.removeEventListener("mousedown",pe,!0),e.removeEventListener("touchend",pe,t),e.removeEventListener("touchstart",le,t),e.removeEventListener("touchmove",fe,t)}function me(e,t){var n=re().box;function r(e){e.target===n&&(E(n,"remove",r),t())}if(0===e)return t();E(n,"remove",T),E(n,"add",r),T=r}function ge(e,t,n){void 0===n&&(n=!1),u($.props.triggerTarget||o).forEach((function(r){r.addEventListener(e,t,n),F.push({node:r,eventType:e,handler:t,options:n})}))}function he(){var e;Z()&&(ge("touchstart",ye,{passive:!0}),ge("touchend",Ee,{passive:!0})),(e=$.props.trigger,e.split(/\s+/).filter(Boolean)).forEach((function(e){if("manual"!==e)switch(ge(e,ye),e){case"mouseenter":ge("mouseleave",Ee);break;case"focus":ge(D?"focusout":"blur",Oe);break;case"focusin":ge("focusout",Oe)}}))}function be(){F.forEach((function(e){var t=e.node,n=e.eventType,r=e.handler,o=e.options;t.removeEventListener(n,r,o)})),F=[]}function ye(e){var t,n=!1;if($.state.isEnabled&&!xe(e)&&!I){var r="focus"===(null==(t=C)?void 0:t.type);C=e,L=e.currentTarget,ue(),!$.state.isVisible&&m(e)&&H.forEach((function(t){return t(e)})),"click"===e.type&&($.props.trigger.indexOf("mouseenter")<0||V)&&!1!==$.props.hideOnClick&&$.state.isVisible?n=!0:Le(e),"click"===e.type&&(V=!n),n&&!r&&De(e)}}function we(e){var t=e.target,n=te().contains(t)||z.contains(t);"mousemove"===e.type&&n||function(e,t){var n=t.clientX,r=t.clientY;return e.every((function(e){var t=e.popperRect,o=e.popperState,i=e.props.interactiveBorder,a=p(o.placement),s=o.modifiersData.offset;if(!s)return!0;var u="bottom"===a?s.top.y:0,c="top"===a?s.bottom.y:0,f="right"===a?s.left.x:0,l="left"===a?s.right.x:0,d=t.top-r+u>i,v=r-t.bottom-c>i,m=t.left-n+f>i,g=n-t.right-l>i;return d||v||m||g}))}(Ae().concat(z).map((function(e){var t,n=null==(t=e._tippy.popperInstance)?void 0:t.state;return n?{popperRect:e.getBoundingClientRect(),popperState:n,props:M}:null})).filter(Boolean),e)&&(ce(),De(e))}function Ee(e){xe(e)||$.props.trigger.indexOf("click")>=0&&V||($.props.interactive?$.hideWithInteractivity(e):De(e))}function Oe(e){$.props.trigger.indexOf("focusin")<0&&e.target!==te()||$.props.interactive&&e.relatedTarget&&z.contains(e.relatedTarget)||De(e)}function xe(e){return!!x.isTouch&&Z()!==e.type.indexOf("touch")>=0}function Ce(){Te();var t=$.props,n=t.popperOptions,r=t.placement,i=t.offset,a=t.getReferenceClientRect,s=t.moveTransition,u=ee()?S(z).arrow:null,c=a?{getBoundingClientRect:a,contextElement:a.contextElement||te()}:o,p=[{name:"offset",options:{offset:i}},{name:"preventOverflow",options:{padding:{top:2,bottom:2,left:5,right:5}}},{name:"flip",options:{padding:5}},{name:"computeStyles",options:{adaptive:!s}},{name:"$$tippy",enabled:!0,phase:"beforeWrite",requires:["computeStyles"],fn:function(e){var t=e.state;if(ee()){var n=re().box;["placement","reference-hidden","escaped"].forEach((function(e){"placement"===e?n.setAttribute("data-placement",t.placement):t.attributes.popper["data-popper-"+e]?n.setAttribute("data-"+e,""):n.removeAttribute("data-"+e)})),t.attributes.popper={}}}}];ee()&&u&&p.push({name:"arrow",options:{element:u,padding:3}}),p.push.apply(p,(null==n?void 0:n.modifiers)||[]),$.popperInstance=e.createPopper(c,z,Object.assign({},n,{placement:r,onFirstUpdate:A,modifiers:p}))}function Te(){$.popperInstance&&($.popperInstance.destroy(),$.popperInstance=null)}function Ae(){return f(z.querySelectorAll("[data-tippy-root]"))}function Le(e){$.clearDelayTimeouts(),e&&ae("onTrigger",[$,e]),de();var t=oe(!0),n=Q(),r=n[0],o=n[1];x.isTouch&&"hold"===r&&o&&(t=o),t?v=setTimeout((function(){$.show()}),t):$.show()}function De(e){if($.clearDelayTimeouts(),ae("onUntrigger",[$,e]),$.state.isVisible){if(!($.props.trigger.indexOf("mouseenter")>=0&&$.props.trigger.indexOf("click")>=0&&["mouseleave","mousemove"].indexOf(e.type)>=0&&V)){var t=oe(!1);t?g=setTimeout((function(){$.state.isVisible&&$.hide()}),t):h=requestAnimationFrame((function(){$.hide()}))}}else ve()}}function F(e,n){void 0===n&&(n={});var r=R.plugins.concat(n.plugins||[]);document.addEventListener("touchstart",T,t),window.addEventListener("blur",L);var o=Object.assign({},n,{plugins:r}),i=h(e).reduce((function(e,t){var n=t&&_(t,o);return n&&e.push(n),e}),[]);return v(e)?i[0]:i}F.defaultProps=R,F.setDefaultProps=function(e){Object.keys(e).forEach((function(t){R[t]=e[t]}))},F.currentInput=x;var W=Object.assign({},e.applyStyles,{effect:function(e){var t=e.state,n={popper:{position:t.options.strategy,left:"0",top:"0",margin:"0"},arrow:{position:"absolute"},reference:{}};Object.assign(t.elements.popper.style,n.popper),t.styles=n,t.elements.arrow&&Object.assign(t.elements.arrow.style,n.arrow)}}),X={mouseover:"mouseenter",focusin:"focus",click:"click"};var Y={name:"animateFill",defaultValue:!1,fn:function(e){var t;if(null==(t=e.props.render)||!t.$$tippy)return{};var n=S(e.popper),r=n.box,o=n.content,i=e.props.animateFill?function(){var e=d();return e.className="tippy-backdrop",y([e],"hidden"),e}():null;return{onCreate:function(){i&&(r.insertBefore(i,r.firstElementChild),r.setAttribute("data-animatefill",""),r.style.overflow="hidden",e.setProps({arrow:!1,animation:"shift-away"}))},onMount:function(){if(i){var e=r.style.transitionDuration,t=Number(e.replace("ms",""));o.style.transitionDelay=Math.round(t/10)+"ms",i.style.transitionDuration=e,y([i],"visible")}},onShow:function(){i&&(i.style.transitionDuration="0ms")},onHide:function(){i&&y([i],"hidden")}}}};var $={clientX:0,clientY:0},q=[];function z(e){var t=e.clientX,n=e.clientY;$={clientX:t,clientY:n}}var J={name:"followCursor",defaultValue:!1,fn:function(e){var t=e.reference,n=w(e.props.triggerTarget||t),r=!1,o=!1,i=!0,a=e.props;function s(){return"initial"===e.props.followCursor&&e.state.isVisible}function u(){n.addEventListener("mousemove",f)}function c(){n.removeEventListener("mousemove",f)}function p(){r=!0,e.setProps({getReferenceClientRect:null}),r=!1}function f(n){var r=!n.target||t.contains(n.target),o=e.props.followCursor,i=n.clientX,a=n.clientY,s=t.getBoundingClientRect(),u=i-s.left,c=a-s.top;!r&&e.props.interactive||e.setProps({getReferenceClientRect:function(){var e=t.getBoundingClientRect(),n=i,r=a;"initial"===o&&(n=e.left+u,r=e.top+c);var s="horizontal"===o?e.top:r,p="vertical"===o?e.right:n,f="horizontal"===o?e.bottom:r,l="vertical"===o?e.left:n;return{width:p-l,height:f-s,top:s,right:p,bottom:f,left:l}}})}function l(){e.props.followCursor&&(q.push({instance:e,doc:n}),function(e){e.addEventListener("mousemove",z)}(n))}function d(){0===(q=q.filter((function(t){return t.instance!==e}))).filter((function(e){return e.doc===n})).length&&function(e){e.removeEventListener("mousemove",z)}(n)}return{onCreate:l,onDestroy:d,onBeforeUpdate:function(){a=e.props},onAfterUpdate:function(t,n){var i=n.followCursor;r||void 0!==i&&a.followCursor!==i&&(d(),i?(l(),!e.state.isMounted||o||s()||u()):(c(),p()))},onMount:function(){e.props.followCursor&&!o&&(i&&(f($),i=!1),s()||u())},onTrigger:function(e,t){m(t)&&($={clientX:t.clientX,clientY:t.clientY}),o="focus"===t.type},onHidden:function(){e.props.followCursor&&(p(),c(),i=!0)}}}};var G={name:"inlinePositioning",defaultValue:!1,fn:function(e){var t,n=e.reference;var r=-1,o=!1,i=[],a={name:"tippyInlinePositioning",enabled:!0,phase:"afterWrite",fn:function(o){var a=o.state;e.props.inlinePositioning&&(-1!==i.indexOf(a.placement)&&(i=[]),t!==a.placement&&-1===i.indexOf(a.placement)&&(i.push(a.placement),e.setProps({getReferenceClientRect:function(){return function(e){return function(e,t,n,r){if(n.length<2||null===e)return t;if(2===n.length&&r>=0&&n[0].left>n[1].right)return n[r]||t;switch(e){case"top":case"bottom":var o=n[0],i=n[n.length-1],a="top"===e,s=o.top,u=i.bottom,c=a?o.left:i.left,p=a?o.right:i.right;return{top:s,bottom:u,left:c,right:p,width:p-c,height:u-s};case"left":case"right":var f=Math.min.apply(Math,n.map((function(e){return e.left}))),l=Math.max.apply(Math,n.map((function(e){return e.right}))),d=n.filter((function(t){return"left"===e?t.left===f:t.right===l})),v=d[0].top,m=d[d.length-1].bottom;return{top:v,bottom:m,left:f,right:l,width:l-f,height:m-v};default:return t}}(p(e),n.getBoundingClientRect(),f(n.getClientRects()),r)}(a.placement)}})),t=a.placement)}};function s(){var t;o||(t=function(e,t){var n;return{popperOptions:Object.assign({},e.popperOptions,{modifiers:[].concat(((null==(n=e.popperOptions)?void 0:n.modifiers)||[]).filter((function(e){return e.name!==t.name})),[t])})}}(e.props,a),o=!0,e.setProps(t),o=!1)}return{onCreate:s,onAfterUpdate:s,onTrigger:function(t,n){if(m(n)){var o=f(e.reference.getClientRects()),i=o.find((function(e){return e.left-2<=n.clientX&&e.right+2>=n.clientX&&e.top-2<=n.clientY&&e.bottom+2>=n.clientY})),a=o.indexOf(i);r=a>-1?a:r}},onHidden:function(){r=-1}}}};var K={name:"sticky",defaultValue:!1,fn:function(e){var t=e.reference,n=e.popper;function r(t){return!0===e.props.sticky||e.props.sticky===t}var o=null,i=null;function a(){var s=r("reference")?(e.popperInstance?e.popperInstance.state.elements.reference:t).getBoundingClientRect():null,u=r("popper")?n.getBoundingClientRect():null;(s&&Q(o,s)||u&&Q(i,u))&&e.popperInstance&&e.popperInstance.update(),o=s,i=u,e.state.isMounted&&requestAnimationFrame(a)}return{onMount:function(){e.props.sticky&&a()}}}};function Q(e,t){return!e||!t||(e.top!==t.top||e.right!==t.right||e.bottom!==t.bottom||e.left!==t.left)}return F.setDefaultProps({plugins:[Y,J,G,K],render:N}),F.createSingleton=function(e,t){var n;void 0===t&&(t={});var r,o=e,i=[],a=[],c=t.overrides,p=[],f=!1;function l(){a=o.map((function(e){return u(e.props.triggerTarget||e.reference)})).reduce((function(e,t){return e.concat(t)}),[])}function v(){i=o.map((function(e){return e.reference}))}function m(e){o.forEach((function(t){e?t.enable():t.disable()}))}function g(e){return o.map((function(t){var n=t.setProps;return t.setProps=function(o){n(o),t.reference===r&&e.setProps(o)},function(){t.setProps=n}}))}function h(e,t){var n=a.indexOf(t);if(t!==r){r=t;var s=(c||[]).concat("content").reduce((function(e,t){return e[t]=o[n].props[t],e}),{});e.setProps(Object.assign({},s,{getReferenceClientRect:"function"==typeof s.getReferenceClientRect?s.getReferenceClientRect:function(){var e;return null==(e=i[n])?void 0:e.getBoundingClientRect()}}))}}m(!1),v(),l();var b={fn:function(){return{onDestroy:function(){m(!0)},onHidden:function(){r=null},onClickOutside:function(e){e.props.showOnCreate&&!f&&(f=!0,r=null)},onShow:function(e){e.props.showOnCreate&&!f&&(f=!0,h(e,i[0]))},onTrigger:function(e,t){h(e,t.currentTarget)}}}},y=F(d(),Object.assign({},s(t,["overrides"]),{plugins:[b].concat(t.plugins||[]),triggerTarget:a,popperOptions:Object.assign({},t.popperOptions,{modifiers:[].concat((null==(n=t.popperOptions)?void 0:n.modifiers)||[],[W])})})),w=y.show;y.show=function(e){if(w(),!r&&null==e)return h(y,i[0]);if(!r||null!=e){if("number"==typeof e)return i[e]&&h(y,i[e]);if(o.indexOf(e)>=0){var t=e.reference;return h(y,t)}return i.indexOf(e)>=0?h(y,e):void 0}},y.showNext=function(){var e=i[0];if(!r)return y.show(0);var t=i.indexOf(r);y.show(i[t+1]||e)},y.showPrevious=function(){var e=i[i.length-1];if(!r)return y.show(e);var t=i.indexOf(r),n=i[t-1]||e;y.show(n)};var E=y.setProps;return y.setProps=function(e){c=e.overrides||c,E(e)},y.setInstances=function(e){m(!0),p.forEach((function(e){return e()})),o=e,m(!1),v(),l(),p=g(y),y.setProps({triggerTarget:a})},p=g(y),y},F.delegate=function(e,n){var r=[],o=[],i=!1,a=n.target,c=s(n,["target"]),p=Object.assign({},c,{trigger:"manual",touch:!1}),f=Object.assign({touch:R.touch},c,{showOnCreate:!0}),l=F(e,p);function d(e){if(e.target&&!i){var t=e.target.closest(a);if(t){var r=t.getAttribute("data-tippy-trigger")||n.trigger||R.trigger;if(!t._tippy&&!("touchstart"===e.type&&"boolean"==typeof f.touch||"touchstart"!==e.type&&r.indexOf(X[e.type])<0)){var s=F(t,f);s&&(o=o.concat(s))}}}}function v(e,t,n,o){void 0===o&&(o=!1),e.addEventListener(t,n,o),r.push({node:e,eventType:t,handler:n,options:o})}return u(l).forEach((function(e){var n=e.destroy,a=e.enable,s=e.disable;e.destroy=function(e){void 0===e&&(e=!0),e&&o.forEach((function(e){e.destroy()})),o=[],r.forEach((function(e){var t=e.node,n=e.eventType,r=e.handler,o=e.options;t.removeEventListener(n,r,o)})),r=[],n()},e.enable=function(){a(),o.forEach((function(e){return e.enable()})),i=!1},e.disable=function(){s(),o.forEach((function(e){return e.disable()})),i=!0},function(e){var n=e.reference;v(n,"touchstart",d,t),v(n,"mouseover",d),v(n,"focusin",d),v(n,"click",d)}(e)})),l},F.hideAll=function(e){var t=void 0===e?{}:e,n=t.exclude,r=t.duration;U.forEach((function(e){var t=!1;if(n&&(t=g(n)?e.reference===n:e.popper===n.popper),!t){var o=e.props.duration;e.setProps({duration:r}),e.hide(),e.state.isDestroyed||e.setProps({duration:o})}}))},F.roundArrow='',F})); - diff --git a/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/uncertainty.html b/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/uncertainty.html deleted file mode 100644 index dc681268d..000000000 --- a/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/uncertainty.html +++ /dev/null @@ -1,1770 +0,0 @@ - - - - - - - - - - - -Uncertainty Analysis Using PEcAn - - - - - - - - - - - - - - - - - - - -
- -
- -
-
-

Uncertainty Analysis Using PEcAn

-
- - - -
- -
-
Authors
-
-

Aritra Dey

-

David LeBauer

-
-
- - - -
- - - -
- - -
-

Introduction

-

In Demo 2 we will be looking at how PEcAn can use information about parameter uncertainty to perform three automated analyses:

-
    -
  • Ensemble Analysis: Repeat numerous model runs, each sampling from the parameter uncertainty, to generate a probability distribution of model projections. Allows us to put a confidence interval on the model.
  • -
  • Sensitivity Analysis: Repeats numerous model runs to assess how changes in model parameters will affect model outputs. Allows us to identify which parameters the model is most sensitive to.
  • -
  • Uncertainty Analysis: Combines information about model sensitivity with information about parameter uncertainty to determine the contribution of each model parameter to the uncertainty in model outputs. Allow us to identify which parameters are driving model uncertainty.
  • -
-

This demo shows how to run an uncertainty analysis workflow in PEcAn using an R-based Quarto notebook. It covers loading settings, configuring models, running simulations, and performing ensemble and sensitivity analyses to assess uncertainty and parameter importance. This programmatic approach complements the web-based PEcAn interface.

-

Context & modeling scenario:

-

We simulate plant and ecosystem carbon balance (Net Primary Productivity and Net Ecosystem Exchange) at the AmeriFlux Niwot Ridge Forest site (US‑NR1) during the year 2004. We use SIPNET parameterized as a temperate conifer PFT and driven by AmeriFlux meteorology following the analysis in Moore et al. (2007). This notebook also provides a compact template that can be extended to more years, locations, and PFTs.

-

What this notebook does:

-
    -
  1. Configure a PEcAn workflow by loading and validating a pecan.xml settings file.
  2. -
  3. Run a set of ecosystem model simulations by writing model configuration files and then running SIPNET.
  4. -
  5. Quantify uncertainty using ensemble analysis, sensitivity analyses, and variance decomposition.
  6. -
  7. Visualize results to identify important parameters and how they influence model variance.
  8. -
  9. Change configuration settings and re-run the workflow.
  10. -
-
-

Prerequisites

-

To run this notebook, you will need to install PEcAn and its dependencies, as well as download the SIPNET model binary.

-
-

PEcAn packages and dependencies.

-
# Enable repository from pecanproject
-options(repos = c(
-  pecanproject = 'https://pecanproject.r-universe.dev',
-  CRAN = 'https://cloud.r-project.org'))
-install.packages('PEcAn.all')
-

A valid pecan.xml configuration file. Start with the example at pecan/documentation/tutorials/Demo_02_Uncertainty_Analysis/pecan.xml.

-
-
-

SIPNET v1.3.0

-

If you haven’t already installed the SIPNET model, you can do so by running the following code. This will download the SIPNET binary to demo_outdir/sipnet and make it executable.

-
-

Note: The demo_outdir directory will be created inside of your PEcAn installation, at documentation/tutorials/Demo_02_Uncertainty_Analysis/demo_outdir/. This directory will contain the SIPNET binary as well as the output generated by PEcAn in this demo.

-
-
-
# Download and install SIPNET v1.3.0
-source(
-  here::here(
-    "documentation/tutorials/Demo_1_Basic_Run/download_sipnet.R"
-  )
-)
-
-
-

Note: You can find the most recent version of the SIPNET binary at: SIPNET GitHub Releases, but this notebook is designed to work with SIPNET v1.3.0.

-
-
-
-
-
-

Load PEcAn Packages

-

First, we need to load the PEcAn R packages. These packages provide all the functions we’ll use to run the workflow.

-
-
# Load the PEcAn.all package, which includes all necessary PEcAn functionality
-library("PEcAn.all")
-
-
Loading required package: PEcAn.DB
-
-
-
Loading required package: PEcAn.settings
-
-
-
Loading required package: PEcAn.MA
-
-
-
Loading required package: PEcAn.logger
-
-
-
Loading required package: PEcAn.utils
-
-
-
Loading required package: PEcAn.uncertainty
-
-
-
Loading required package: PEcAn.data.atmosphere
-
-
-
Loading required package: PEcAn.data.land
-
-
-
Loading required package: PEcAn.data.remote
-
-
-
Loading required package: PEcAn.assim.batch
-
-
-
Loading required package: PEcAn.emulator
-
-
-
Loading required package: PEcAn.priors
-
-
-
Loading required package: PEcAn.benchmark
-
-
-
Loading required package: PEcAn.remote
-
-
-
Loading required package: PEcAn.workflow
-
-
-
-
-

Load PEcAn Settings File

-

Use the XML settings file (pecan.xml) exactly as in the Demo 1 Basic Run tutorial. See the “Load PEcAn Settings File” section of Demo 1 for a more detailed walkthrough of fields and schema. In this tutorial we focus on settings relevant to this notebook and explain the additional options associated with uncertainty analysis.

-
-

Settings

-

Example settings for this demo live at pecan/documentation/tutorials/Demo_02_Uncertainty_Analysis/pecan.xml and you can read more about the settings in the PEcAn Documentation, and sections focused on ensemble and sensitivity analysis settings in particular.

-

Open that settings file and look at the ensemble and sensitivity analysis sections. You can modify these settings to change the number of ensemble members, the variable to analyze, and the sampling method. Some of the key settings in this demo include:

-

Ensemble size

-

The number of runs in the ensemble is set to 50 in this demo, but a larger ensemble size (100-5000) is often used in practice to better estimate the posterior distribution of the output.

-

Output variable

-

The output variable for the ensemble analysis is set to NPP (Net Primary Productivity). You can change this to other variables like NEE (Net Ecosystem Exchange), LAI (Leaf Area Index), ET (Evapotranspiration), etc. You can also specify multiple variables by providing a vector of variable names (e.g., c("NPP", "NEE", "LAI")) to analyze uncertainty across several ecosystem processes simultaneously.

-

Sampling method

-

The sampling method for generating parameter sets is set to halton in this demo. This tells PEcAn to sample using the Halton sequence, which is a quasi-random sampling method that more efficiently explores parameter space than random sampling. Other options include Latin Hypercube (lhc), which is another quasi-random sequence, as well as uniform that draws random samples. A random sampler requires a larger ensemble size to adequately explore parameter space.

-

Sensitivity analysis quantiles

-

PEcAn’s sensitivity analysis includes a handy shortcut that converts a specified standard deviation into its normal quantile equivalent. In the example pecan.xml, these are set to -1, 1 (the median value, 0, occurs by default) which are converted internally to the 15.9th and 84.1th quantiles of the parameter distribution. You can add more quantiles to explore a wider range of parameter values: {-3, -2, -1, 1, 2, 3} is often used in practice.

-

By working in quantiles relative to each parameter’s distribution, the sensitivity and variance decomposition reflect sensitivity across the range of parameter values. Many sensitivity analyses tools use a fixed perturbation size such as the mean +/- 10%. PEcAn’s SA does not take this approach because it does not capture the uncertainty across the parameter distribution and can not be used for variance decomposition.

-
-
-

Load the settings file

-
-
settings_path <- here::here("documentation/tutorials/Demo_02_Uncertainty_Analysis/pecan.xml")
-
-settings <- PEcAn.settings::read.settings(settings_path)
-
-settings <- PEcAn.settings::prepare.settings(settings)
-
-

See Demo 1 Section 6 for details on what these functions do. Briefly, they read the XML file, convert it into an R list object that PEcAn can use, check that settings are valid, fill in defaults, and create the output directory.

-
-
-
-

Write Model Configuration Files

-

This step generates the model-specific configuration files that will be used to run the ecosystem model. The process involves:

-
    -
  1. Disabling database write operations because we are not using a database
  2. -
-
-
settings$database <- NULL # Disable database operations for this demo
-
-
    -
  1. Generating SIPNET configuration files using the runModule.run.write.configs() function.
  2. -
-
-
settings <- PEcAn.workflow::runModule.run.write.configs(settings)
-
-
Error in postgresqlNewConnection(drv, ...) : 
-  RPosgreSQL error: could not connect root@/var/run/postgresql:5432 on dbname "root": connection to server on socket "/var/run/postgresql/.s.PGSQL.5432" failed: No such file or directory
-    Is the server running locally and accepting connections on that socket?
-
-
-
Loading required package: PEcAn.SIPNET
-
-
-
-
-

Run Model Simulations

-

This section executes the SIPNET simulations and retrieves the results.

-

It uses the function runModule_start_model_runs(settings) to initiate the model runs using the configuration files generated in the previous step.

-
-
PEcAn.workflow::runModule_start_model_runs(settings)
-
-

-  |                                                                            
-  |                                                                      |   0%
-  |                                                                            
-  |=                                                                     |   1%
-  |                                                                            
-  |==                                                                    |   2%
-  |                                                                            
-  |==                                                                    |   3%
-  |                                                                            
-  |===                                                                   |   4%
-  |                                                                            
-  |====                                                                  |   6%
-  |                                                                            
-  |=====                                                                 |   7%
-  |                                                                            
-  |======                                                                |   8%
-  |                                                                            
-  |======                                                                |   9%
-  |                                                                            
-  |=======                                                               |  10%
-  |                                                                            
-  |========                                                              |  11%
-  |                                                                            
-  |=========                                                             |  12%
-  |                                                                            
-  |=========                                                             |  13%
-  |                                                                            
-  |==========                                                            |  15%
-  |                                                                            
-  |===========                                                           |  16%
-  |                                                                            
-  |============                                                          |  17%
-  |                                                                            
-  |=============                                                         |  18%
-  |                                                                            
-  |=============                                                         |  19%
-  |                                                                            
-  |==============                                                        |  20%
-  |                                                                            
-  |===============                                                       |  21%
-  |                                                                            
-  |================                                                      |  22%
-  |                                                                            
-  |=================                                                     |  24%
-  |                                                                            
-  |=================                                                     |  25%
-  |                                                                            
-  |==================                                                    |  26%
-  |                                                                            
-  |===================                                                   |  27%
-  |                                                                            
-  |====================                                                  |  28%
-  |                                                                            
-  |====================                                                  |  29%
-  |                                                                            
-  |=====================                                                 |  30%
-  |                                                                            
-  |======================                                                |  31%
-  |                                                                            
-  |=======================                                               |  33%
-  |                                                                            
-  |========================                                              |  34%
-  |                                                                            
-  |========================                                              |  35%
-  |                                                                            
-  |=========================                                             |  36%
-  |                                                                            
-  |==========================                                            |  37%
-  |                                                                            
-  |===========================                                           |  38%
-  |                                                                            
-  |============================                                          |  39%
-  |                                                                            
-  |============================                                          |  40%
-  |                                                                            
-  |=============================                                         |  42%
-  |                                                                            
-  |==============================                                        |  43%
-  |                                                                            
-  |===============================                                       |  44%
-  |                                                                            
-  |===============================                                       |  45%
-  |                                                                            
-  |================================                                      |  46%
-  |                                                                            
-  |=================================                                     |  47%
-  |                                                                            
-  |==================================                                    |  48%
-  |                                                                            
-  |===================================                                   |  49%
-  |                                                                            
-  |===================================                                   |  51%
-  |                                                                            
-  |====================================                                  |  52%
-  |                                                                            
-  |=====================================                                 |  53%
-  |                                                                            
-  |======================================                                |  54%
-  |                                                                            
-  |=======================================                               |  55%
-  |                                                                            
-  |=======================================                               |  56%
-  |                                                                            
-  |========================================                              |  57%
-  |                                                                            
-  |=========================================                             |  58%
-  |                                                                            
-  |==========================================                            |  60%
-  |                                                                            
-  |==========================================                            |  61%
-  |                                                                            
-  |===========================================                           |  62%
-  |                                                                            
-  |============================================                          |  63%
-  |                                                                            
-  |=============================================                         |  64%
-  |                                                                            
-  |==============================================                        |  65%
-  |                                                                            
-  |==============================================                        |  66%
-  |                                                                            
-  |===============================================                       |  67%
-  |                                                                            
-  |================================================                      |  69%
-  |                                                                            
-  |=================================================                     |  70%
-  |                                                                            
-  |==================================================                    |  71%
-  |                                                                            
-  |==================================================                    |  72%
-  |                                                                            
-  |===================================================                   |  73%
-  |                                                                            
-  |====================================================                  |  74%
-  |                                                                            
-  |=====================================================                 |  75%
-  |                                                                            
-  |=====================================================                 |  76%
-  |                                                                            
-  |======================================================                |  78%
-  |                                                                            
-  |=======================================================               |  79%
-  |                                                                            
-  |========================================================              |  80%
-  |                                                                            
-  |=========================================================             |  81%
-  |                                                                            
-  |=========================================================             |  82%
-  |                                                                            
-  |==========================================================            |  83%
-  |                                                                            
-  |===========================================================           |  84%
-  |                                                                            
-  |============================================================          |  85%
-  |                                                                            
-  |=============================================================         |  87%
-  |                                                                            
-  |=============================================================         |  88%
-  |                                                                            
-  |==============================================================        |  89%
-  |                                                                            
-  |===============================================================       |  90%
-  |                                                                            
-  |================================================================      |  91%
-  |                                                                            
-  |================================================================      |  92%
-  |                                                                            
-  |=================================================================     |  93%
-  |                                                                            
-  |==================================================================    |  94%
-  |                                                                            
-  |===================================================================   |  96%
-  |                                                                            
-  |====================================================================  |  97%
-  |                                                                            
-  |====================================================================  |  98%
-  |                                                                            
-  |===================================================================== |  99%
-  |                                                                            
-  |======================================================================| 100%
-
-
-

The PEcAn workflow will take a longer time to complete than in Demo 1 because we have just asked for over a hundred model runs. Once the runs are complete we will continue.

-
-
-

Fetch Model Outputs

-

Next we convert all of the model output from the previous run to a standard format that PEcAn can use for analysis. This is done using the runModule.get.results() function.

-
-
runModule.get.results(settings)
-
-
-
-

Ensemble and Sensitivity Analysis

-

Next, we use the outputs from the previous step to perform ensemble and sensitivity analyses.

-

Ensemble Analysis: Quantifies uncertainty in model predictions by running multiple simulations with parameters sampled from their uncertainty distributions. This generates probability distributions of model outputs and confidence intervals.

-
-
runModule.run.ensemble.analysis(settings)
-
-
[1] "----- Variable: NPP"
-[1] "----- Running ensemble analysis for site:  Niwot Ridge Forest/LTER NWT1 (US-NR1)"
-
-
-
[1] "----- Done!"
-[1] " "
-[1] "-----------------------------------------------"
-[1] " "
-[1] " "
-
-
-

Sensitivity Analysis: Systematically varies individual parameters to assess their influence on model outputs. This identifies which parameters most strongly affect model predictions and helps prioritize parameter refinement efforts.

-
-
runModule.run.sensitivity.analysis(settings)
-
-
$coef.vars
-         growth_resp_factor          leaf_turnover_rate 
-                 0.52314023                  0.88169612 
-      root_respiration_rate          root_turnover_rate 
-                 0.57750504                  0.57760373 
-                       Amax    leaf_respiration_rate_m2 
-                 0.57764863                  0.55600452 
-                        SLA                       leafC 
-                 0.80223473                  0.02607590 
-                Vm_low_temp                    AmaxFrac 
-                 0.01097613                  0.11546966 
-                    psnTOpt       stem_respiration_rate 
-                 0.03417927                  0.57838935 
-     extinction_coefficient         half_saturation_PAR 
-                 0.13855053                  0.42885852 
-                  dVPDSlope                     dVpdExp 
-                 0.53356551                  0.28896893 
-        veg_respiration_Q10   fine_root_respiration_Q10 
-                 0.17324390                  0.32501552 
-coarse_root_respiration_Q10 
-                 0.32534666 
-
-$elasticities
-         growth_resp_factor          leaf_turnover_rate 
-                 0.00000000                  0.02320464 
-      root_respiration_rate          root_turnover_rate 
-                -0.02508999                  0.05192989 
-                       Amax    leaf_respiration_rate_m2 
-                 2.83476962                 -2.06513816 
-                        SLA                       leafC 
-                 0.81446798                  0.15306831 
-                Vm_low_temp                    AmaxFrac 
-                 1.01795920                  2.48502840 
-                    psnTOpt       stem_respiration_rate 
-                 1.01055079                 -1.43854509 
-     extinction_coefficient         half_saturation_PAR 
-                -0.57229325                 -1.28681308 
-                  dVPDSlope                     dVpdExp 
-                -0.18295933                  0.09271587 
-        veg_respiration_Q10   fine_root_respiration_Q10 
-                 6.50084187                  0.08360650 
-coarse_root_respiration_Q10 
-                -0.23722866 
-
-$sensitivities
-         growth_resp_factor          leaf_turnover_rate 
-               0.000000e+00                9.970835e-11 
-      root_respiration_rate          root_turnover_rate 
-              -2.359663e-12                4.884707e-11 
-                       Amax    leaf_respiration_rate_m2 
-               6.666635e-10               -1.944744e-09 
-                        SLA                       leafC 
-               2.732070e-10                1.422201e-11 
-                Vm_low_temp                    AmaxFrac 
-              -9.748919e-10                1.557956e-08 
-                    psnTOpt       stem_respiration_rate 
-               2.423273e-10               -1.355162e-10 
-     extinction_coefficient         half_saturation_PAR 
-              -5.381744e-09               -3.907003e-10 
-                  dVPDSlope                     dVpdExp 
-              -6.624579e-09                2.181281e-10 
-        veg_respiration_Q10   fine_root_respiration_Q10 
-               1.528495e-08                1.229585e-10 
-coarse_root_respiration_Q10 
-              -3.491744e-10 
-
-$variances
-         growth_resp_factor          leaf_turnover_rate 
-               5.983871e-50                1.785332e-20 
-      root_respiration_rate          root_turnover_rate 
-               4.672753e-21                2.193432e-20 
-                       Amax    leaf_respiration_rate_m2 
-               6.122857e-17                2.785313e-17 
-                        SLA                       leafC 
-               1.096593e-17                3.746338e-22 
-                Vm_low_temp                    AmaxFrac 
-               8.542850e-18                1.822057e-18 
-                    psnTOpt       stem_respiration_rate 
-               5.995813e-18                1.530077e-17 
-     extinction_coefficient         half_saturation_PAR 
-               1.389601e-19                6.768366e-18 
-                  dVPDSlope                     dVpdExp 
-               2.123853e-19                1.622220e-20 
-        veg_respiration_Q10   fine_root_respiration_Q10 
-               2.851950e-17                1.785504e-20 
-coarse_root_respiration_Q10 
-               1.316744e-19 
-
-$partial.variances
-         growth_resp_factor          leaf_turnover_rate 
-               3.571204e-34                1.065495e-04 
-      root_respiration_rate          root_turnover_rate 
-               2.788722e-05                1.309051e-04 
-                       Amax    leaf_respiration_rate_m2 
-               3.654152e-01                1.662288e-01 
-                        SLA                       leafC 
-               6.544522e-02                2.235833e-06 
-                Vm_low_temp                    AmaxFrac 
-               5.098415e-02                1.087413e-02 
-                    psnTOpt       stem_respiration_rate 
-               3.578331e-02                9.131574e-02 
-     extinction_coefficient         half_saturation_PAR 
-               8.293210e-04                4.039395e-02 
-                  dVPDSlope                     dVpdExp 
-               1.267526e-03                9.681491e-05 
-        veg_respiration_Q10   fine_root_respiration_Q10 
-               1.702058e-01                1.065597e-04 
-coarse_root_respiration_Q10 
-               7.858395e-04 
-
-       growth_resp_factor leaf_turnover_rate root_respiration_rate
-15.866       4.701256e-09       4.449915e-09          4.793975e-09
-50           4.701256e-09       4.701256e-09          4.701256e-09
-84.134       4.701256e-09       4.739615e-09          4.632887e-09
-       root_turnover_rate          Amax leaf_respiration_rate_m2          SLA
-15.866       4.437930e-09 -7.392576e-09             9.995320e-09 7.454526e-10
-50           4.701256e-09  4.701256e-09             4.701256e-09 4.701256e-09
-84.134       4.771365e-09  1.080759e-08            -8.726093e-10 4.574289e-10
-              leafC  Vm_low_temp     AmaxFrac       psnTOpt
-15.866 4.689967e-09 6.977459e-09 3.003852e-09 -5.232746e-09
-50     4.701256e-09 4.701256e-09 4.701256e-09  4.701256e-09
-84.134 4.727503e-09 1.776842e-09 6.194027e-09  7.597368e-09
-       stem_respiration_rate extinction_coefficient half_saturation_PAR
-15.866          9.335914e-09           5.145403e-09        8.187772e-09
-50              4.701256e-09           4.701256e-09        4.701256e-09
-84.134          8.203046e-11           4.264066e-09        2.050097e-09
-          dVPDSlope      dVpdExp veg_respiration_Q10 fine_root_respiration_Q10
-15.866 5.155744e-09 4.511517e-09       -3.046701e-09              4.466264e-09
-50     4.701256e-09 4.701256e-09        4.701256e-09              4.701256e-09
-84.134 4.070785e-09 4.809312e-09        9.472557e-09              4.768234e-09
-       coarse_root_respiration_Q10
-15.866                5.142842e-09
-50                    4.701256e-09
-84.134                4.284874e-09
-
-
-
-
-

PEcAn Outputs

-
-

Output Directory Structure

-

These are the key folders and files that will be created under the directory defined by settings$outdir (e.g., demo_outdir in the example). The file contents are described in the next section.

-

We discussed the output directory in Demo 1 (Basic Run), but now we have three new folders that contain outputs from the sensitivity, ensemble, and variance decomposition analyses. Here we focus on the additional outputs generated by the ensemble and sensitivity analyses.

-
demo_outdir/
-├── run/                                    # Configuration & execution metadata
-│   ├── runs.txt                           # List of run IDs (SA and ensemble runs)
-│   ├── ENS-*-*/                          # Ensemble run directories (e.g., ENS-00001--1/)
-│   └── SA-*-*/                           # Sensitivity analysis run directories
-├── out/                                   # Raw model outputs by run ID
-│   └── <runid>/                          # E.g., daily or sub-daily SIPNET output files
-├── ensemble.analysis.*.pdf                # Ensemble analysis plots
-├── ensemble.output.*.Rdata               # Raw ensemble outputs
-├── ensemble.samples.*.Rdata              # Parameter samples used for ensemble
-├── ensemble.ts.*.Rdata                   # Time series data from ensemble
-├── samples.Rdata                         # Parameter samples for both SA and ensemble
-├── sensitivity.output.*.Rdata            # SA model outputs
-├── sensitivity.results.*.Rdata           # Processed SA results
-├── sensitivity.samples.*.Rdata           # SA parameter samples
-├── variance.decomposition.*.pdf          # Variance decomposition analysis
-├── pft/                                  # Parameter (prior/posterior) files per PFT
-│   └── temperate.coniferous/
-└── sipnet                                # SIPNET binary (downloaded earlier)
-
-

Model outputs and logs

-
    -
  • Standardized netCDF files ([year].nc) for analysis and visualization
  • -
  • Raw model output (for SIPNET, e.g., sipnet.out per run)
  • -
  • logfile.txt with model and workflow messages
  • -
  • Note: pft/ contains parameter files used in estimation; see the parameter-estimation tutorial (Demo 3) for details
  • -
-
-
-
-
-

Understanding PEcAn Uncertainty Analysis Outputs

-

After running ensemble and sensitivity analyses, PEcAn generates several important outputs that help you understand model uncertainty and parameter sensitivity.

-

The samples.Rdata file contains the parameter values used in the sensitivity and ensemble runs. It stores two objects, sa.samples and ensemble.samples, which are the parameter values for the sensitivity analysis and ensemble runs, respectively.

-
-

Ensemble Analysis Outputs

-

The ensemble analysis produces:

-
    -
  • ensemble.Rdata: Contains ensemble.output object with model predictions for all ensemble members
  • -
  • ensemble.analysis.[RunID].[Variable].[StartYear].[EndYear].pdf: Histogram and boxplot of ensemble predictions
  • -
  • ensemble.ts.[RunID].[Variable].[StartYear].[EndYear].pdf: Time-series plot showing ensemble mean, median, and 95% confidence intervals
  • -
-
-
-

Sensitivity Analysis Outputs

-

The sensitivity analysis generates:

-
    -
  • sensitivity.analysis.[RunID].[Variable].[StartYear].[EndYear].pdf: Raw data points from univariate analyses with spline fits.
  • -
  • sensitivity.output.[RunID].[Variable].[StartYear].[EndYear].Rdata: Model outputs corresponding to parameter variations.
  • -
  • sensitivity.analysis.[RunID].[Variable].[StartYear].[EndYear].pdf shows the raw data points from univariate one-at-a-time analyses and spline fits through the points. Open this file to determine which parameters are most and least sensitive.
  • -
-
-
-

Variance Decomposition Outputs

-

The variance decomposition produces:

-
    -
  • variance.decomposition.[RunID].[Variable].[StartYear].[EndYear].pdf: Three-column analysis showing: -
      -
    • Coefficient of variation (normalized posterior variance)
    • -
    • Elasticity (normalized sensitivity)
    • -
    • Partial standard deviation of each parameter
    • -
  • -
-
-
-

Interpreting the Results

-

Variance Decomposition Analysis:

-
    -
  • Parameters are sorted by their contribution to model output uncertainty (the right column).
  • -
  • Identify parameters that are: -
      -
    • Highly sensitive but low uncertainty.
    • -
    • Highly uncertain but low sensitivity.
    • -
    • Both sensitive and uncertain.
    • -
  • -
  • Identify parameters that are both sensitive and uncertain for future constraint with data or expert knowledge.
  • -
  • Potential gotchas: -
      -
    • Flat sensitivity curves: check that parameter values were correctly generated and read by the model.
    • -
    • Parameters with high uncertainty: consider revising priors.
    • -
    • Multi-modal or otherwise unexpected parameter distributions: check that parameter was specified correctly.
    • -
  • -
-

Choose the parameter that you think provides the most efficient means of reducing model uncertainty and propose how you might best reduce uncertainty in this process. In making this choice remember that not all processes in models can be directly observed, and that the cost-per-sample for different measurements can vary tremendously (and thus the parameter you measure next is not always the one contributing the most to model variability). Also consider the role of parameter uncertainty versus model sensitivity in justifying your choice of what parameters to constrain.

-
-
-
-

Visualize Uncertainty Analysis Results

-

This section loads the results from the uncertainty analyses and generates plots directly in the notebook. This provides an immediate view of the ensemble time series, sensitivity plots, and variance decomposition.

-
-

Ensemble Analysis Visualization

-

Here we visualize the results of the ensemble analysis. It shows the overall distribution of the model output and how the output and its uncertainty change over time.

-

This section reproduces the plots saved in the ensemble.analysis/ folder in order to show the user how to access and visualize the results programmatically so that they can further investigate output and customize plots.

-
-
# --- 1. Define Helper Variables ---
-# Extract key variables from the settings object to simplify file path construction
-# and plotting. This makes the code cleaner and easier to read.
-variable <- settings$ensemble$variable
-pft <- settings$pfts[[1]]
-start.year <- lubridate::year(settings$run$start.date)
-end.year <- lubridate::year(settings$run$end.date)
-ensemble.id <- if (!is.null(settings$ensemble$id)) settings$ensemble$id else "NOENSEMBLEID"
-
-# --- 2. Load and Plot Ensemble Output Distribution ---
-# This section visualizes the distribution of the ensemble model runs.
-# It generates a histogram and a boxplot to show the central tendency, spread,
-# and shape of the output variable's distribution.
-
-# Construct the path to the ensemble output file
-ens_file <- PEcAn.uncertainty::ensemble.filename(
-  settings,
-  prefix = "ensemble.output",
-  ensemble.id = ensemble.id,
-  variable = variable,
-  start.year = start.year,
-  end.year = end.year
-)
-
-# Check if the file exists, then load and plot the data
-if (file.exists(ens_file)) {
-  ens_env <- new.env()
-  load(ens_file, envir = ens_env)
-  ens_data <- as.numeric(unlist(ens_env$ensemble.output))
-
-  # Define units for plot labels
-  units <- paste0(variable, " (", PEcAn.utils::mstmipvar(variable, silent = TRUE)$units, ")")
-
-  # Create side-by-side histogram and boxplot
-  par(mfrow = c(1, 2), mar = c(4, 4.8, 1, 2))
-  hist(ens_data, xlab = units, main = "Ensemble Distribution", cex.lab = 1.4, col = "grey85")
-  box(lwd = 2.2)
-  boxplot(ens_data, ylab = units, main = "Ensemble Boxplot", col = "grey85", cex.lab = 1.5)
-  box(lwd = 2.2)
-  par(mfrow = c(1, 1))
-} else {
-  PEcAn.logger::logger.warn("Could not find ensemble output file:", ens_file)
-}
-
-
-# --- 3. Plot Ensemble Time Series ---
-# This section visualizes the ensemble results over time, showing the mean,
-# median, and 95% confidence interval of the model output.
-ens_ts_data <- PEcAn.uncertainty::read.ensemble.ts(settings, variable = variable)
-
-
[1] "----- Variable: NPP"
-[1] "----- Reading ensemble output ------"
-[1] "ENS-00001--1"
-[1] "ENS-00002--1"
-[1] "ENS-00003--1"
-[1] "ENS-00004--1"
-[1] "ENS-00005--1"
-[1] "ENS-00006--1"
-[1] "ENS-00007--1"
-[1] "ENS-00008--1"
-[1] "ENS-00009--1"
-[1] "ENS-00010--1"
-[1] "ENS-00011--1"
-[1] "ENS-00012--1"
-[1] "ENS-00013--1"
-[1] "ENS-00014--1"
-[1] "ENS-00015--1"
-[1] "ENS-00016--1"
-[1] "ENS-00017--1"
-[1] "ENS-00018--1"
-[1] "ENS-00019--1"
-[1] "ENS-00020--1"
-[1] "ENS-00021--1"
-[1] "ENS-00022--1"
-[1] "ENS-00023--1"
-[1] "ENS-00024--1"
-[1] "ENS-00025--1"
-[1] "ENS-00026--1"
-[1] "ENS-00027--1"
-[1] "ENS-00028--1"
-[1] "ENS-00029--1"
-[1] "ENS-00030--1"
-[1] "ENS-00031--1"
-[1] "ENS-00032--1"
-[1] "ENS-00033--1"
-[1] "ENS-00034--1"
-[1] "ENS-00035--1"
-[1] "ENS-00036--1"
-[1] "ENS-00037--1"
-[1] "ENS-00038--1"
-[1] "ENS-00039--1"
-[1] "ENS-00040--1"
-[1] "ENS-00041--1"
-[1] "ENS-00042--1"
-[1] "ENS-00043--1"
-[1] "ENS-00044--1"
-[1] "ENS-00045--1"
-[1] "ENS-00046--1"
-[1] "ENS-00047--1"
-[1] "ENS-00048--1"
-[1] "ENS-00049--1"
-[1] "ENS-00050--1"
-
-
if (!is.null(ens_ts_data)) {
-  PEcAn.uncertainty::ensemble.ts(ens_ts_data)
-}
-
-
[1] "------ Generating ensemble time-series plot ------"
-
-
-
-
-

-
-
-
-
-
-
-

Sensitivity and Variance Decomposition Visualization

-

This block visualizes the results of the sensitivity analysis. The plots show how sensitive the model output is to changes in each parameter and which parameters contribute most to the overall uncertainty.

-
-
# --- 1. Load Sensitivity Analysis Results ---
-# This section loads the saved sensitivity analysis data, which contains the
-# outputs needed to generate the sensitivity and variance decomposition plots.
-
-# Construct the path to the sensitivity analysis results file
-sens_file <- file.path(
-  settings$outdir,
-  paste0("sensitivity.results", ".", ensemble.id, ".", variable, ".", start.year, ".", end.year, ".Rdata")
-)
-
-# Check if the file exists, then load the data and generate plots
-if (file.exists(sens_file)) {
-  sens_env <- new.env()
-  load(sens_file, envir = sens_env)
-  sensitivity.results <- sens_env$sensitivity.results
-
-  # --- 2. Generate Sensitivity Plots ---
-  # These plots show how the model output changes as each parameter is varied
-  # one at a time, helping to identify which parameters have the strongest influence.
-  sa_plots <- PEcAn.uncertainty::plot_sensitivities(
-    sensitivity.results[[pft$name]]$sensitivity.output
-  )
-  print(do.call(gridExtra::grid.arrange, c(sa_plots, ncol = floor(sqrt(length(sa_plots))))))
-
-  # --- 3. Generate Variance Decomposition Plots ---
-  # These plots break down the total output variance into contributions from
-  # each parameter, highlighting the most important sources of uncertainty.
-  vd_plots <- PEcAn.uncertainty::plot_variance_decomposition(
-    sensitivity.results[[pft$name]]$variance.decomposition.output
-  )
-  print(do.call(gridExtra::grid.arrange, c(vd_plots, ncol = 4)))
-} else {
-  PEcAn.logger::logger.warn("Could not find sensitivity results file:", sens_file)
-}
-
-
-
-
-

Customizing Ensemble Analysis Parameters (Optional)

-
-

(Optional) Use this section only if you want to override the default ensemble analysis parameters. Skip if defaults are sufficient.

-
-

Important: If you modify the ensemble analysis parameters in this section, re-run Section Section 7 and then Section Section 10 to regenerate outputs and plots.

-
-
-
# Set the number of ensemble members (model runs)
-settings$ensemble$size <- 50
-
-# Specify the variable(s) to be analyzed in the ensemble
-# Single variable:
-settings$ensemble$variable <- "NEE"
-# Multiple variables (uncomment to use):
-# settings$ensemble$variable <- c("NEE", "NPP", "LAI")
-
-# Choose the method for sampling the parameter space (options: "uniform", "lhc", "halton", "sobol", "torus")
-settings$ensemble$samplingspace$parameters$method <- "halton"
-
-
-
-
-

Customizing Sensitivity Analysis Parameters (Optional)

-
-

(Optional) Use this section only if you want to override the default sensitivity analysis parameters. Skip if defaults are sufficient.

-
-

Important: If you modify the sensitivity analysis parameters in this section, re-run Section Section 7 and then Section Section 10 to regenerate outputs and plots.

-
-
-
# Set the quantiles (in standard deviations) for parameter distribution in sensitivity analysis
-settings$sensitivity.analysis$quantiles$sigma <- c(-2, -1, 1, 2)
-
-# Specify the variable to be analyzed in sensitivity analysis
-settings$sensitivity.analysis$variable <- "NEE"
-
-
-
-
-

Extract Model Results and Prepare for Analysis

-

After the model simulation completes, we need to extract the results and prepare them for analysis. This involves:

-
    -
  1. Reading the run ID
  2. -
  3. Setting up output paths
  4. -
  5. Defining time period
  6. -
  7. Loading model output
  8. -
-
-
runid <- as.character(read.table(paste(settings$outdir, "/run/", "runs.txt", sep = ""))[1, 1]) # Note: if you are using an xml from a run with multiple ensembles this line will provide only the first run id
-# You can change [1,1] to [10,1], [5,1], etc. to select different run IDs from runs.txt
-# For example: [10,1] selects the 10th run ID, [5,1] selects the 5th run ID
-outdir <- paste(settings$outdir, "/out/", runid, sep = "")
-start.year <- as.numeric(lubridate::year(settings$run$start.date))
-end.year <- as.numeric(lubridate::year(settings$run$end.date))
-model_output <- PEcAn.utils::read.output(
-  runid,
-  outdir,
-  start.year,
-  end.year,
-  variables = NULL,
-  dataframe = TRUE,
-  verbose = FALSE
-)
-available_vars <- names(model_output)[!names(model_output) %in% c("posix", "time_bounds")]
-
-
-
-

Display Available Model Variables

-

This section shows all the variables that are available in the model output. These variables represent different ecosystem processes and states that the model has simulated.

-
-
vars_df <- PEcAn.utils::standard_vars |>
-  dplyr::select(
-    Variable = Variable.Name,
-    Description = Long.name
-  ) |>
-  dplyr::filter(Variable %in% available_vars) |>
-  # TODO: add year to PEcAn.utils::standard vars
-  dplyr::bind_rows(
-    dplyr::tibble(
-      Variable = "year",
-      Description = "Year"
-    )
-  )
-
-vars_df$Description[is.na(vars_df$Description)] <- "(No description available)"
-knitr::kable(vars_df, caption = "Model Output Variables and Descriptions")
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Model Output Variables and Descriptions
VariableDescription
GPPGross Primary Productivity
NEENet Ecosystem Exchange
TotalRespTotal Respiration
AutoRespAutotrophic Respiration
HeteroRespHeterotrophic Respiration
SoilRespSoil Respiration
NPPNet Primary Productivity
GWBIGross Woody Biomass Increment
TotLivBiomTotal living biomass
AGBTotal aboveground biomass
LAILeaf Area Index
leaf_carbon_contentLeaf Carbon Content
fine_root_carbon_contentFine Root Carbon Content
coarse_root_carbon_contentCoarse Root Carbon Content
AbvGrndWoodAbove ground woody biomass
TotSoilCarbTotal Soil Carbon
litter_carbon_contentLitter Carbon Content
QleLatent heat
TranspTotal transpiration
SoilMoistAverage Layer Soil Moisture
SoilMoistFracAverage Layer Fraction of Saturation
SWESnow Water Equivalent
litter_mass_content_of_waterAverage layer litter moisture
yearYear
-
-
-
-
-

Visualize Model Results

-

This section provides examples of how to create time series plots of different model variables. The examples cover various ecosystem processes including carbon fluxes, carbon pools, water variables, and structural variables like Leaf Area Index (LAI).

-
-

Plot Carbon Fluxes

-
-
# Plot Gross Primary Productivity (GPP) and Net Primary Productivity (NPP)
-plot(model_output$posix, model_output$GPP,
-  type = "l",
-  col = "green",
-  xlab = "Date",
-  ylab = "Carbon Flux (kg C m-2 s-1)",
-  main = paste("Carbon Fluxes Over Time — PEcAn", runid)
-)
-lines(model_output$posix, model_output$NPP, col = "blue")
-legend("topright", legend = c("GPP", "NPP"), col = c("green", "blue"), lty = 1)
-
-
-
-

-
-
-
-
-
-
-

Plot Carbon Pools

-
-
# Plot Total Live Biomass and Total Soil Carbon
-plot(model_output$posix, model_output$TotLivBiom,
-  type = "l",
-  col = "darkgreen",
-  xlab = "Date",
-  ylab = "Carbon Pool (kg C m-2)",
-  main = paste("Carbon Pools Over Time — PEcAn", runid)
-)
-lines(model_output$posix, model_output$TotSoilCarb, col = "brown")
-legend("topright", legend = c("Total Live Biomass", "Total Soil Carbon"), col = c("darkgreen", "brown"), lty = 1)
-
-
-
-

-
-
-
-
-
-
-

Plot Water Variables

-
-
# Plot Soil Moisture and Snow Water Equivalent
-plot(model_output$posix, model_output$SoilMoist,
-  type = "l",
-  col = "blue",
-  xlab = "Date",
-  ylab = "Soil Moisture (kg m-2)",
-  main = paste("Soil Moisture Over Time — PEcAn", runid)
-)
-lines(model_output$posix, model_output$SWE, col = "lightblue")
-legend("topright", legend = c("Soil Moisture", "Snow Water Equivalent"), col = c("blue", "lightblue"), lty = 1)
-
-
-
-

-
-
-
-
-
-
-

Plot LAI and Biomass

-
-
# Plot Leaf Area Index (LAI) and Above Ground Wood
-plot(model_output$posix, model_output$LAI,
-  type = "l",
-  col = "darkgreen",
-  xlab = "Date",
-  ylab = "LAI (m2 m-2)",
-  main = paste("Leaf Area Index Over Time — PEcAn", runid)
-)
-lines(model_output$posix, model_output$AbvGrndWood, col = "brown")
-legend("topright", legend = c("LAI", "Above Ground Wood"), col = c("darkgreen", "brown"), lty = 1)
-
-
-
-

-
-
-
-
-
-
-
-

Conclusion

-

This notebook demonstrated how to set up, run, and analyze a PEcAn ecosystem model workflow programmatically. You can now modify parameters, try different models, or extend the analysis as needed.

-

Try editing the pecan.xml file. Give it a new name and update the settings_path variable at the beginning of this Demo to point to the new file. See how the changes affect the model output!

-
-
-

Further Exploration

-

The next set of tutorials will focus on the process of data assimilation and parameter estimation. The next two steps are in “.Rmd” files which can be viewed online.

-

Assimilation ‘by hand’

-

Explore how model error changes as a function of parameter value (i.e. data assimilation ‘by hand’)

-

MCMC Concepts Explore Bayesian MCMC concepts using the photosynthesis module

-

More info about tools, analyses, and specific tasks…

-

Additional information about specific tasks (adding sites, models, data; software updates; etc.) and analyses (e.g. data assimilation) can be found in the PEcAn documentation

-

If you encounter a problem with PEcAn that’s not covered in the documentation, or if PEcAn is missing functionality you need, please search known bugs and issues, submit a bug report, or ask a question in our chat room.

-
-
-

Clean Up Workflow Output (Optional)

-

If you want to remove all files and directories created by this workflow and start fresh, you can run the following code. This will delete the entire output directory specified in your settings. Use with caution!

-
-
# WARNING: This will permanently delete all workflow output files!
-# Uncomment the line below to enable cleanup.
-# fs::dir_delete(settings$outdir)
-
-
-
-

Session Information

-
-

PEcAn package versions.

-
-
PEcAn.all::pecan_version()
-
-
 package               v1.9.0 installed  source              
- PEcAn.all             1.9.0  1.9.0.9000 local (/pecan/bas...
- PEcAn.allometry       1.7.4  1.7.4.9000 local (/pecan/mod...
- PEcAn.assim.batch     1.9.0  1.9.0.9000 local (/pecan/mod...
- PEcAn.BASGRA          1.8.1  1.8.1.9000 local (/pecan/mod...
- PEcAn.benchmark       1.7.4  1.7.4.9000 local (/pecan/mod...
- PEcAn.BIOCRO          1.7.4  1.7.5      local (/pecan/mod...
- PEcAn.CABLE           1.7.4  NA         NA                  
- PEcAn.CLM45           1.7.4  1.7.4.9000 local (/pecan/mod...
- PEcAn.DALEC           1.7.4  1.7.5      local (/pecan/mod...
- PEcAn.data.atmosphere 1.9.0  1.9.1      local (/pecan/mod...
- PEcAn.data.land       1.8.1  1.8.2      local (/pecan/mod...
- PEcAn.data.mining     1.7.4  NA         NA                  
- PEcAn.data.remote     1.9.0  1.9.1      local (/pecan/mod...
- PEcAn.DB              1.8.1  1.8.1.9000 local (/pecan/bas...
- PEcAn.dvmdostem       1.7.4  1.7.5      local (/pecan/mod...
- PEcAn.ED2             1.8.1  1.8.2      local (/pecan/mod...
- PEcAn.emulator        1.8.1  1.8.1.9000 local (/pecan/mod...
- PEcAn.FATES           1.8.0  1.8.1      local (/pecan/mod...
- PEcAn.GDAY            1.7.4  1.7.5      local (/pecan/mod...
- PEcAn.JULES           1.7.4  1.7.5      local (/pecan/mod...
- PEcAn.LDNDC           1.0.1  1.0.2      local (/pecan/mod...
- PEcAn.LINKAGES        1.7.4  1.7.5      local (/pecan/mod...
- PEcAn.logger          1.8.3  1.8.4      local (/pecan/bas...
- PEcAn.LPJGUESS        1.8.0  1.8.1      local (/pecan/mod...
- PEcAn.MA              1.7.4  1.7.4.9000 local (/pecan/mod...
- PEcAn.MAAT            1.7.4  1.7.5      local (/pecan/mod...
- PEcAn.MAESPA          1.7.4  1.7.5      local (/pecan/mod...
- PEcAn.ModelName       1.8.1  1.8.1.9000 local (/pecan/mod...
- PEcAn.photosynthesis  1.7.4  1.7.4.9000 local (/pecan/mod...
- PEcAn.PRELES          1.7.4  NA         NA                  
- PEcAn.priors          1.7.4  1.7.4.9000 local (/pecan/mod...
- PEcAn.qaqc            1.7.4  1.7.4.9000 local (/pecan/bas...
- PEcAn.remote          1.9.0  1.9.0.9000 local (/pecan/bas...
- PEcAn.settings        1.9.0  1.9.1      local (/pecan/bas...
- PEcAn.SIBCASA         0.0.2  0.0.3      local (/pecan/mod...
- PEcAn.SIPNET          1.9.0  1.9.1      local (/pecan/mod...
- PEcAn.STICS           1.8.1  1.8.2      local (/pecan/mod...
- PEcAn.uncertainty     1.8.1  1.8.2      local (/pecan/mod...
- PEcAn.utils           1.8.1  1.8.2      local (/pecan/bas...
- PEcAn.visualization   1.8.1  1.8.1.9000 local (/pecan/bas...
- PEcAn.workflow        1.9.0  1.9.0.9000 local (/pecan/bas...
- PEcAnAssimSequential  1.9.0  1.9.0.9000 local (/pecan/mod...
- PEcAnRTM              1.7.4  1.9.0.9000 local (/pecan/mod...
-
-
-
-
-

R session information:

-
-
sessionInfo()
-
-
R version 4.4.3 (2025-02-28)
-Platform: x86_64-pc-linux-gnu
-Running under: Ubuntu 24.04.2 LTS
-
-Matrix products: default
-BLAS:   /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3 
-LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.26.so;  LAPACK version 3.12.0
-
-locale:
- [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C              
- [3] LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8    
- [5] LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8   
- [7] LC_PAPER=en_US.UTF-8       LC_NAME=C                 
- [9] LC_ADDRESS=C               LC_TELEPHONE=C            
-[11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       
-
-time zone: Etc/UTC
-tzcode source: system (glibc)
-
-attached base packages:
-[1] stats     graphics  grDevices utils     datasets  methods   base     
-
-other attached packages:
- [1] PEcAn.SIPNET_1.9.1           PEcAn.all_1.9.0.9000        
- [3] PEcAn.workflow_1.9.0.9000    PEcAn.remote_1.9.0.9000     
- [5] PEcAn.benchmark_1.7.4.9000   PEcAn.priors_1.7.4.9000     
- [7] PEcAn.emulator_1.8.1.9000    PEcAn.assim.batch_1.9.0.9000
- [9] PEcAn.data.remote_1.9.1      PEcAn.data.land_1.8.2       
-[11] PEcAn.data.atmosphere_1.9.1  PEcAn.uncertainty_1.8.2     
-[13] PEcAn.utils_1.8.2            PEcAn.logger_1.8.4          
-[15] PEcAn.MA_1.7.4.9000          PEcAn.settings_1.9.1        
-[17] PEcAn.DB_1.8.1.9000         
-
-loaded via a namespace (and not attached):
- [1] PEcAn.qaqc_1.7.4.9000           DBI_1.2.3                      
- [3] gridExtra_2.3                   PEcAn.allometry_1.7.4.9000     
- [5] rlang_1.1.5                     magrittr_2.0.3                 
- [7] furrr_0.3.1                     e1071_1.7-16                   
- [9] compiler_4.4.3                  vctrs_0.6.5                    
-[11] stringr_1.5.1                   pkgconfig_2.0.3                
-[13] PEcAn.MAESPA_1.7.5              fastmap_1.2.0                  
-[15] PEcAn.ED2_1.8.2                 labeling_0.4.3                 
-[17] PEcAn.dvmdostem_1.7.5           PEcAn.ModelName_1.8.1.9000     
-[19] rmarkdown_2.29                  pracma_2.4.4                   
-[21] sessioninfo_1.2.3               purrr_1.0.4                    
-[23] xfun_0.52                       PEcAn.JULES_1.7.5              
-[25] jsonlite_2.0.0                  PEcAn.LINKAGES_1.7.5           
-[27] PEcAn.SIBCASA_0.0.3             parallel_4.4.3                 
-[29] R6_2.6.1                        PEcAn.DALEC_1.7.5              
-[31] stringi_1.8.7                   PEcAn.CLM45_1.7.4.9000         
-[33] RPostgreSQL_0.7-8               parallelly_1.43.0              
-[35] numDeriv_2016.8-1.1             lubridate_1.9.4                
-[37] Rcpp_1.0.14                     iterators_1.0.14               
-[39] knitr_1.50                      PEcAnAssimSequential_1.9.0.9000
-[41] igraph_2.1.4                    rngWELL_0.10-10                
-[43] timechange_0.3.0                tidyselect_1.2.1               
-[45] abind_1.4-8                     yaml_2.3.10                    
-[47] PEcAn.LPJGUESS_1.8.1            codetools_0.2-20               
-[49] listenv_0.9.1                   lattice_0.22-6                 
-[51] tibble_3.2.1                    withr_3.0.2                    
-[53] coda_0.19-4.1                   evaluate_1.0.3                 
-[55] future_1.34.0                   sf_1.0-20                      
-[57] units_0.8-7                     proxy_0.4-27                   
-[59] PEcAn.BASGRA_1.8.1.9000         pillar_1.10.2                  
-[61] PEcAn.BIOCRO_1.7.5              KernSmooth_2.23-26             
-[63] foreach_1.5.2                   nimble_1.3.0                   
-[65] ncdf4_1.24                      generics_0.1.3                 
-[67] rprojroot_2.0.4                 ggplot2_3.5.2                  
-[69] munsell_0.5.1                   scales_1.3.0                   
-[71] randtoolbox_2.0.5               globals_0.16.3                 
-[73] PEcAn.MAAT_1.7.5                PEcAn.STICS_1.8.2              
-[75] class_7.3-23                    glue_1.8.0                     
-[77] tools_4.4.3                     data.table_1.17.0              
-[79] XML_3.99-0.18                   grid_4.4.3                     
-[81] PEcAn.visualization_1.8.1.9000  PEcAn.photosynthesis_1.7.4.9000
-[83] colorspace_2.1-1                cli_3.6.4                      
-[85] PEcAnRTM_1.9.0.9000             dplyr_1.1.4                    
-[87] PEcAn.GDAY_1.7.5                gtable_0.3.6                   
-[89] PEcAn.FATES_1.8.1               digest_0.6.37                  
-[91] classInt_0.4-11                 PEcAn.LDNDC_1.0.2              
-[93] rjson_0.2.23                    htmlwidgets_1.6.4              
-[95] farver_2.1.2                    htmltools_0.5.8.1              
-[97] lifecycle_1.0.4                 here_1.0.1                     
-
-
-
-
- -
- - -
- - - - - \ No newline at end of file diff --git a/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/uncertainty_files/figure-html/plot-carbon-fluxes-1.png b/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/uncertainty_files/figure-html/plot-carbon-fluxes-1.png deleted file mode 100644 index 8fe6bec90..000000000 Binary files a/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/uncertainty_files/figure-html/plot-carbon-fluxes-1.png and /dev/null differ diff --git a/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/uncertainty_files/figure-html/plot-carbon-pools-1.png b/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/uncertainty_files/figure-html/plot-carbon-pools-1.png deleted file mode 100644 index c21fc5d2f..000000000 Binary files a/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/uncertainty_files/figure-html/plot-carbon-pools-1.png and /dev/null differ diff --git a/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/uncertainty_files/figure-html/plot-lai-biomass-1.png b/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/uncertainty_files/figure-html/plot-lai-biomass-1.png deleted file mode 100644 index c33ae1268..000000000 Binary files a/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/uncertainty_files/figure-html/plot-lai-biomass-1.png and /dev/null differ diff --git a/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/uncertainty_files/figure-html/plot-water-variables-1.png b/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/uncertainty_files/figure-html/plot-water-variables-1.png deleted file mode 100644 index 5fca5bf7d..000000000 Binary files a/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/uncertainty_files/figure-html/plot-water-variables-1.png and /dev/null differ diff --git a/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/uncertainty_files/figure-html/visualize-ensemble-results-1.png b/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/uncertainty_files/figure-html/visualize-ensemble-results-1.png deleted file mode 100644 index 87b78c07e..000000000 Binary files a/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/uncertainty_files/figure-html/visualize-ensemble-results-1.png and /dev/null differ diff --git a/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/uncertainty_files/libs/bootstrap/bootstrap-icons.css b/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/uncertainty_files/libs/bootstrap/bootstrap-icons.css deleted file mode 100644 index 285e4448f..000000000 --- a/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/uncertainty_files/libs/bootstrap/bootstrap-icons.css +++ /dev/null @@ -1,2078 +0,0 @@ -/*! - * Bootstrap Icons v1.11.1 (https://icons.getbootstrap.com/) - * Copyright 2019-2023 The Bootstrap Authors - * Licensed under MIT (https://github.com/twbs/icons/blob/main/LICENSE) - */ - -@font-face { - font-display: block; - font-family: "bootstrap-icons"; - src: -url("./bootstrap-icons.woff?2820a3852bdb9a5832199cc61cec4e65") format("woff"); -} - -.bi::before, -[class^="bi-"]::before, -[class*=" bi-"]::before { - display: inline-block; - font-family: bootstrap-icons !important; - font-style: normal; - font-weight: normal !important; - font-variant: normal; - text-transform: none; - line-height: 1; - vertical-align: -.125em; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -.bi-123::before { content: "\f67f"; } -.bi-alarm-fill::before { content: "\f101"; } -.bi-alarm::before { content: "\f102"; } -.bi-align-bottom::before { content: "\f103"; } -.bi-align-center::before { content: "\f104"; } -.bi-align-end::before { content: "\f105"; } -.bi-align-middle::before { content: "\f106"; } -.bi-align-start::before { content: "\f107"; } -.bi-align-top::before { content: "\f108"; } -.bi-alt::before { content: "\f109"; } -.bi-app-indicator::before { content: "\f10a"; } -.bi-app::before { content: "\f10b"; } -.bi-archive-fill::before { content: "\f10c"; } -.bi-archive::before { content: "\f10d"; } -.bi-arrow-90deg-down::before { content: "\f10e"; } -.bi-arrow-90deg-left::before { content: "\f10f"; } -.bi-arrow-90deg-right::before { content: "\f110"; } -.bi-arrow-90deg-up::before { content: "\f111"; } -.bi-arrow-bar-down::before { content: "\f112"; } -.bi-arrow-bar-left::before { content: "\f113"; } -.bi-arrow-bar-right::before { content: "\f114"; } -.bi-arrow-bar-up::before { content: "\f115"; } -.bi-arrow-clockwise::before { content: "\f116"; } -.bi-arrow-counterclockwise::before { content: "\f117"; } -.bi-arrow-down-circle-fill::before { content: "\f118"; } -.bi-arrow-down-circle::before { content: "\f119"; } -.bi-arrow-down-left-circle-fill::before { content: "\f11a"; } -.bi-arrow-down-left-circle::before { content: "\f11b"; } -.bi-arrow-down-left-square-fill::before { content: "\f11c"; } -.bi-arrow-down-left-square::before { content: "\f11d"; } -.bi-arrow-down-left::before { content: "\f11e"; } -.bi-arrow-down-right-circle-fill::before { content: "\f11f"; } -.bi-arrow-down-right-circle::before { content: "\f120"; } -.bi-arrow-down-right-square-fill::before { content: "\f121"; } -.bi-arrow-down-right-square::before { content: "\f122"; } -.bi-arrow-down-right::before { content: "\f123"; } -.bi-arrow-down-short::before { content: "\f124"; } -.bi-arrow-down-square-fill::before { content: "\f125"; } -.bi-arrow-down-square::before { content: "\f126"; } -.bi-arrow-down-up::before { content: "\f127"; } -.bi-arrow-down::before { content: "\f128"; } -.bi-arrow-left-circle-fill::before { content: "\f129"; } -.bi-arrow-left-circle::before { content: "\f12a"; } -.bi-arrow-left-right::before { content: "\f12b"; } -.bi-arrow-left-short::before { content: "\f12c"; } -.bi-arrow-left-square-fill::before { content: "\f12d"; } -.bi-arrow-left-square::before { content: "\f12e"; } -.bi-arrow-left::before { content: "\f12f"; } -.bi-arrow-repeat::before { content: "\f130"; } -.bi-arrow-return-left::before { content: "\f131"; } -.bi-arrow-return-right::before { content: "\f132"; } -.bi-arrow-right-circle-fill::before { content: "\f133"; } -.bi-arrow-right-circle::before { content: "\f134"; } -.bi-arrow-right-short::before { content: "\f135"; } -.bi-arrow-right-square-fill::before { content: "\f136"; } -.bi-arrow-right-square::before { content: "\f137"; } -.bi-arrow-right::before { content: "\f138"; } -.bi-arrow-up-circle-fill::before { content: "\f139"; } -.bi-arrow-up-circle::before { content: "\f13a"; } -.bi-arrow-up-left-circle-fill::before { content: "\f13b"; } -.bi-arrow-up-left-circle::before { content: "\f13c"; } -.bi-arrow-up-left-square-fill::before { content: "\f13d"; } -.bi-arrow-up-left-square::before { content: "\f13e"; } -.bi-arrow-up-left::before { content: "\f13f"; } -.bi-arrow-up-right-circle-fill::before { content: "\f140"; } -.bi-arrow-up-right-circle::before { content: "\f141"; } -.bi-arrow-up-right-square-fill::before { content: "\f142"; } -.bi-arrow-up-right-square::before { content: "\f143"; } -.bi-arrow-up-right::before { content: "\f144"; } -.bi-arrow-up-short::before { content: "\f145"; } -.bi-arrow-up-square-fill::before { content: "\f146"; } -.bi-arrow-up-square::before { content: "\f147"; } -.bi-arrow-up::before { content: "\f148"; } -.bi-arrows-angle-contract::before { content: "\f149"; } -.bi-arrows-angle-expand::before { content: "\f14a"; } -.bi-arrows-collapse::before { content: "\f14b"; } -.bi-arrows-expand::before { content: "\f14c"; } -.bi-arrows-fullscreen::before { content: "\f14d"; } -.bi-arrows-move::before { content: "\f14e"; } -.bi-aspect-ratio-fill::before { content: "\f14f"; } -.bi-aspect-ratio::before { content: "\f150"; } -.bi-asterisk::before { content: "\f151"; } -.bi-at::before { content: "\f152"; } -.bi-award-fill::before { content: "\f153"; } -.bi-award::before { content: "\f154"; } -.bi-back::before { content: "\f155"; } -.bi-backspace-fill::before { content: "\f156"; } -.bi-backspace-reverse-fill::before { content: "\f157"; } -.bi-backspace-reverse::before { content: "\f158"; } -.bi-backspace::before { content: "\f159"; } -.bi-badge-3d-fill::before { content: "\f15a"; } -.bi-badge-3d::before { content: "\f15b"; } -.bi-badge-4k-fill::before { content: "\f15c"; } -.bi-badge-4k::before { content: "\f15d"; } -.bi-badge-8k-fill::before { content: "\f15e"; } -.bi-badge-8k::before { content: "\f15f"; } -.bi-badge-ad-fill::before { content: "\f160"; } -.bi-badge-ad::before { content: "\f161"; } -.bi-badge-ar-fill::before { content: "\f162"; } -.bi-badge-ar::before { content: "\f163"; } -.bi-badge-cc-fill::before { content: "\f164"; } -.bi-badge-cc::before { content: "\f165"; } -.bi-badge-hd-fill::before { content: "\f166"; } -.bi-badge-hd::before { content: "\f167"; } -.bi-badge-tm-fill::before { content: "\f168"; } -.bi-badge-tm::before { content: "\f169"; } -.bi-badge-vo-fill::before { content: "\f16a"; } -.bi-badge-vo::before { content: "\f16b"; } -.bi-badge-vr-fill::before { content: "\f16c"; } -.bi-badge-vr::before { content: "\f16d"; } -.bi-badge-wc-fill::before { content: "\f16e"; } -.bi-badge-wc::before { content: "\f16f"; } -.bi-bag-check-fill::before { content: "\f170"; } -.bi-bag-check::before { content: "\f171"; } -.bi-bag-dash-fill::before { content: "\f172"; } -.bi-bag-dash::before { content: "\f173"; } -.bi-bag-fill::before { content: "\f174"; } -.bi-bag-plus-fill::before { content: "\f175"; } -.bi-bag-plus::before { content: "\f176"; } -.bi-bag-x-fill::before { content: "\f177"; } -.bi-bag-x::before { content: "\f178"; } -.bi-bag::before { content: "\f179"; } -.bi-bar-chart-fill::before { content: "\f17a"; } -.bi-bar-chart-line-fill::before { content: "\f17b"; } -.bi-bar-chart-line::before { content: "\f17c"; } -.bi-bar-chart-steps::before { content: "\f17d"; } -.bi-bar-chart::before { content: "\f17e"; } -.bi-basket-fill::before { content: "\f17f"; } -.bi-basket::before { content: "\f180"; } -.bi-basket2-fill::before { content: "\f181"; } -.bi-basket2::before { content: "\f182"; } -.bi-basket3-fill::before { content: "\f183"; } -.bi-basket3::before { content: "\f184"; } -.bi-battery-charging::before { content: "\f185"; } -.bi-battery-full::before { content: "\f186"; } -.bi-battery-half::before { content: "\f187"; } -.bi-battery::before { content: "\f188"; } -.bi-bell-fill::before { content: "\f189"; } -.bi-bell::before { content: "\f18a"; } -.bi-bezier::before { content: "\f18b"; } -.bi-bezier2::before { content: "\f18c"; } -.bi-bicycle::before { content: "\f18d"; } -.bi-binoculars-fill::before { content: "\f18e"; } -.bi-binoculars::before { content: "\f18f"; } -.bi-blockquote-left::before { content: "\f190"; } -.bi-blockquote-right::before { content: "\f191"; } -.bi-book-fill::before { content: "\f192"; } -.bi-book-half::before { content: "\f193"; } -.bi-book::before { content: "\f194"; } -.bi-bookmark-check-fill::before { content: "\f195"; } -.bi-bookmark-check::before { content: "\f196"; } -.bi-bookmark-dash-fill::before { content: "\f197"; } -.bi-bookmark-dash::before { content: "\f198"; } -.bi-bookmark-fill::before { content: "\f199"; } -.bi-bookmark-heart-fill::before { content: "\f19a"; } -.bi-bookmark-heart::before { content: "\f19b"; } -.bi-bookmark-plus-fill::before { content: "\f19c"; } -.bi-bookmark-plus::before { content: "\f19d"; } -.bi-bookmark-star-fill::before { content: "\f19e"; } -.bi-bookmark-star::before { content: "\f19f"; } -.bi-bookmark-x-fill::before { content: "\f1a0"; } -.bi-bookmark-x::before { content: "\f1a1"; } -.bi-bookmark::before { content: "\f1a2"; } -.bi-bookmarks-fill::before { content: "\f1a3"; } -.bi-bookmarks::before { content: "\f1a4"; } -.bi-bookshelf::before { content: "\f1a5"; } -.bi-bootstrap-fill::before { content: "\f1a6"; } -.bi-bootstrap-reboot::before { content: "\f1a7"; } -.bi-bootstrap::before { content: "\f1a8"; } -.bi-border-all::before { content: "\f1a9"; } -.bi-border-bottom::before { content: "\f1aa"; } -.bi-border-center::before { content: "\f1ab"; } -.bi-border-inner::before { content: "\f1ac"; } -.bi-border-left::before { content: "\f1ad"; } -.bi-border-middle::before { content: "\f1ae"; } -.bi-border-outer::before { content: "\f1af"; } -.bi-border-right::before { content: "\f1b0"; } -.bi-border-style::before { content: "\f1b1"; } -.bi-border-top::before { content: "\f1b2"; } -.bi-border-width::before { content: "\f1b3"; } -.bi-border::before { content: "\f1b4"; } -.bi-bounding-box-circles::before { content: "\f1b5"; } -.bi-bounding-box::before { content: "\f1b6"; } -.bi-box-arrow-down-left::before { content: "\f1b7"; } -.bi-box-arrow-down-right::before { content: "\f1b8"; } -.bi-box-arrow-down::before { content: "\f1b9"; } -.bi-box-arrow-in-down-left::before { content: "\f1ba"; } -.bi-box-arrow-in-down-right::before { content: "\f1bb"; } -.bi-box-arrow-in-down::before { content: "\f1bc"; } -.bi-box-arrow-in-left::before { content: "\f1bd"; } -.bi-box-arrow-in-right::before { content: "\f1be"; } -.bi-box-arrow-in-up-left::before { content: "\f1bf"; } -.bi-box-arrow-in-up-right::before { content: "\f1c0"; } -.bi-box-arrow-in-up::before { content: "\f1c1"; } -.bi-box-arrow-left::before { content: "\f1c2"; } -.bi-box-arrow-right::before { content: "\f1c3"; } -.bi-box-arrow-up-left::before { content: "\f1c4"; } -.bi-box-arrow-up-right::before { content: "\f1c5"; } -.bi-box-arrow-up::before { content: "\f1c6"; } -.bi-box-seam::before { content: "\f1c7"; } -.bi-box::before { content: "\f1c8"; } -.bi-braces::before { content: "\f1c9"; } -.bi-bricks::before { content: "\f1ca"; } -.bi-briefcase-fill::before { content: "\f1cb"; } -.bi-briefcase::before { content: "\f1cc"; } -.bi-brightness-alt-high-fill::before { content: "\f1cd"; } -.bi-brightness-alt-high::before { content: "\f1ce"; } -.bi-brightness-alt-low-fill::before { content: "\f1cf"; } -.bi-brightness-alt-low::before { content: "\f1d0"; } -.bi-brightness-high-fill::before { content: "\f1d1"; } -.bi-brightness-high::before { content: "\f1d2"; } -.bi-brightness-low-fill::before { content: "\f1d3"; } -.bi-brightness-low::before { content: "\f1d4"; } -.bi-broadcast-pin::before { content: "\f1d5"; } -.bi-broadcast::before { content: "\f1d6"; } -.bi-brush-fill::before { content: "\f1d7"; } -.bi-brush::before { content: "\f1d8"; } -.bi-bucket-fill::before { content: "\f1d9"; } -.bi-bucket::before { content: "\f1da"; } -.bi-bug-fill::before { content: "\f1db"; } -.bi-bug::before { content: "\f1dc"; } -.bi-building::before { content: "\f1dd"; } -.bi-bullseye::before { content: "\f1de"; } -.bi-calculator-fill::before { content: "\f1df"; } -.bi-calculator::before { content: "\f1e0"; } -.bi-calendar-check-fill::before { content: "\f1e1"; } -.bi-calendar-check::before { content: "\f1e2"; } -.bi-calendar-date-fill::before { content: "\f1e3"; } -.bi-calendar-date::before { content: "\f1e4"; } -.bi-calendar-day-fill::before { content: "\f1e5"; } -.bi-calendar-day::before { content: "\f1e6"; } -.bi-calendar-event-fill::before { content: "\f1e7"; } -.bi-calendar-event::before { content: "\f1e8"; } -.bi-calendar-fill::before { content: "\f1e9"; } -.bi-calendar-minus-fill::before { content: "\f1ea"; } -.bi-calendar-minus::before { content: "\f1eb"; } -.bi-calendar-month-fill::before { content: "\f1ec"; } -.bi-calendar-month::before { content: "\f1ed"; } -.bi-calendar-plus-fill::before { content: "\f1ee"; } -.bi-calendar-plus::before { content: "\f1ef"; } -.bi-calendar-range-fill::before { content: "\f1f0"; } -.bi-calendar-range::before { content: "\f1f1"; } -.bi-calendar-week-fill::before { content: "\f1f2"; } -.bi-calendar-week::before { content: "\f1f3"; } -.bi-calendar-x-fill::before { content: "\f1f4"; } -.bi-calendar-x::before { content: "\f1f5"; } -.bi-calendar::before { content: "\f1f6"; } -.bi-calendar2-check-fill::before { content: "\f1f7"; } -.bi-calendar2-check::before { content: "\f1f8"; } -.bi-calendar2-date-fill::before { content: "\f1f9"; } -.bi-calendar2-date::before { content: "\f1fa"; } -.bi-calendar2-day-fill::before { content: "\f1fb"; } -.bi-calendar2-day::before { content: "\f1fc"; } -.bi-calendar2-event-fill::before { content: "\f1fd"; } -.bi-calendar2-event::before { content: "\f1fe"; } -.bi-calendar2-fill::before { content: "\f1ff"; } -.bi-calendar2-minus-fill::before { content: "\f200"; } -.bi-calendar2-minus::before { content: "\f201"; } -.bi-calendar2-month-fill::before { content: "\f202"; } -.bi-calendar2-month::before { content: "\f203"; } -.bi-calendar2-plus-fill::before { content: "\f204"; } -.bi-calendar2-plus::before { content: "\f205"; } -.bi-calendar2-range-fill::before { content: "\f206"; } -.bi-calendar2-range::before { content: "\f207"; } -.bi-calendar2-week-fill::before { content: "\f208"; } -.bi-calendar2-week::before { content: "\f209"; } -.bi-calendar2-x-fill::before { content: "\f20a"; } -.bi-calendar2-x::before { content: "\f20b"; } -.bi-calendar2::before { content: "\f20c"; } -.bi-calendar3-event-fill::before { content: "\f20d"; } -.bi-calendar3-event::before { content: "\f20e"; } -.bi-calendar3-fill::before { content: "\f20f"; } -.bi-calendar3-range-fill::before { content: "\f210"; } -.bi-calendar3-range::before { content: "\f211"; } -.bi-calendar3-week-fill::before { content: "\f212"; } -.bi-calendar3-week::before { content: "\f213"; } -.bi-calendar3::before { content: "\f214"; } -.bi-calendar4-event::before { content: "\f215"; } -.bi-calendar4-range::before { content: "\f216"; } -.bi-calendar4-week::before { content: "\f217"; } -.bi-calendar4::before { content: "\f218"; } -.bi-camera-fill::before { content: "\f219"; } -.bi-camera-reels-fill::before { content: "\f21a"; } -.bi-camera-reels::before { content: "\f21b"; } -.bi-camera-video-fill::before { content: "\f21c"; } -.bi-camera-video-off-fill::before { content: "\f21d"; } -.bi-camera-video-off::before { content: "\f21e"; } -.bi-camera-video::before { content: "\f21f"; } -.bi-camera::before { content: "\f220"; } -.bi-camera2::before { content: "\f221"; } -.bi-capslock-fill::before { content: "\f222"; } -.bi-capslock::before { content: "\f223"; } -.bi-card-checklist::before { content: "\f224"; } -.bi-card-heading::before { content: "\f225"; } -.bi-card-image::before { content: "\f226"; } -.bi-card-list::before { content: "\f227"; } -.bi-card-text::before { content: "\f228"; } -.bi-caret-down-fill::before { content: "\f229"; } -.bi-caret-down-square-fill::before { content: "\f22a"; } -.bi-caret-down-square::before { content: "\f22b"; } -.bi-caret-down::before { content: "\f22c"; } -.bi-caret-left-fill::before { content: "\f22d"; } -.bi-caret-left-square-fill::before { content: "\f22e"; } -.bi-caret-left-square::before { content: "\f22f"; } -.bi-caret-left::before { content: "\f230"; } -.bi-caret-right-fill::before { content: "\f231"; } -.bi-caret-right-square-fill::before { content: "\f232"; } -.bi-caret-right-square::before { content: "\f233"; } -.bi-caret-right::before { content: "\f234"; } -.bi-caret-up-fill::before { content: "\f235"; } -.bi-caret-up-square-fill::before { content: "\f236"; } -.bi-caret-up-square::before { content: "\f237"; } -.bi-caret-up::before { content: "\f238"; } -.bi-cart-check-fill::before { content: "\f239"; } -.bi-cart-check::before { content: "\f23a"; } -.bi-cart-dash-fill::before { content: "\f23b"; } -.bi-cart-dash::before { content: "\f23c"; } -.bi-cart-fill::before { content: "\f23d"; } -.bi-cart-plus-fill::before { content: "\f23e"; } -.bi-cart-plus::before { content: "\f23f"; } -.bi-cart-x-fill::before { content: "\f240"; } -.bi-cart-x::before { content: "\f241"; } -.bi-cart::before { content: "\f242"; } -.bi-cart2::before { content: "\f243"; } -.bi-cart3::before { content: "\f244"; } -.bi-cart4::before { content: "\f245"; } -.bi-cash-stack::before { content: "\f246"; } -.bi-cash::before { content: "\f247"; } -.bi-cast::before { content: "\f248"; } -.bi-chat-dots-fill::before { content: "\f249"; } -.bi-chat-dots::before { content: "\f24a"; } -.bi-chat-fill::before { content: "\f24b"; } -.bi-chat-left-dots-fill::before { content: "\f24c"; } -.bi-chat-left-dots::before { content: "\f24d"; } -.bi-chat-left-fill::before { content: "\f24e"; } -.bi-chat-left-quote-fill::before { content: "\f24f"; } -.bi-chat-left-quote::before { content: "\f250"; } -.bi-chat-left-text-fill::before { content: "\f251"; } -.bi-chat-left-text::before { content: "\f252"; } -.bi-chat-left::before { content: "\f253"; } -.bi-chat-quote-fill::before { content: "\f254"; } -.bi-chat-quote::before { content: "\f255"; } -.bi-chat-right-dots-fill::before { content: "\f256"; } -.bi-chat-right-dots::before { content: "\f257"; } -.bi-chat-right-fill::before { content: "\f258"; } -.bi-chat-right-quote-fill::before { content: "\f259"; } -.bi-chat-right-quote::before { content: "\f25a"; } -.bi-chat-right-text-fill::before { content: "\f25b"; } -.bi-chat-right-text::before { content: "\f25c"; } -.bi-chat-right::before { content: "\f25d"; } -.bi-chat-square-dots-fill::before { content: "\f25e"; } -.bi-chat-square-dots::before { content: "\f25f"; } -.bi-chat-square-fill::before { content: "\f260"; } -.bi-chat-square-quote-fill::before { content: "\f261"; } -.bi-chat-square-quote::before { content: "\f262"; } -.bi-chat-square-text-fill::before { content: "\f263"; } -.bi-chat-square-text::before { content: "\f264"; } -.bi-chat-square::before { content: "\f265"; } -.bi-chat-text-fill::before { content: "\f266"; } -.bi-chat-text::before { content: "\f267"; } -.bi-chat::before { content: "\f268"; } -.bi-check-all::before { content: "\f269"; } -.bi-check-circle-fill::before { content: "\f26a"; } -.bi-check-circle::before { content: "\f26b"; } -.bi-check-square-fill::before { content: "\f26c"; } -.bi-check-square::before { content: "\f26d"; } -.bi-check::before { content: "\f26e"; } -.bi-check2-all::before { content: "\f26f"; } -.bi-check2-circle::before { content: "\f270"; } -.bi-check2-square::before { content: "\f271"; } -.bi-check2::before { content: "\f272"; } -.bi-chevron-bar-contract::before { content: "\f273"; } -.bi-chevron-bar-down::before { content: "\f274"; } -.bi-chevron-bar-expand::before { content: "\f275"; } -.bi-chevron-bar-left::before { content: "\f276"; } -.bi-chevron-bar-right::before { content: "\f277"; } -.bi-chevron-bar-up::before { content: "\f278"; } -.bi-chevron-compact-down::before { content: "\f279"; } -.bi-chevron-compact-left::before { content: "\f27a"; } -.bi-chevron-compact-right::before { content: "\f27b"; } -.bi-chevron-compact-up::before { content: "\f27c"; } -.bi-chevron-contract::before { content: "\f27d"; } -.bi-chevron-double-down::before { content: "\f27e"; } -.bi-chevron-double-left::before { content: "\f27f"; } -.bi-chevron-double-right::before { content: "\f280"; } -.bi-chevron-double-up::before { content: "\f281"; } -.bi-chevron-down::before { content: "\f282"; } -.bi-chevron-expand::before { content: "\f283"; } -.bi-chevron-left::before { content: "\f284"; } -.bi-chevron-right::before { content: "\f285"; } -.bi-chevron-up::before { content: "\f286"; } -.bi-circle-fill::before { content: "\f287"; } -.bi-circle-half::before { content: "\f288"; } -.bi-circle-square::before { content: "\f289"; } -.bi-circle::before { content: "\f28a"; } -.bi-clipboard-check::before { content: "\f28b"; } -.bi-clipboard-data::before { content: "\f28c"; } -.bi-clipboard-minus::before { content: "\f28d"; } -.bi-clipboard-plus::before { content: "\f28e"; } -.bi-clipboard-x::before { content: "\f28f"; } -.bi-clipboard::before { content: "\f290"; } -.bi-clock-fill::before { content: "\f291"; } -.bi-clock-history::before { content: "\f292"; } -.bi-clock::before { content: "\f293"; } -.bi-cloud-arrow-down-fill::before { content: "\f294"; } -.bi-cloud-arrow-down::before { content: "\f295"; } -.bi-cloud-arrow-up-fill::before { content: "\f296"; } -.bi-cloud-arrow-up::before { content: "\f297"; } -.bi-cloud-check-fill::before { content: "\f298"; } -.bi-cloud-check::before { content: "\f299"; } -.bi-cloud-download-fill::before { content: "\f29a"; } -.bi-cloud-download::before { content: "\f29b"; } -.bi-cloud-drizzle-fill::before { content: "\f29c"; } -.bi-cloud-drizzle::before { content: "\f29d"; } -.bi-cloud-fill::before { content: "\f29e"; } -.bi-cloud-fog-fill::before { content: "\f29f"; } -.bi-cloud-fog::before { content: "\f2a0"; } -.bi-cloud-fog2-fill::before { content: "\f2a1"; } -.bi-cloud-fog2::before { content: "\f2a2"; } -.bi-cloud-hail-fill::before { content: "\f2a3"; } -.bi-cloud-hail::before { content: "\f2a4"; } -.bi-cloud-haze-fill::before { content: "\f2a6"; } -.bi-cloud-haze::before { content: "\f2a7"; } -.bi-cloud-haze2-fill::before { content: "\f2a8"; } -.bi-cloud-lightning-fill::before { content: "\f2a9"; } -.bi-cloud-lightning-rain-fill::before { content: "\f2aa"; } -.bi-cloud-lightning-rain::before { content: "\f2ab"; } -.bi-cloud-lightning::before { content: "\f2ac"; } -.bi-cloud-minus-fill::before { content: "\f2ad"; } -.bi-cloud-minus::before { content: "\f2ae"; } -.bi-cloud-moon-fill::before { content: "\f2af"; } -.bi-cloud-moon::before { content: "\f2b0"; } -.bi-cloud-plus-fill::before { content: "\f2b1"; } -.bi-cloud-plus::before { content: "\f2b2"; } -.bi-cloud-rain-fill::before { content: "\f2b3"; } -.bi-cloud-rain-heavy-fill::before { content: "\f2b4"; } -.bi-cloud-rain-heavy::before { content: "\f2b5"; } -.bi-cloud-rain::before { content: "\f2b6"; } -.bi-cloud-slash-fill::before { content: "\f2b7"; } -.bi-cloud-slash::before { content: "\f2b8"; } -.bi-cloud-sleet-fill::before { content: "\f2b9"; } -.bi-cloud-sleet::before { content: "\f2ba"; } -.bi-cloud-snow-fill::before { content: "\f2bb"; } -.bi-cloud-snow::before { content: "\f2bc"; } -.bi-cloud-sun-fill::before { content: "\f2bd"; } -.bi-cloud-sun::before { content: "\f2be"; } -.bi-cloud-upload-fill::before { content: "\f2bf"; } -.bi-cloud-upload::before { content: "\f2c0"; } -.bi-cloud::before { content: "\f2c1"; } -.bi-clouds-fill::before { content: "\f2c2"; } -.bi-clouds::before { content: "\f2c3"; } -.bi-cloudy-fill::before { content: "\f2c4"; } -.bi-cloudy::before { content: "\f2c5"; } -.bi-code-slash::before { content: "\f2c6"; } -.bi-code-square::before { content: "\f2c7"; } -.bi-code::before { content: "\f2c8"; } -.bi-collection-fill::before { content: "\f2c9"; } -.bi-collection-play-fill::before { content: "\f2ca"; } -.bi-collection-play::before { content: "\f2cb"; } -.bi-collection::before { content: "\f2cc"; } -.bi-columns-gap::before { content: "\f2cd"; } -.bi-columns::before { content: "\f2ce"; } -.bi-command::before { content: "\f2cf"; } -.bi-compass-fill::before { content: "\f2d0"; } -.bi-compass::before { content: "\f2d1"; } -.bi-cone-striped::before { content: "\f2d2"; } -.bi-cone::before { content: "\f2d3"; } -.bi-controller::before { content: "\f2d4"; } -.bi-cpu-fill::before { content: "\f2d5"; } -.bi-cpu::before { content: "\f2d6"; } -.bi-credit-card-2-back-fill::before { content: "\f2d7"; } -.bi-credit-card-2-back::before { content: "\f2d8"; } -.bi-credit-card-2-front-fill::before { content: "\f2d9"; } -.bi-credit-card-2-front::before { content: "\f2da"; } -.bi-credit-card-fill::before { content: "\f2db"; } -.bi-credit-card::before { content: "\f2dc"; } -.bi-crop::before { content: "\f2dd"; } -.bi-cup-fill::before { content: "\f2de"; } -.bi-cup-straw::before { content: "\f2df"; } -.bi-cup::before { content: "\f2e0"; } -.bi-cursor-fill::before { content: "\f2e1"; } -.bi-cursor-text::before { content: "\f2e2"; } -.bi-cursor::before { content: "\f2e3"; } -.bi-dash-circle-dotted::before { content: "\f2e4"; } -.bi-dash-circle-fill::before { content: "\f2e5"; } -.bi-dash-circle::before { content: "\f2e6"; } -.bi-dash-square-dotted::before { content: "\f2e7"; } -.bi-dash-square-fill::before { content: "\f2e8"; } -.bi-dash-square::before { content: "\f2e9"; } -.bi-dash::before { content: "\f2ea"; } -.bi-diagram-2-fill::before { content: "\f2eb"; } -.bi-diagram-2::before { content: "\f2ec"; } -.bi-diagram-3-fill::before { content: "\f2ed"; } -.bi-diagram-3::before { content: "\f2ee"; } -.bi-diamond-fill::before { content: "\f2ef"; } -.bi-diamond-half::before { content: "\f2f0"; } -.bi-diamond::before { content: "\f2f1"; } -.bi-dice-1-fill::before { content: "\f2f2"; } -.bi-dice-1::before { content: "\f2f3"; } -.bi-dice-2-fill::before { content: "\f2f4"; } -.bi-dice-2::before { content: "\f2f5"; } -.bi-dice-3-fill::before { content: "\f2f6"; } -.bi-dice-3::before { content: "\f2f7"; } -.bi-dice-4-fill::before { content: "\f2f8"; } -.bi-dice-4::before { content: "\f2f9"; } -.bi-dice-5-fill::before { content: "\f2fa"; } -.bi-dice-5::before { content: "\f2fb"; } -.bi-dice-6-fill::before { content: "\f2fc"; } -.bi-dice-6::before { content: "\f2fd"; } -.bi-disc-fill::before { content: "\f2fe"; } -.bi-disc::before { content: "\f2ff"; } -.bi-discord::before { content: "\f300"; } -.bi-display-fill::before { content: "\f301"; } -.bi-display::before { content: "\f302"; } -.bi-distribute-horizontal::before { content: "\f303"; } -.bi-distribute-vertical::before { content: "\f304"; } -.bi-door-closed-fill::before { content: "\f305"; } -.bi-door-closed::before { content: "\f306"; } -.bi-door-open-fill::before { content: "\f307"; } -.bi-door-open::before { content: "\f308"; } -.bi-dot::before { content: "\f309"; } -.bi-download::before { content: "\f30a"; } -.bi-droplet-fill::before { content: "\f30b"; } -.bi-droplet-half::before { content: "\f30c"; } -.bi-droplet::before { content: "\f30d"; } -.bi-earbuds::before { content: "\f30e"; } -.bi-easel-fill::before { content: "\f30f"; } -.bi-easel::before { content: "\f310"; } -.bi-egg-fill::before { content: "\f311"; } -.bi-egg-fried::before { content: "\f312"; } -.bi-egg::before { content: "\f313"; } -.bi-eject-fill::before { content: "\f314"; } -.bi-eject::before { content: "\f315"; } -.bi-emoji-angry-fill::before { content: "\f316"; } -.bi-emoji-angry::before { content: "\f317"; } -.bi-emoji-dizzy-fill::before { content: "\f318"; } -.bi-emoji-dizzy::before { content: "\f319"; } -.bi-emoji-expressionless-fill::before { content: "\f31a"; } -.bi-emoji-expressionless::before { content: "\f31b"; } -.bi-emoji-frown-fill::before { content: "\f31c"; } -.bi-emoji-frown::before { content: "\f31d"; } -.bi-emoji-heart-eyes-fill::before { content: "\f31e"; } -.bi-emoji-heart-eyes::before { content: "\f31f"; } -.bi-emoji-laughing-fill::before { content: "\f320"; } -.bi-emoji-laughing::before { content: "\f321"; } -.bi-emoji-neutral-fill::before { content: "\f322"; } -.bi-emoji-neutral::before { content: "\f323"; } -.bi-emoji-smile-fill::before { content: "\f324"; } -.bi-emoji-smile-upside-down-fill::before { content: "\f325"; } -.bi-emoji-smile-upside-down::before { content: "\f326"; } -.bi-emoji-smile::before { content: "\f327"; } -.bi-emoji-sunglasses-fill::before { content: "\f328"; } -.bi-emoji-sunglasses::before { content: "\f329"; } -.bi-emoji-wink-fill::before { content: "\f32a"; } -.bi-emoji-wink::before { content: "\f32b"; } -.bi-envelope-fill::before { content: "\f32c"; } -.bi-envelope-open-fill::before { content: "\f32d"; } -.bi-envelope-open::before { content: "\f32e"; } -.bi-envelope::before { content: "\f32f"; } -.bi-eraser-fill::before { content: "\f330"; } -.bi-eraser::before { content: "\f331"; } -.bi-exclamation-circle-fill::before { content: "\f332"; } -.bi-exclamation-circle::before { content: "\f333"; } -.bi-exclamation-diamond-fill::before { content: "\f334"; } -.bi-exclamation-diamond::before { content: "\f335"; } -.bi-exclamation-octagon-fill::before { content: "\f336"; } -.bi-exclamation-octagon::before { content: "\f337"; } -.bi-exclamation-square-fill::before { content: "\f338"; } -.bi-exclamation-square::before { content: "\f339"; } -.bi-exclamation-triangle-fill::before { content: "\f33a"; } -.bi-exclamation-triangle::before { content: "\f33b"; } -.bi-exclamation::before { content: "\f33c"; } -.bi-exclude::before { content: "\f33d"; } -.bi-eye-fill::before { content: "\f33e"; } -.bi-eye-slash-fill::before { content: "\f33f"; } -.bi-eye-slash::before { content: "\f340"; } -.bi-eye::before { content: "\f341"; } -.bi-eyedropper::before { content: "\f342"; } -.bi-eyeglasses::before { content: "\f343"; } -.bi-facebook::before { content: "\f344"; } -.bi-file-arrow-down-fill::before { content: "\f345"; } -.bi-file-arrow-down::before { content: "\f346"; } -.bi-file-arrow-up-fill::before { content: "\f347"; } -.bi-file-arrow-up::before { content: "\f348"; } -.bi-file-bar-graph-fill::before { content: "\f349"; } -.bi-file-bar-graph::before { content: "\f34a"; } -.bi-file-binary-fill::before { content: "\f34b"; } -.bi-file-binary::before { content: "\f34c"; } -.bi-file-break-fill::before { content: "\f34d"; } -.bi-file-break::before { content: "\f34e"; } -.bi-file-check-fill::before { content: "\f34f"; } -.bi-file-check::before { content: "\f350"; } -.bi-file-code-fill::before { content: "\f351"; } -.bi-file-code::before { content: "\f352"; } -.bi-file-diff-fill::before { content: "\f353"; } -.bi-file-diff::before { content: "\f354"; } -.bi-file-earmark-arrow-down-fill::before { content: "\f355"; } -.bi-file-earmark-arrow-down::before { content: "\f356"; } -.bi-file-earmark-arrow-up-fill::before { content: "\f357"; } -.bi-file-earmark-arrow-up::before { content: "\f358"; } -.bi-file-earmark-bar-graph-fill::before { content: "\f359"; } -.bi-file-earmark-bar-graph::before { content: "\f35a"; } -.bi-file-earmark-binary-fill::before { content: "\f35b"; } -.bi-file-earmark-binary::before { content: "\f35c"; } -.bi-file-earmark-break-fill::before { content: "\f35d"; } -.bi-file-earmark-break::before { content: "\f35e"; } -.bi-file-earmark-check-fill::before { content: "\f35f"; } -.bi-file-earmark-check::before { content: "\f360"; } -.bi-file-earmark-code-fill::before { content: "\f361"; } -.bi-file-earmark-code::before { content: "\f362"; } -.bi-file-earmark-diff-fill::before { content: "\f363"; } -.bi-file-earmark-diff::before { content: "\f364"; } -.bi-file-earmark-easel-fill::before { content: "\f365"; } -.bi-file-earmark-easel::before { content: "\f366"; } -.bi-file-earmark-excel-fill::before { content: "\f367"; } -.bi-file-earmark-excel::before { content: "\f368"; } -.bi-file-earmark-fill::before { content: "\f369"; } -.bi-file-earmark-font-fill::before { content: "\f36a"; } -.bi-file-earmark-font::before { content: "\f36b"; } -.bi-file-earmark-image-fill::before { content: "\f36c"; } -.bi-file-earmark-image::before { content: "\f36d"; } -.bi-file-earmark-lock-fill::before { content: "\f36e"; } -.bi-file-earmark-lock::before { content: "\f36f"; } -.bi-file-earmark-lock2-fill::before { content: "\f370"; } -.bi-file-earmark-lock2::before { content: "\f371"; } -.bi-file-earmark-medical-fill::before { content: "\f372"; } -.bi-file-earmark-medical::before { content: "\f373"; } -.bi-file-earmark-minus-fill::before { content: "\f374"; } -.bi-file-earmark-minus::before { content: "\f375"; } -.bi-file-earmark-music-fill::before { content: "\f376"; } -.bi-file-earmark-music::before { content: "\f377"; } -.bi-file-earmark-person-fill::before { content: "\f378"; } -.bi-file-earmark-person::before { content: "\f379"; } -.bi-file-earmark-play-fill::before { content: "\f37a"; } -.bi-file-earmark-play::before { content: "\f37b"; } -.bi-file-earmark-plus-fill::before { content: "\f37c"; } -.bi-file-earmark-plus::before { content: "\f37d"; } -.bi-file-earmark-post-fill::before { content: "\f37e"; } -.bi-file-earmark-post::before { content: "\f37f"; } -.bi-file-earmark-ppt-fill::before { content: "\f380"; } -.bi-file-earmark-ppt::before { content: "\f381"; } -.bi-file-earmark-richtext-fill::before { content: "\f382"; } -.bi-file-earmark-richtext::before { content: "\f383"; } -.bi-file-earmark-ruled-fill::before { content: "\f384"; } -.bi-file-earmark-ruled::before { content: "\f385"; } -.bi-file-earmark-slides-fill::before { content: "\f386"; } -.bi-file-earmark-slides::before { content: "\f387"; } -.bi-file-earmark-spreadsheet-fill::before { content: "\f388"; } -.bi-file-earmark-spreadsheet::before { content: "\f389"; } -.bi-file-earmark-text-fill::before { content: "\f38a"; } -.bi-file-earmark-text::before { content: "\f38b"; } -.bi-file-earmark-word-fill::before { content: "\f38c"; } -.bi-file-earmark-word::before { content: "\f38d"; } -.bi-file-earmark-x-fill::before { content: "\f38e"; } -.bi-file-earmark-x::before { content: "\f38f"; } -.bi-file-earmark-zip-fill::before { content: "\f390"; } -.bi-file-earmark-zip::before { content: "\f391"; } -.bi-file-earmark::before { content: "\f392"; } -.bi-file-easel-fill::before { content: "\f393"; } -.bi-file-easel::before { content: "\f394"; } -.bi-file-excel-fill::before { content: "\f395"; } -.bi-file-excel::before { content: "\f396"; } -.bi-file-fill::before { content: "\f397"; } -.bi-file-font-fill::before { content: "\f398"; } -.bi-file-font::before { content: "\f399"; } -.bi-file-image-fill::before { content: "\f39a"; } -.bi-file-image::before { content: "\f39b"; } -.bi-file-lock-fill::before { content: "\f39c"; } -.bi-file-lock::before { content: "\f39d"; } -.bi-file-lock2-fill::before { content: "\f39e"; } -.bi-file-lock2::before { content: "\f39f"; } -.bi-file-medical-fill::before { content: "\f3a0"; } -.bi-file-medical::before { content: "\f3a1"; } -.bi-file-minus-fill::before { content: "\f3a2"; } -.bi-file-minus::before { content: "\f3a3"; } -.bi-file-music-fill::before { content: "\f3a4"; } -.bi-file-music::before { content: "\f3a5"; } -.bi-file-person-fill::before { content: "\f3a6"; } -.bi-file-person::before { content: "\f3a7"; } -.bi-file-play-fill::before { content: "\f3a8"; } -.bi-file-play::before { content: "\f3a9"; } -.bi-file-plus-fill::before { content: "\f3aa"; } -.bi-file-plus::before { content: "\f3ab"; } -.bi-file-post-fill::before { content: "\f3ac"; } -.bi-file-post::before { content: "\f3ad"; } -.bi-file-ppt-fill::before { content: "\f3ae"; } -.bi-file-ppt::before { content: "\f3af"; } -.bi-file-richtext-fill::before { content: "\f3b0"; } -.bi-file-richtext::before { content: "\f3b1"; } -.bi-file-ruled-fill::before { content: "\f3b2"; } -.bi-file-ruled::before { content: "\f3b3"; } -.bi-file-slides-fill::before { content: "\f3b4"; } -.bi-file-slides::before { content: "\f3b5"; } -.bi-file-spreadsheet-fill::before { content: "\f3b6"; } -.bi-file-spreadsheet::before { content: "\f3b7"; } -.bi-file-text-fill::before { content: "\f3b8"; } -.bi-file-text::before { content: "\f3b9"; } -.bi-file-word-fill::before { content: "\f3ba"; } -.bi-file-word::before { content: "\f3bb"; } -.bi-file-x-fill::before { content: "\f3bc"; } -.bi-file-x::before { content: "\f3bd"; } -.bi-file-zip-fill::before { content: "\f3be"; } -.bi-file-zip::before { content: "\f3bf"; } -.bi-file::before { content: "\f3c0"; } -.bi-files-alt::before { content: "\f3c1"; } -.bi-files::before { content: "\f3c2"; } -.bi-film::before { content: "\f3c3"; } -.bi-filter-circle-fill::before { content: "\f3c4"; } -.bi-filter-circle::before { content: "\f3c5"; } -.bi-filter-left::before { content: "\f3c6"; } -.bi-filter-right::before { content: "\f3c7"; } -.bi-filter-square-fill::before { content: "\f3c8"; } -.bi-filter-square::before { content: "\f3c9"; } -.bi-filter::before { content: "\f3ca"; } -.bi-flag-fill::before { content: "\f3cb"; } -.bi-flag::before { content: "\f3cc"; } -.bi-flower1::before { content: "\f3cd"; } -.bi-flower2::before { content: "\f3ce"; } -.bi-flower3::before { content: "\f3cf"; } -.bi-folder-check::before { content: "\f3d0"; } -.bi-folder-fill::before { content: "\f3d1"; } -.bi-folder-minus::before { content: "\f3d2"; } -.bi-folder-plus::before { content: "\f3d3"; } -.bi-folder-symlink-fill::before { content: "\f3d4"; } -.bi-folder-symlink::before { content: "\f3d5"; } -.bi-folder-x::before { content: "\f3d6"; } -.bi-folder::before { content: "\f3d7"; } -.bi-folder2-open::before { content: "\f3d8"; } -.bi-folder2::before { content: "\f3d9"; } -.bi-fonts::before { content: "\f3da"; } -.bi-forward-fill::before { content: "\f3db"; } -.bi-forward::before { content: "\f3dc"; } -.bi-front::before { content: "\f3dd"; } -.bi-fullscreen-exit::before { content: "\f3de"; } -.bi-fullscreen::before { content: "\f3df"; } -.bi-funnel-fill::before { content: "\f3e0"; } -.bi-funnel::before { content: "\f3e1"; } -.bi-gear-fill::before { content: "\f3e2"; } -.bi-gear-wide-connected::before { content: "\f3e3"; } -.bi-gear-wide::before { content: "\f3e4"; } -.bi-gear::before { content: "\f3e5"; } -.bi-gem::before { content: "\f3e6"; } -.bi-geo-alt-fill::before { content: "\f3e7"; } -.bi-geo-alt::before { content: "\f3e8"; } -.bi-geo-fill::before { content: "\f3e9"; } -.bi-geo::before { content: "\f3ea"; } -.bi-gift-fill::before { content: "\f3eb"; } -.bi-gift::before { content: "\f3ec"; } -.bi-github::before { content: "\f3ed"; } -.bi-globe::before { content: "\f3ee"; } -.bi-globe2::before { content: "\f3ef"; } -.bi-google::before { content: "\f3f0"; } -.bi-graph-down::before { content: "\f3f1"; } -.bi-graph-up::before { content: "\f3f2"; } -.bi-grid-1x2-fill::before { content: "\f3f3"; } -.bi-grid-1x2::before { content: "\f3f4"; } -.bi-grid-3x2-gap-fill::before { content: "\f3f5"; } -.bi-grid-3x2-gap::before { content: "\f3f6"; } -.bi-grid-3x2::before { content: "\f3f7"; } -.bi-grid-3x3-gap-fill::before { content: "\f3f8"; } -.bi-grid-3x3-gap::before { content: "\f3f9"; } -.bi-grid-3x3::before { content: "\f3fa"; } -.bi-grid-fill::before { content: "\f3fb"; } -.bi-grid::before { content: "\f3fc"; } -.bi-grip-horizontal::before { content: "\f3fd"; } -.bi-grip-vertical::before { content: "\f3fe"; } -.bi-hammer::before { content: "\f3ff"; } -.bi-hand-index-fill::before { content: "\f400"; } -.bi-hand-index-thumb-fill::before { content: "\f401"; } -.bi-hand-index-thumb::before { content: "\f402"; } -.bi-hand-index::before { content: "\f403"; } -.bi-hand-thumbs-down-fill::before { content: "\f404"; } -.bi-hand-thumbs-down::before { content: "\f405"; } -.bi-hand-thumbs-up-fill::before { content: "\f406"; } -.bi-hand-thumbs-up::before { content: "\f407"; } -.bi-handbag-fill::before { content: "\f408"; } -.bi-handbag::before { content: "\f409"; } -.bi-hash::before { content: "\f40a"; } -.bi-hdd-fill::before { content: "\f40b"; } -.bi-hdd-network-fill::before { content: "\f40c"; } -.bi-hdd-network::before { content: "\f40d"; } -.bi-hdd-rack-fill::before { content: "\f40e"; } -.bi-hdd-rack::before { content: "\f40f"; } -.bi-hdd-stack-fill::before { content: "\f410"; } -.bi-hdd-stack::before { content: "\f411"; } -.bi-hdd::before { content: "\f412"; } -.bi-headphones::before { content: "\f413"; } -.bi-headset::before { content: "\f414"; } -.bi-heart-fill::before { content: "\f415"; } -.bi-heart-half::before { content: "\f416"; } -.bi-heart::before { content: "\f417"; } -.bi-heptagon-fill::before { content: "\f418"; } -.bi-heptagon-half::before { content: "\f419"; } -.bi-heptagon::before { content: "\f41a"; } -.bi-hexagon-fill::before { content: "\f41b"; } -.bi-hexagon-half::before { content: "\f41c"; } -.bi-hexagon::before { content: "\f41d"; } -.bi-hourglass-bottom::before { content: "\f41e"; } -.bi-hourglass-split::before { content: "\f41f"; } -.bi-hourglass-top::before { content: "\f420"; } -.bi-hourglass::before { content: "\f421"; } -.bi-house-door-fill::before { content: "\f422"; } -.bi-house-door::before { content: "\f423"; } -.bi-house-fill::before { content: "\f424"; } -.bi-house::before { content: "\f425"; } -.bi-hr::before { content: "\f426"; } -.bi-hurricane::before { content: "\f427"; } -.bi-image-alt::before { content: "\f428"; } -.bi-image-fill::before { content: "\f429"; } -.bi-image::before { content: "\f42a"; } -.bi-images::before { content: "\f42b"; } -.bi-inbox-fill::before { content: "\f42c"; } -.bi-inbox::before { content: "\f42d"; } -.bi-inboxes-fill::before { content: "\f42e"; } -.bi-inboxes::before { content: "\f42f"; } -.bi-info-circle-fill::before { content: "\f430"; } -.bi-info-circle::before { content: "\f431"; } -.bi-info-square-fill::before { content: "\f432"; } -.bi-info-square::before { content: "\f433"; } -.bi-info::before { content: "\f434"; } -.bi-input-cursor-text::before { content: "\f435"; } -.bi-input-cursor::before { content: "\f436"; } -.bi-instagram::before { content: "\f437"; } -.bi-intersect::before { content: "\f438"; } -.bi-journal-album::before { content: "\f439"; } -.bi-journal-arrow-down::before { content: "\f43a"; } -.bi-journal-arrow-up::before { content: "\f43b"; } -.bi-journal-bookmark-fill::before { content: "\f43c"; } -.bi-journal-bookmark::before { content: "\f43d"; } -.bi-journal-check::before { content: "\f43e"; } -.bi-journal-code::before { content: "\f43f"; } -.bi-journal-medical::before { content: "\f440"; } -.bi-journal-minus::before { content: "\f441"; } -.bi-journal-plus::before { content: "\f442"; } -.bi-journal-richtext::before { content: "\f443"; } -.bi-journal-text::before { content: "\f444"; } -.bi-journal-x::before { content: "\f445"; } -.bi-journal::before { content: "\f446"; } -.bi-journals::before { content: "\f447"; } -.bi-joystick::before { content: "\f448"; } -.bi-justify-left::before { content: "\f449"; } -.bi-justify-right::before { content: "\f44a"; } -.bi-justify::before { content: "\f44b"; } -.bi-kanban-fill::before { content: "\f44c"; } -.bi-kanban::before { content: "\f44d"; } -.bi-key-fill::before { content: "\f44e"; } -.bi-key::before { content: "\f44f"; } -.bi-keyboard-fill::before { content: "\f450"; } -.bi-keyboard::before { content: "\f451"; } -.bi-ladder::before { content: "\f452"; } -.bi-lamp-fill::before { content: "\f453"; } -.bi-lamp::before { content: "\f454"; } -.bi-laptop-fill::before { content: "\f455"; } -.bi-laptop::before { content: "\f456"; } -.bi-layer-backward::before { content: "\f457"; } -.bi-layer-forward::before { content: "\f458"; } -.bi-layers-fill::before { content: "\f459"; } -.bi-layers-half::before { content: "\f45a"; } -.bi-layers::before { content: "\f45b"; } -.bi-layout-sidebar-inset-reverse::before { content: "\f45c"; } -.bi-layout-sidebar-inset::before { content: "\f45d"; } -.bi-layout-sidebar-reverse::before { content: "\f45e"; } -.bi-layout-sidebar::before { content: "\f45f"; } -.bi-layout-split::before { content: "\f460"; } -.bi-layout-text-sidebar-reverse::before { content: "\f461"; } -.bi-layout-text-sidebar::before { content: "\f462"; } -.bi-layout-text-window-reverse::before { content: "\f463"; } -.bi-layout-text-window::before { content: "\f464"; } -.bi-layout-three-columns::before { content: "\f465"; } -.bi-layout-wtf::before { content: "\f466"; } -.bi-life-preserver::before { content: "\f467"; } -.bi-lightbulb-fill::before { content: "\f468"; } -.bi-lightbulb-off-fill::before { content: "\f469"; } -.bi-lightbulb-off::before { content: "\f46a"; } -.bi-lightbulb::before { content: "\f46b"; } -.bi-lightning-charge-fill::before { content: "\f46c"; } -.bi-lightning-charge::before { content: "\f46d"; } -.bi-lightning-fill::before { content: "\f46e"; } -.bi-lightning::before { content: "\f46f"; } -.bi-link-45deg::before { content: "\f470"; } -.bi-link::before { content: "\f471"; } -.bi-linkedin::before { content: "\f472"; } -.bi-list-check::before { content: "\f473"; } -.bi-list-nested::before { content: "\f474"; } -.bi-list-ol::before { content: "\f475"; } -.bi-list-stars::before { content: "\f476"; } -.bi-list-task::before { content: "\f477"; } -.bi-list-ul::before { content: "\f478"; } -.bi-list::before { content: "\f479"; } -.bi-lock-fill::before { content: "\f47a"; } -.bi-lock::before { content: "\f47b"; } -.bi-mailbox::before { content: "\f47c"; } -.bi-mailbox2::before { content: "\f47d"; } -.bi-map-fill::before { content: "\f47e"; } -.bi-map::before { content: "\f47f"; } -.bi-markdown-fill::before { content: "\f480"; } -.bi-markdown::before { content: "\f481"; } -.bi-mask::before { content: "\f482"; } -.bi-megaphone-fill::before { content: "\f483"; } -.bi-megaphone::before { content: "\f484"; } -.bi-menu-app-fill::before { content: "\f485"; } -.bi-menu-app::before { content: "\f486"; } -.bi-menu-button-fill::before { content: "\f487"; } -.bi-menu-button-wide-fill::before { content: "\f488"; } -.bi-menu-button-wide::before { content: "\f489"; } -.bi-menu-button::before { content: "\f48a"; } -.bi-menu-down::before { content: "\f48b"; } -.bi-menu-up::before { content: "\f48c"; } -.bi-mic-fill::before { content: "\f48d"; } -.bi-mic-mute-fill::before { content: "\f48e"; } -.bi-mic-mute::before { content: "\f48f"; } -.bi-mic::before { content: "\f490"; } -.bi-minecart-loaded::before { content: "\f491"; } -.bi-minecart::before { content: "\f492"; } -.bi-moisture::before { content: "\f493"; } -.bi-moon-fill::before { content: "\f494"; } -.bi-moon-stars-fill::before { content: "\f495"; } -.bi-moon-stars::before { content: "\f496"; } -.bi-moon::before { content: "\f497"; } -.bi-mouse-fill::before { content: "\f498"; } -.bi-mouse::before { content: "\f499"; } -.bi-mouse2-fill::before { content: "\f49a"; } -.bi-mouse2::before { content: "\f49b"; } -.bi-mouse3-fill::before { content: "\f49c"; } -.bi-mouse3::before { content: "\f49d"; } -.bi-music-note-beamed::before { content: "\f49e"; } -.bi-music-note-list::before { content: "\f49f"; } -.bi-music-note::before { content: "\f4a0"; } -.bi-music-player-fill::before { content: "\f4a1"; } -.bi-music-player::before { content: "\f4a2"; } -.bi-newspaper::before { content: "\f4a3"; } -.bi-node-minus-fill::before { content: "\f4a4"; } -.bi-node-minus::before { content: "\f4a5"; } -.bi-node-plus-fill::before { content: "\f4a6"; } -.bi-node-plus::before { content: "\f4a7"; } -.bi-nut-fill::before { content: "\f4a8"; } -.bi-nut::before { content: "\f4a9"; } -.bi-octagon-fill::before { content: "\f4aa"; } -.bi-octagon-half::before { content: "\f4ab"; } -.bi-octagon::before { content: "\f4ac"; } -.bi-option::before { content: "\f4ad"; } -.bi-outlet::before { content: "\f4ae"; } -.bi-paint-bucket::before { content: "\f4af"; } -.bi-palette-fill::before { content: "\f4b0"; } -.bi-palette::before { content: "\f4b1"; } -.bi-palette2::before { content: "\f4b2"; } -.bi-paperclip::before { content: "\f4b3"; } -.bi-paragraph::before { content: "\f4b4"; } -.bi-patch-check-fill::before { content: "\f4b5"; } -.bi-patch-check::before { content: "\f4b6"; } -.bi-patch-exclamation-fill::before { content: "\f4b7"; } -.bi-patch-exclamation::before { content: "\f4b8"; } -.bi-patch-minus-fill::before { content: "\f4b9"; } -.bi-patch-minus::before { content: "\f4ba"; } -.bi-patch-plus-fill::before { content: "\f4bb"; } -.bi-patch-plus::before { content: "\f4bc"; } -.bi-patch-question-fill::before { content: "\f4bd"; } -.bi-patch-question::before { content: "\f4be"; } -.bi-pause-btn-fill::before { content: "\f4bf"; } -.bi-pause-btn::before { content: "\f4c0"; } -.bi-pause-circle-fill::before { content: "\f4c1"; } -.bi-pause-circle::before { content: "\f4c2"; } -.bi-pause-fill::before { content: "\f4c3"; } -.bi-pause::before { content: "\f4c4"; } -.bi-peace-fill::before { content: "\f4c5"; } -.bi-peace::before { content: "\f4c6"; } -.bi-pen-fill::before { content: "\f4c7"; } -.bi-pen::before { content: "\f4c8"; } -.bi-pencil-fill::before { content: "\f4c9"; } -.bi-pencil-square::before { content: "\f4ca"; } -.bi-pencil::before { content: "\f4cb"; } -.bi-pentagon-fill::before { content: "\f4cc"; } -.bi-pentagon-half::before { content: "\f4cd"; } -.bi-pentagon::before { content: "\f4ce"; } -.bi-people-fill::before { content: "\f4cf"; } -.bi-people::before { content: "\f4d0"; } -.bi-percent::before { content: "\f4d1"; } -.bi-person-badge-fill::before { content: "\f4d2"; } -.bi-person-badge::before { content: "\f4d3"; } -.bi-person-bounding-box::before { content: "\f4d4"; } -.bi-person-check-fill::before { content: "\f4d5"; } -.bi-person-check::before { content: "\f4d6"; } -.bi-person-circle::before { content: "\f4d7"; } -.bi-person-dash-fill::before { content: "\f4d8"; } -.bi-person-dash::before { content: "\f4d9"; } -.bi-person-fill::before { content: "\f4da"; } -.bi-person-lines-fill::before { content: "\f4db"; } -.bi-person-plus-fill::before { content: "\f4dc"; } -.bi-person-plus::before { content: "\f4dd"; } -.bi-person-square::before { content: "\f4de"; } -.bi-person-x-fill::before { content: "\f4df"; } -.bi-person-x::before { content: "\f4e0"; } -.bi-person::before { content: "\f4e1"; } -.bi-phone-fill::before { content: "\f4e2"; } -.bi-phone-landscape-fill::before { content: "\f4e3"; } -.bi-phone-landscape::before { content: "\f4e4"; } -.bi-phone-vibrate-fill::before { content: "\f4e5"; } -.bi-phone-vibrate::before { content: "\f4e6"; } -.bi-phone::before { content: "\f4e7"; } -.bi-pie-chart-fill::before { content: "\f4e8"; } -.bi-pie-chart::before { content: "\f4e9"; } -.bi-pin-angle-fill::before { content: "\f4ea"; } -.bi-pin-angle::before { content: "\f4eb"; } -.bi-pin-fill::before { content: "\f4ec"; } -.bi-pin::before { content: "\f4ed"; } -.bi-pip-fill::before { content: "\f4ee"; } -.bi-pip::before { content: "\f4ef"; } -.bi-play-btn-fill::before { content: "\f4f0"; } -.bi-play-btn::before { content: "\f4f1"; } -.bi-play-circle-fill::before { content: "\f4f2"; } -.bi-play-circle::before { content: "\f4f3"; } -.bi-play-fill::before { content: "\f4f4"; } -.bi-play::before { content: "\f4f5"; } -.bi-plug-fill::before { content: "\f4f6"; } -.bi-plug::before { content: "\f4f7"; } -.bi-plus-circle-dotted::before { content: "\f4f8"; } -.bi-plus-circle-fill::before { content: "\f4f9"; } -.bi-plus-circle::before { content: "\f4fa"; } -.bi-plus-square-dotted::before { content: "\f4fb"; } -.bi-plus-square-fill::before { content: "\f4fc"; } -.bi-plus-square::before { content: "\f4fd"; } -.bi-plus::before { content: "\f4fe"; } -.bi-power::before { content: "\f4ff"; } -.bi-printer-fill::before { content: "\f500"; } -.bi-printer::before { content: "\f501"; } -.bi-puzzle-fill::before { content: "\f502"; } -.bi-puzzle::before { content: "\f503"; } -.bi-question-circle-fill::before { content: "\f504"; } -.bi-question-circle::before { content: "\f505"; } -.bi-question-diamond-fill::before { content: "\f506"; } -.bi-question-diamond::before { content: "\f507"; } -.bi-question-octagon-fill::before { content: "\f508"; } -.bi-question-octagon::before { content: "\f509"; } -.bi-question-square-fill::before { content: "\f50a"; } -.bi-question-square::before { content: "\f50b"; } -.bi-question::before { content: "\f50c"; } -.bi-rainbow::before { content: "\f50d"; } -.bi-receipt-cutoff::before { content: "\f50e"; } -.bi-receipt::before { content: "\f50f"; } -.bi-reception-0::before { content: "\f510"; } -.bi-reception-1::before { content: "\f511"; } -.bi-reception-2::before { content: "\f512"; } -.bi-reception-3::before { content: "\f513"; } -.bi-reception-4::before { content: "\f514"; } -.bi-record-btn-fill::before { content: "\f515"; } -.bi-record-btn::before { content: "\f516"; } -.bi-record-circle-fill::before { content: "\f517"; } -.bi-record-circle::before { content: "\f518"; } -.bi-record-fill::before { content: "\f519"; } -.bi-record::before { content: "\f51a"; } -.bi-record2-fill::before { content: "\f51b"; } -.bi-record2::before { content: "\f51c"; } -.bi-reply-all-fill::before { content: "\f51d"; } -.bi-reply-all::before { content: "\f51e"; } -.bi-reply-fill::before { content: "\f51f"; } -.bi-reply::before { content: "\f520"; } -.bi-rss-fill::before { content: "\f521"; } -.bi-rss::before { content: "\f522"; } -.bi-rulers::before { content: "\f523"; } -.bi-save-fill::before { content: "\f524"; } -.bi-save::before { content: "\f525"; } -.bi-save2-fill::before { content: "\f526"; } -.bi-save2::before { content: "\f527"; } -.bi-scissors::before { content: "\f528"; } -.bi-screwdriver::before { content: "\f529"; } -.bi-search::before { content: "\f52a"; } -.bi-segmented-nav::before { content: "\f52b"; } -.bi-server::before { content: "\f52c"; } -.bi-share-fill::before { content: "\f52d"; } -.bi-share::before { content: "\f52e"; } -.bi-shield-check::before { content: "\f52f"; } -.bi-shield-exclamation::before { content: "\f530"; } -.bi-shield-fill-check::before { content: "\f531"; } -.bi-shield-fill-exclamation::before { content: "\f532"; } -.bi-shield-fill-minus::before { content: "\f533"; } -.bi-shield-fill-plus::before { content: "\f534"; } -.bi-shield-fill-x::before { content: "\f535"; } -.bi-shield-fill::before { content: "\f536"; } -.bi-shield-lock-fill::before { content: "\f537"; } -.bi-shield-lock::before { content: "\f538"; } -.bi-shield-minus::before { content: "\f539"; } -.bi-shield-plus::before { content: "\f53a"; } -.bi-shield-shaded::before { content: "\f53b"; } -.bi-shield-slash-fill::before { content: "\f53c"; } -.bi-shield-slash::before { content: "\f53d"; } -.bi-shield-x::before { content: "\f53e"; } -.bi-shield::before { content: "\f53f"; } -.bi-shift-fill::before { content: "\f540"; } -.bi-shift::before { content: "\f541"; } -.bi-shop-window::before { content: "\f542"; } -.bi-shop::before { content: "\f543"; } -.bi-shuffle::before { content: "\f544"; } -.bi-signpost-2-fill::before { content: "\f545"; } -.bi-signpost-2::before { content: "\f546"; } -.bi-signpost-fill::before { content: "\f547"; } -.bi-signpost-split-fill::before { content: "\f548"; } -.bi-signpost-split::before { content: "\f549"; } -.bi-signpost::before { content: "\f54a"; } -.bi-sim-fill::before { content: "\f54b"; } -.bi-sim::before { content: "\f54c"; } -.bi-skip-backward-btn-fill::before { content: "\f54d"; } -.bi-skip-backward-btn::before { content: "\f54e"; } -.bi-skip-backward-circle-fill::before { content: "\f54f"; } -.bi-skip-backward-circle::before { content: "\f550"; } -.bi-skip-backward-fill::before { content: "\f551"; } -.bi-skip-backward::before { content: "\f552"; } -.bi-skip-end-btn-fill::before { content: "\f553"; } -.bi-skip-end-btn::before { content: "\f554"; } -.bi-skip-end-circle-fill::before { content: "\f555"; } -.bi-skip-end-circle::before { content: "\f556"; } -.bi-skip-end-fill::before { content: "\f557"; } -.bi-skip-end::before { content: "\f558"; } -.bi-skip-forward-btn-fill::before { content: "\f559"; } -.bi-skip-forward-btn::before { content: "\f55a"; } -.bi-skip-forward-circle-fill::before { content: "\f55b"; } -.bi-skip-forward-circle::before { content: "\f55c"; } -.bi-skip-forward-fill::before { content: "\f55d"; } -.bi-skip-forward::before { content: "\f55e"; } -.bi-skip-start-btn-fill::before { content: "\f55f"; } -.bi-skip-start-btn::before { content: "\f560"; } -.bi-skip-start-circle-fill::before { content: "\f561"; } -.bi-skip-start-circle::before { content: "\f562"; } -.bi-skip-start-fill::before { content: "\f563"; } -.bi-skip-start::before { content: "\f564"; } -.bi-slack::before { content: "\f565"; } -.bi-slash-circle-fill::before { content: "\f566"; } -.bi-slash-circle::before { content: "\f567"; } -.bi-slash-square-fill::before { content: "\f568"; } -.bi-slash-square::before { content: "\f569"; } -.bi-slash::before { content: "\f56a"; } -.bi-sliders::before { content: "\f56b"; } -.bi-smartwatch::before { content: "\f56c"; } -.bi-snow::before { content: "\f56d"; } -.bi-snow2::before { content: "\f56e"; } -.bi-snow3::before { content: "\f56f"; } -.bi-sort-alpha-down-alt::before { content: "\f570"; } -.bi-sort-alpha-down::before { content: "\f571"; } -.bi-sort-alpha-up-alt::before { content: "\f572"; } -.bi-sort-alpha-up::before { content: "\f573"; } -.bi-sort-down-alt::before { content: "\f574"; } -.bi-sort-down::before { content: "\f575"; } -.bi-sort-numeric-down-alt::before { content: "\f576"; } -.bi-sort-numeric-down::before { content: "\f577"; } -.bi-sort-numeric-up-alt::before { content: "\f578"; } -.bi-sort-numeric-up::before { content: "\f579"; } -.bi-sort-up-alt::before { content: "\f57a"; } -.bi-sort-up::before { content: "\f57b"; } -.bi-soundwave::before { content: "\f57c"; } -.bi-speaker-fill::before { content: "\f57d"; } -.bi-speaker::before { content: "\f57e"; } -.bi-speedometer::before { content: "\f57f"; } -.bi-speedometer2::before { content: "\f580"; } -.bi-spellcheck::before { content: "\f581"; } -.bi-square-fill::before { content: "\f582"; } -.bi-square-half::before { content: "\f583"; } -.bi-square::before { content: "\f584"; } -.bi-stack::before { content: "\f585"; } -.bi-star-fill::before { content: "\f586"; } -.bi-star-half::before { content: "\f587"; } -.bi-star::before { content: "\f588"; } -.bi-stars::before { content: "\f589"; } -.bi-stickies-fill::before { content: "\f58a"; } -.bi-stickies::before { content: "\f58b"; } -.bi-sticky-fill::before { content: "\f58c"; } -.bi-sticky::before { content: "\f58d"; } -.bi-stop-btn-fill::before { content: "\f58e"; } -.bi-stop-btn::before { content: "\f58f"; } -.bi-stop-circle-fill::before { content: "\f590"; } -.bi-stop-circle::before { content: "\f591"; } -.bi-stop-fill::before { content: "\f592"; } -.bi-stop::before { content: "\f593"; } -.bi-stoplights-fill::before { content: "\f594"; } -.bi-stoplights::before { content: "\f595"; } -.bi-stopwatch-fill::before { content: "\f596"; } -.bi-stopwatch::before { content: "\f597"; } -.bi-subtract::before { content: "\f598"; } -.bi-suit-club-fill::before { content: "\f599"; } -.bi-suit-club::before { content: "\f59a"; } -.bi-suit-diamond-fill::before { content: "\f59b"; } -.bi-suit-diamond::before { content: "\f59c"; } -.bi-suit-heart-fill::before { content: "\f59d"; } -.bi-suit-heart::before { content: "\f59e"; } -.bi-suit-spade-fill::before { content: "\f59f"; } -.bi-suit-spade::before { content: "\f5a0"; } -.bi-sun-fill::before { content: "\f5a1"; } -.bi-sun::before { content: "\f5a2"; } -.bi-sunglasses::before { content: "\f5a3"; } -.bi-sunrise-fill::before { content: "\f5a4"; } -.bi-sunrise::before { content: "\f5a5"; } -.bi-sunset-fill::before { content: "\f5a6"; } -.bi-sunset::before { content: "\f5a7"; } -.bi-symmetry-horizontal::before { content: "\f5a8"; } -.bi-symmetry-vertical::before { content: "\f5a9"; } -.bi-table::before { content: "\f5aa"; } -.bi-tablet-fill::before { content: "\f5ab"; } -.bi-tablet-landscape-fill::before { content: "\f5ac"; } -.bi-tablet-landscape::before { content: "\f5ad"; } -.bi-tablet::before { content: "\f5ae"; } -.bi-tag-fill::before { content: "\f5af"; } -.bi-tag::before { content: "\f5b0"; } -.bi-tags-fill::before { content: "\f5b1"; } -.bi-tags::before { content: "\f5b2"; } -.bi-telegram::before { content: "\f5b3"; } -.bi-telephone-fill::before { content: "\f5b4"; } -.bi-telephone-forward-fill::before { content: "\f5b5"; } -.bi-telephone-forward::before { content: "\f5b6"; } -.bi-telephone-inbound-fill::before { content: "\f5b7"; } -.bi-telephone-inbound::before { content: "\f5b8"; } -.bi-telephone-minus-fill::before { content: "\f5b9"; } -.bi-telephone-minus::before { content: "\f5ba"; } -.bi-telephone-outbound-fill::before { content: "\f5bb"; } -.bi-telephone-outbound::before { content: "\f5bc"; } -.bi-telephone-plus-fill::before { content: "\f5bd"; } -.bi-telephone-plus::before { content: "\f5be"; } -.bi-telephone-x-fill::before { content: "\f5bf"; } -.bi-telephone-x::before { content: "\f5c0"; } -.bi-telephone::before { content: "\f5c1"; } -.bi-terminal-fill::before { content: "\f5c2"; } -.bi-terminal::before { content: "\f5c3"; } -.bi-text-center::before { content: "\f5c4"; } -.bi-text-indent-left::before { content: "\f5c5"; } -.bi-text-indent-right::before { content: "\f5c6"; } -.bi-text-left::before { content: "\f5c7"; } -.bi-text-paragraph::before { content: "\f5c8"; } -.bi-text-right::before { content: "\f5c9"; } -.bi-textarea-resize::before { content: "\f5ca"; } -.bi-textarea-t::before { content: "\f5cb"; } -.bi-textarea::before { content: "\f5cc"; } -.bi-thermometer-half::before { content: "\f5cd"; } -.bi-thermometer-high::before { content: "\f5ce"; } -.bi-thermometer-low::before { content: "\f5cf"; } -.bi-thermometer-snow::before { content: "\f5d0"; } -.bi-thermometer-sun::before { content: "\f5d1"; } -.bi-thermometer::before { content: "\f5d2"; } -.bi-three-dots-vertical::before { content: "\f5d3"; } -.bi-three-dots::before { content: "\f5d4"; } -.bi-toggle-off::before { content: "\f5d5"; } -.bi-toggle-on::before { content: "\f5d6"; } -.bi-toggle2-off::before { content: "\f5d7"; } -.bi-toggle2-on::before { content: "\f5d8"; } -.bi-toggles::before { content: "\f5d9"; } -.bi-toggles2::before { content: "\f5da"; } -.bi-tools::before { content: "\f5db"; } -.bi-tornado::before { content: "\f5dc"; } -.bi-trash-fill::before { content: "\f5dd"; } -.bi-trash::before { content: "\f5de"; } -.bi-trash2-fill::before { content: "\f5df"; } -.bi-trash2::before { content: "\f5e0"; } -.bi-tree-fill::before { content: "\f5e1"; } -.bi-tree::before { content: "\f5e2"; } -.bi-triangle-fill::before { content: "\f5e3"; } -.bi-triangle-half::before { content: "\f5e4"; } -.bi-triangle::before { content: "\f5e5"; } -.bi-trophy-fill::before { content: "\f5e6"; } -.bi-trophy::before { content: "\f5e7"; } -.bi-tropical-storm::before { content: "\f5e8"; } -.bi-truck-flatbed::before { content: "\f5e9"; } -.bi-truck::before { content: "\f5ea"; } -.bi-tsunami::before { content: "\f5eb"; } -.bi-tv-fill::before { content: "\f5ec"; } -.bi-tv::before { content: "\f5ed"; } -.bi-twitch::before { content: "\f5ee"; } -.bi-twitter::before { content: "\f5ef"; } -.bi-type-bold::before { content: "\f5f0"; } -.bi-type-h1::before { content: "\f5f1"; } -.bi-type-h2::before { content: "\f5f2"; } -.bi-type-h3::before { content: "\f5f3"; } -.bi-type-italic::before { content: "\f5f4"; } -.bi-type-strikethrough::before { content: "\f5f5"; } -.bi-type-underline::before { content: "\f5f6"; } -.bi-type::before { content: "\f5f7"; } -.bi-ui-checks-grid::before { content: "\f5f8"; } -.bi-ui-checks::before { content: "\f5f9"; } -.bi-ui-radios-grid::before { content: "\f5fa"; } -.bi-ui-radios::before { content: "\f5fb"; } -.bi-umbrella-fill::before { content: "\f5fc"; } -.bi-umbrella::before { content: "\f5fd"; } -.bi-union::before { content: "\f5fe"; } -.bi-unlock-fill::before { content: "\f5ff"; } -.bi-unlock::before { content: "\f600"; } -.bi-upc-scan::before { content: "\f601"; } -.bi-upc::before { content: "\f602"; } -.bi-upload::before { content: "\f603"; } -.bi-vector-pen::before { content: "\f604"; } -.bi-view-list::before { content: "\f605"; } -.bi-view-stacked::before { content: "\f606"; } -.bi-vinyl-fill::before { content: "\f607"; } -.bi-vinyl::before { content: "\f608"; } -.bi-voicemail::before { content: "\f609"; } -.bi-volume-down-fill::before { content: "\f60a"; } -.bi-volume-down::before { content: "\f60b"; } -.bi-volume-mute-fill::before { content: "\f60c"; } -.bi-volume-mute::before { content: "\f60d"; } -.bi-volume-off-fill::before { content: "\f60e"; } -.bi-volume-off::before { content: "\f60f"; } -.bi-volume-up-fill::before { content: "\f610"; } -.bi-volume-up::before { content: "\f611"; } -.bi-vr::before { content: "\f612"; } -.bi-wallet-fill::before { content: "\f613"; } -.bi-wallet::before { content: "\f614"; } -.bi-wallet2::before { content: "\f615"; } -.bi-watch::before { content: "\f616"; } -.bi-water::before { content: "\f617"; } -.bi-whatsapp::before { content: "\f618"; } -.bi-wifi-1::before { content: "\f619"; } -.bi-wifi-2::before { content: "\f61a"; } -.bi-wifi-off::before { content: "\f61b"; } -.bi-wifi::before { content: "\f61c"; } -.bi-wind::before { content: "\f61d"; } -.bi-window-dock::before { content: "\f61e"; } -.bi-window-sidebar::before { content: "\f61f"; } -.bi-window::before { content: "\f620"; } -.bi-wrench::before { content: "\f621"; } -.bi-x-circle-fill::before { content: "\f622"; } -.bi-x-circle::before { content: "\f623"; } -.bi-x-diamond-fill::before { content: "\f624"; } -.bi-x-diamond::before { content: "\f625"; } -.bi-x-octagon-fill::before { content: "\f626"; } -.bi-x-octagon::before { content: "\f627"; } -.bi-x-square-fill::before { content: "\f628"; } -.bi-x-square::before { content: "\f629"; } -.bi-x::before { content: "\f62a"; } -.bi-youtube::before { content: "\f62b"; } -.bi-zoom-in::before { content: "\f62c"; } -.bi-zoom-out::before { content: "\f62d"; } -.bi-bank::before { content: "\f62e"; } -.bi-bank2::before { content: "\f62f"; } -.bi-bell-slash-fill::before { content: "\f630"; } -.bi-bell-slash::before { content: "\f631"; } -.bi-cash-coin::before { content: "\f632"; } -.bi-check-lg::before { content: "\f633"; } -.bi-coin::before { content: "\f634"; } -.bi-currency-bitcoin::before { content: "\f635"; } -.bi-currency-dollar::before { content: "\f636"; } -.bi-currency-euro::before { content: "\f637"; } -.bi-currency-exchange::before { content: "\f638"; } -.bi-currency-pound::before { content: "\f639"; } -.bi-currency-yen::before { content: "\f63a"; } -.bi-dash-lg::before { content: "\f63b"; } -.bi-exclamation-lg::before { content: "\f63c"; } -.bi-file-earmark-pdf-fill::before { content: "\f63d"; } -.bi-file-earmark-pdf::before { content: "\f63e"; } -.bi-file-pdf-fill::before { content: "\f63f"; } -.bi-file-pdf::before { content: "\f640"; } -.bi-gender-ambiguous::before { content: "\f641"; } -.bi-gender-female::before { content: "\f642"; } -.bi-gender-male::before { content: "\f643"; } -.bi-gender-trans::before { content: "\f644"; } -.bi-headset-vr::before { content: "\f645"; } -.bi-info-lg::before { content: "\f646"; } -.bi-mastodon::before { content: "\f647"; } -.bi-messenger::before { content: "\f648"; } -.bi-piggy-bank-fill::before { content: "\f649"; } -.bi-piggy-bank::before { content: "\f64a"; } -.bi-pin-map-fill::before { content: "\f64b"; } -.bi-pin-map::before { content: "\f64c"; } -.bi-plus-lg::before { content: "\f64d"; } -.bi-question-lg::before { content: "\f64e"; } -.bi-recycle::before { content: "\f64f"; } -.bi-reddit::before { content: "\f650"; } -.bi-safe-fill::before { content: "\f651"; } -.bi-safe2-fill::before { content: "\f652"; } -.bi-safe2::before { content: "\f653"; } -.bi-sd-card-fill::before { content: "\f654"; } -.bi-sd-card::before { content: "\f655"; } -.bi-skype::before { content: "\f656"; } -.bi-slash-lg::before { content: "\f657"; } -.bi-translate::before { content: "\f658"; } -.bi-x-lg::before { content: "\f659"; } -.bi-safe::before { content: "\f65a"; } -.bi-apple::before { content: "\f65b"; } -.bi-microsoft::before { content: "\f65d"; } -.bi-windows::before { content: "\f65e"; } -.bi-behance::before { content: "\f65c"; } -.bi-dribbble::before { content: "\f65f"; } -.bi-line::before { content: "\f660"; } -.bi-medium::before { content: "\f661"; } -.bi-paypal::before { content: "\f662"; } -.bi-pinterest::before { content: "\f663"; } -.bi-signal::before { content: "\f664"; } -.bi-snapchat::before { content: "\f665"; } -.bi-spotify::before { content: "\f666"; } -.bi-stack-overflow::before { content: "\f667"; } -.bi-strava::before { content: "\f668"; } -.bi-wordpress::before { content: "\f669"; } -.bi-vimeo::before { content: "\f66a"; } -.bi-activity::before { content: "\f66b"; } -.bi-easel2-fill::before { content: "\f66c"; } -.bi-easel2::before { content: "\f66d"; } -.bi-easel3-fill::before { content: "\f66e"; } -.bi-easel3::before { content: "\f66f"; } -.bi-fan::before { content: "\f670"; } -.bi-fingerprint::before { content: "\f671"; } -.bi-graph-down-arrow::before { content: "\f672"; } -.bi-graph-up-arrow::before { content: "\f673"; } -.bi-hypnotize::before { content: "\f674"; } -.bi-magic::before { content: "\f675"; } -.bi-person-rolodex::before { content: "\f676"; } -.bi-person-video::before { content: "\f677"; } -.bi-person-video2::before { content: "\f678"; } -.bi-person-video3::before { content: "\f679"; } -.bi-person-workspace::before { content: "\f67a"; } -.bi-radioactive::before { content: "\f67b"; } -.bi-webcam-fill::before { content: "\f67c"; } -.bi-webcam::before { content: "\f67d"; } -.bi-yin-yang::before { content: "\f67e"; } -.bi-bandaid-fill::before { content: "\f680"; } -.bi-bandaid::before { content: "\f681"; } -.bi-bluetooth::before { content: "\f682"; } -.bi-body-text::before { content: "\f683"; } -.bi-boombox::before { content: "\f684"; } -.bi-boxes::before { content: "\f685"; } -.bi-dpad-fill::before { content: "\f686"; } -.bi-dpad::before { content: "\f687"; } -.bi-ear-fill::before { content: "\f688"; } -.bi-ear::before { content: "\f689"; } -.bi-envelope-check-fill::before { content: "\f68b"; } -.bi-envelope-check::before { content: "\f68c"; } -.bi-envelope-dash-fill::before { content: "\f68e"; } -.bi-envelope-dash::before { content: "\f68f"; } -.bi-envelope-exclamation-fill::before { content: "\f691"; } -.bi-envelope-exclamation::before { content: "\f692"; } -.bi-envelope-plus-fill::before { content: "\f693"; } -.bi-envelope-plus::before { content: "\f694"; } -.bi-envelope-slash-fill::before { content: "\f696"; } -.bi-envelope-slash::before { content: "\f697"; } -.bi-envelope-x-fill::before { content: "\f699"; } -.bi-envelope-x::before { content: "\f69a"; } -.bi-explicit-fill::before { content: "\f69b"; } -.bi-explicit::before { content: "\f69c"; } -.bi-git::before { content: "\f69d"; } -.bi-infinity::before { content: "\f69e"; } -.bi-list-columns-reverse::before { content: "\f69f"; } -.bi-list-columns::before { content: "\f6a0"; } -.bi-meta::before { content: "\f6a1"; } -.bi-nintendo-switch::before { content: "\f6a4"; } -.bi-pc-display-horizontal::before { content: "\f6a5"; } -.bi-pc-display::before { content: "\f6a6"; } -.bi-pc-horizontal::before { content: "\f6a7"; } -.bi-pc::before { content: "\f6a8"; } -.bi-playstation::before { content: "\f6a9"; } -.bi-plus-slash-minus::before { content: "\f6aa"; } -.bi-projector-fill::before { content: "\f6ab"; } -.bi-projector::before { content: "\f6ac"; } -.bi-qr-code-scan::before { content: "\f6ad"; } -.bi-qr-code::before { content: "\f6ae"; } -.bi-quora::before { content: "\f6af"; } -.bi-quote::before { content: "\f6b0"; } -.bi-robot::before { content: "\f6b1"; } -.bi-send-check-fill::before { content: "\f6b2"; } -.bi-send-check::before { content: "\f6b3"; } -.bi-send-dash-fill::before { content: "\f6b4"; } -.bi-send-dash::before { content: "\f6b5"; } -.bi-send-exclamation-fill::before { content: "\f6b7"; } -.bi-send-exclamation::before { content: "\f6b8"; } -.bi-send-fill::before { content: "\f6b9"; } -.bi-send-plus-fill::before { content: "\f6ba"; } -.bi-send-plus::before { content: "\f6bb"; } -.bi-send-slash-fill::before { content: "\f6bc"; } -.bi-send-slash::before { content: "\f6bd"; } -.bi-send-x-fill::before { content: "\f6be"; } -.bi-send-x::before { content: "\f6bf"; } -.bi-send::before { content: "\f6c0"; } -.bi-steam::before { content: "\f6c1"; } -.bi-terminal-dash::before { content: "\f6c3"; } -.bi-terminal-plus::before { content: "\f6c4"; } -.bi-terminal-split::before { content: "\f6c5"; } -.bi-ticket-detailed-fill::before { content: "\f6c6"; } -.bi-ticket-detailed::before { content: "\f6c7"; } -.bi-ticket-fill::before { content: "\f6c8"; } -.bi-ticket-perforated-fill::before { content: "\f6c9"; } -.bi-ticket-perforated::before { content: "\f6ca"; } -.bi-ticket::before { content: "\f6cb"; } -.bi-tiktok::before { content: "\f6cc"; } -.bi-window-dash::before { content: "\f6cd"; } -.bi-window-desktop::before { content: "\f6ce"; } -.bi-window-fullscreen::before { content: "\f6cf"; } -.bi-window-plus::before { content: "\f6d0"; } -.bi-window-split::before { content: "\f6d1"; } -.bi-window-stack::before { content: "\f6d2"; } -.bi-window-x::before { content: "\f6d3"; } -.bi-xbox::before { content: "\f6d4"; } -.bi-ethernet::before { content: "\f6d5"; } -.bi-hdmi-fill::before { content: "\f6d6"; } -.bi-hdmi::before { content: "\f6d7"; } -.bi-usb-c-fill::before { content: "\f6d8"; } -.bi-usb-c::before { content: "\f6d9"; } -.bi-usb-fill::before { content: "\f6da"; } -.bi-usb-plug-fill::before { content: "\f6db"; } -.bi-usb-plug::before { content: "\f6dc"; } -.bi-usb-symbol::before { content: "\f6dd"; } -.bi-usb::before { content: "\f6de"; } -.bi-boombox-fill::before { content: "\f6df"; } -.bi-displayport::before { content: "\f6e1"; } -.bi-gpu-card::before { content: "\f6e2"; } -.bi-memory::before { content: "\f6e3"; } -.bi-modem-fill::before { content: "\f6e4"; } -.bi-modem::before { content: "\f6e5"; } -.bi-motherboard-fill::before { content: "\f6e6"; } -.bi-motherboard::before { content: "\f6e7"; } -.bi-optical-audio-fill::before { content: "\f6e8"; } -.bi-optical-audio::before { content: "\f6e9"; } -.bi-pci-card::before { content: "\f6ea"; } -.bi-router-fill::before { content: "\f6eb"; } -.bi-router::before { content: "\f6ec"; } -.bi-thunderbolt-fill::before { content: "\f6ef"; } -.bi-thunderbolt::before { content: "\f6f0"; } -.bi-usb-drive-fill::before { content: "\f6f1"; } -.bi-usb-drive::before { content: "\f6f2"; } -.bi-usb-micro-fill::before { content: "\f6f3"; } -.bi-usb-micro::before { content: "\f6f4"; } -.bi-usb-mini-fill::before { content: "\f6f5"; } -.bi-usb-mini::before { content: "\f6f6"; } -.bi-cloud-haze2::before { content: "\f6f7"; } -.bi-device-hdd-fill::before { content: "\f6f8"; } -.bi-device-hdd::before { content: "\f6f9"; } -.bi-device-ssd-fill::before { content: "\f6fa"; } -.bi-device-ssd::before { content: "\f6fb"; } -.bi-displayport-fill::before { content: "\f6fc"; } -.bi-mortarboard-fill::before { content: "\f6fd"; } -.bi-mortarboard::before { content: "\f6fe"; } -.bi-terminal-x::before { content: "\f6ff"; } -.bi-arrow-through-heart-fill::before { content: "\f700"; } -.bi-arrow-through-heart::before { content: "\f701"; } -.bi-badge-sd-fill::before { content: "\f702"; } -.bi-badge-sd::before { content: "\f703"; } -.bi-bag-heart-fill::before { content: "\f704"; } -.bi-bag-heart::before { content: "\f705"; } -.bi-balloon-fill::before { content: "\f706"; } -.bi-balloon-heart-fill::before { content: "\f707"; } -.bi-balloon-heart::before { content: "\f708"; } -.bi-balloon::before { content: "\f709"; } -.bi-box2-fill::before { content: "\f70a"; } -.bi-box2-heart-fill::before { content: "\f70b"; } -.bi-box2-heart::before { content: "\f70c"; } -.bi-box2::before { content: "\f70d"; } -.bi-braces-asterisk::before { content: "\f70e"; } -.bi-calendar-heart-fill::before { content: "\f70f"; } -.bi-calendar-heart::before { content: "\f710"; } -.bi-calendar2-heart-fill::before { content: "\f711"; } -.bi-calendar2-heart::before { content: "\f712"; } -.bi-chat-heart-fill::before { content: "\f713"; } -.bi-chat-heart::before { content: "\f714"; } -.bi-chat-left-heart-fill::before { content: "\f715"; } -.bi-chat-left-heart::before { content: "\f716"; } -.bi-chat-right-heart-fill::before { content: "\f717"; } -.bi-chat-right-heart::before { content: "\f718"; } -.bi-chat-square-heart-fill::before { content: "\f719"; } -.bi-chat-square-heart::before { content: "\f71a"; } -.bi-clipboard-check-fill::before { content: "\f71b"; } -.bi-clipboard-data-fill::before { content: "\f71c"; } -.bi-clipboard-fill::before { content: "\f71d"; } -.bi-clipboard-heart-fill::before { content: "\f71e"; } -.bi-clipboard-heart::before { content: "\f71f"; } -.bi-clipboard-minus-fill::before { content: "\f720"; } -.bi-clipboard-plus-fill::before { content: "\f721"; } -.bi-clipboard-pulse::before { content: "\f722"; } -.bi-clipboard-x-fill::before { content: "\f723"; } -.bi-clipboard2-check-fill::before { content: "\f724"; } -.bi-clipboard2-check::before { content: "\f725"; } -.bi-clipboard2-data-fill::before { content: "\f726"; } -.bi-clipboard2-data::before { content: "\f727"; } -.bi-clipboard2-fill::before { content: "\f728"; } -.bi-clipboard2-heart-fill::before { content: "\f729"; } -.bi-clipboard2-heart::before { content: "\f72a"; } -.bi-clipboard2-minus-fill::before { content: "\f72b"; } -.bi-clipboard2-minus::before { content: "\f72c"; } -.bi-clipboard2-plus-fill::before { content: "\f72d"; } -.bi-clipboard2-plus::before { content: "\f72e"; } -.bi-clipboard2-pulse-fill::before { content: "\f72f"; } -.bi-clipboard2-pulse::before { content: "\f730"; } -.bi-clipboard2-x-fill::before { content: "\f731"; } -.bi-clipboard2-x::before { content: "\f732"; } -.bi-clipboard2::before { content: "\f733"; } -.bi-emoji-kiss-fill::before { content: "\f734"; } -.bi-emoji-kiss::before { content: "\f735"; } -.bi-envelope-heart-fill::before { content: "\f736"; } -.bi-envelope-heart::before { content: "\f737"; } -.bi-envelope-open-heart-fill::before { content: "\f738"; } -.bi-envelope-open-heart::before { content: "\f739"; } -.bi-envelope-paper-fill::before { content: "\f73a"; } -.bi-envelope-paper-heart-fill::before { content: "\f73b"; } -.bi-envelope-paper-heart::before { content: "\f73c"; } -.bi-envelope-paper::before { content: "\f73d"; } -.bi-filetype-aac::before { content: "\f73e"; } -.bi-filetype-ai::before { content: "\f73f"; } -.bi-filetype-bmp::before { content: "\f740"; } -.bi-filetype-cs::before { content: "\f741"; } -.bi-filetype-css::before { content: "\f742"; } -.bi-filetype-csv::before { content: "\f743"; } -.bi-filetype-doc::before { content: "\f744"; } -.bi-filetype-docx::before { content: "\f745"; } -.bi-filetype-exe::before { content: "\f746"; } -.bi-filetype-gif::before { content: "\f747"; } -.bi-filetype-heic::before { content: "\f748"; } -.bi-filetype-html::before { content: "\f749"; } -.bi-filetype-java::before { content: "\f74a"; } -.bi-filetype-jpg::before { content: "\f74b"; } -.bi-filetype-js::before { content: "\f74c"; } -.bi-filetype-jsx::before { content: "\f74d"; } -.bi-filetype-key::before { content: "\f74e"; } -.bi-filetype-m4p::before { content: "\f74f"; } -.bi-filetype-md::before { content: "\f750"; } -.bi-filetype-mdx::before { content: "\f751"; } -.bi-filetype-mov::before { content: "\f752"; } -.bi-filetype-mp3::before { content: "\f753"; } -.bi-filetype-mp4::before { content: "\f754"; } -.bi-filetype-otf::before { content: "\f755"; } -.bi-filetype-pdf::before { content: "\f756"; } -.bi-filetype-php::before { content: "\f757"; } -.bi-filetype-png::before { content: "\f758"; } -.bi-filetype-ppt::before { content: "\f75a"; } -.bi-filetype-psd::before { content: "\f75b"; } -.bi-filetype-py::before { content: "\f75c"; } -.bi-filetype-raw::before { content: "\f75d"; } -.bi-filetype-rb::before { content: "\f75e"; } -.bi-filetype-sass::before { content: "\f75f"; } -.bi-filetype-scss::before { content: "\f760"; } -.bi-filetype-sh::before { content: "\f761"; } -.bi-filetype-svg::before { content: "\f762"; } -.bi-filetype-tiff::before { content: "\f763"; } -.bi-filetype-tsx::before { content: "\f764"; } -.bi-filetype-ttf::before { content: "\f765"; } -.bi-filetype-txt::before { content: "\f766"; } -.bi-filetype-wav::before { content: "\f767"; } -.bi-filetype-woff::before { content: "\f768"; } -.bi-filetype-xls::before { content: "\f76a"; } -.bi-filetype-xml::before { content: "\f76b"; } -.bi-filetype-yml::before { content: "\f76c"; } -.bi-heart-arrow::before { content: "\f76d"; } -.bi-heart-pulse-fill::before { content: "\f76e"; } -.bi-heart-pulse::before { content: "\f76f"; } -.bi-heartbreak-fill::before { content: "\f770"; } -.bi-heartbreak::before { content: "\f771"; } -.bi-hearts::before { content: "\f772"; } -.bi-hospital-fill::before { content: "\f773"; } -.bi-hospital::before { content: "\f774"; } -.bi-house-heart-fill::before { content: "\f775"; } -.bi-house-heart::before { content: "\f776"; } -.bi-incognito::before { content: "\f777"; } -.bi-magnet-fill::before { content: "\f778"; } -.bi-magnet::before { content: "\f779"; } -.bi-person-heart::before { content: "\f77a"; } -.bi-person-hearts::before { content: "\f77b"; } -.bi-phone-flip::before { content: "\f77c"; } -.bi-plugin::before { content: "\f77d"; } -.bi-postage-fill::before { content: "\f77e"; } -.bi-postage-heart-fill::before { content: "\f77f"; } -.bi-postage-heart::before { content: "\f780"; } -.bi-postage::before { content: "\f781"; } -.bi-postcard-fill::before { content: "\f782"; } -.bi-postcard-heart-fill::before { content: "\f783"; } -.bi-postcard-heart::before { content: "\f784"; } -.bi-postcard::before { content: "\f785"; } -.bi-search-heart-fill::before { content: "\f786"; } -.bi-search-heart::before { content: "\f787"; } -.bi-sliders2-vertical::before { content: "\f788"; } -.bi-sliders2::before { content: "\f789"; } -.bi-trash3-fill::before { content: "\f78a"; } -.bi-trash3::before { content: "\f78b"; } -.bi-valentine::before { content: "\f78c"; } -.bi-valentine2::before { content: "\f78d"; } -.bi-wrench-adjustable-circle-fill::before { content: "\f78e"; } -.bi-wrench-adjustable-circle::before { content: "\f78f"; } -.bi-wrench-adjustable::before { content: "\f790"; } -.bi-filetype-json::before { content: "\f791"; } -.bi-filetype-pptx::before { content: "\f792"; } -.bi-filetype-xlsx::before { content: "\f793"; } -.bi-1-circle-fill::before { content: "\f796"; } -.bi-1-circle::before { content: "\f797"; } -.bi-1-square-fill::before { content: "\f798"; } -.bi-1-square::before { content: "\f799"; } -.bi-2-circle-fill::before { content: "\f79c"; } -.bi-2-circle::before { content: "\f79d"; } -.bi-2-square-fill::before { content: "\f79e"; } -.bi-2-square::before { content: "\f79f"; } -.bi-3-circle-fill::before { content: "\f7a2"; } -.bi-3-circle::before { content: "\f7a3"; } -.bi-3-square-fill::before { content: "\f7a4"; } -.bi-3-square::before { content: "\f7a5"; } -.bi-4-circle-fill::before { content: "\f7a8"; } -.bi-4-circle::before { content: "\f7a9"; } -.bi-4-square-fill::before { content: "\f7aa"; } -.bi-4-square::before { content: "\f7ab"; } -.bi-5-circle-fill::before { content: "\f7ae"; } -.bi-5-circle::before { content: "\f7af"; } -.bi-5-square-fill::before { content: "\f7b0"; } -.bi-5-square::before { content: "\f7b1"; } -.bi-6-circle-fill::before { content: "\f7b4"; } -.bi-6-circle::before { content: "\f7b5"; } -.bi-6-square-fill::before { content: "\f7b6"; } -.bi-6-square::before { content: "\f7b7"; } -.bi-7-circle-fill::before { content: "\f7ba"; } -.bi-7-circle::before { content: "\f7bb"; } -.bi-7-square-fill::before { content: "\f7bc"; } -.bi-7-square::before { content: "\f7bd"; } -.bi-8-circle-fill::before { content: "\f7c0"; } -.bi-8-circle::before { content: "\f7c1"; } -.bi-8-square-fill::before { content: "\f7c2"; } -.bi-8-square::before { content: "\f7c3"; } -.bi-9-circle-fill::before { content: "\f7c6"; } -.bi-9-circle::before { content: "\f7c7"; } -.bi-9-square-fill::before { content: "\f7c8"; } -.bi-9-square::before { content: "\f7c9"; } -.bi-airplane-engines-fill::before { content: "\f7ca"; } -.bi-airplane-engines::before { content: "\f7cb"; } -.bi-airplane-fill::before { content: "\f7cc"; } -.bi-airplane::before { content: "\f7cd"; } -.bi-alexa::before { content: "\f7ce"; } -.bi-alipay::before { content: "\f7cf"; } -.bi-android::before { content: "\f7d0"; } -.bi-android2::before { content: "\f7d1"; } -.bi-box-fill::before { content: "\f7d2"; } -.bi-box-seam-fill::before { content: "\f7d3"; } -.bi-browser-chrome::before { content: "\f7d4"; } -.bi-browser-edge::before { content: "\f7d5"; } -.bi-browser-firefox::before { content: "\f7d6"; } -.bi-browser-safari::before { content: "\f7d7"; } -.bi-c-circle-fill::before { content: "\f7da"; } -.bi-c-circle::before { content: "\f7db"; } -.bi-c-square-fill::before { content: "\f7dc"; } -.bi-c-square::before { content: "\f7dd"; } -.bi-capsule-pill::before { content: "\f7de"; } -.bi-capsule::before { content: "\f7df"; } -.bi-car-front-fill::before { content: "\f7e0"; } -.bi-car-front::before { content: "\f7e1"; } -.bi-cassette-fill::before { content: "\f7e2"; } -.bi-cassette::before { content: "\f7e3"; } -.bi-cc-circle-fill::before { content: "\f7e6"; } -.bi-cc-circle::before { content: "\f7e7"; } -.bi-cc-square-fill::before { content: "\f7e8"; } -.bi-cc-square::before { content: "\f7e9"; } -.bi-cup-hot-fill::before { content: "\f7ea"; } -.bi-cup-hot::before { content: "\f7eb"; } -.bi-currency-rupee::before { content: "\f7ec"; } -.bi-dropbox::before { content: "\f7ed"; } -.bi-escape::before { content: "\f7ee"; } -.bi-fast-forward-btn-fill::before { content: "\f7ef"; } -.bi-fast-forward-btn::before { content: "\f7f0"; } -.bi-fast-forward-circle-fill::before { content: "\f7f1"; } -.bi-fast-forward-circle::before { content: "\f7f2"; } -.bi-fast-forward-fill::before { content: "\f7f3"; } -.bi-fast-forward::before { content: "\f7f4"; } -.bi-filetype-sql::before { content: "\f7f5"; } -.bi-fire::before { content: "\f7f6"; } -.bi-google-play::before { content: "\f7f7"; } -.bi-h-circle-fill::before { content: "\f7fa"; } -.bi-h-circle::before { content: "\f7fb"; } -.bi-h-square-fill::before { content: "\f7fc"; } -.bi-h-square::before { content: "\f7fd"; } -.bi-indent::before { content: "\f7fe"; } -.bi-lungs-fill::before { content: "\f7ff"; } -.bi-lungs::before { content: "\f800"; } -.bi-microsoft-teams::before { content: "\f801"; } -.bi-p-circle-fill::before { content: "\f804"; } -.bi-p-circle::before { content: "\f805"; } -.bi-p-square-fill::before { content: "\f806"; } -.bi-p-square::before { content: "\f807"; } -.bi-pass-fill::before { content: "\f808"; } -.bi-pass::before { content: "\f809"; } -.bi-prescription::before { content: "\f80a"; } -.bi-prescription2::before { content: "\f80b"; } -.bi-r-circle-fill::before { content: "\f80e"; } -.bi-r-circle::before { content: "\f80f"; } -.bi-r-square-fill::before { content: "\f810"; } -.bi-r-square::before { content: "\f811"; } -.bi-repeat-1::before { content: "\f812"; } -.bi-repeat::before { content: "\f813"; } -.bi-rewind-btn-fill::before { content: "\f814"; } -.bi-rewind-btn::before { content: "\f815"; } -.bi-rewind-circle-fill::before { content: "\f816"; } -.bi-rewind-circle::before { content: "\f817"; } -.bi-rewind-fill::before { content: "\f818"; } -.bi-rewind::before { content: "\f819"; } -.bi-train-freight-front-fill::before { content: "\f81a"; } -.bi-train-freight-front::before { content: "\f81b"; } -.bi-train-front-fill::before { content: "\f81c"; } -.bi-train-front::before { content: "\f81d"; } -.bi-train-lightrail-front-fill::before { content: "\f81e"; } -.bi-train-lightrail-front::before { content: "\f81f"; } -.bi-truck-front-fill::before { content: "\f820"; } -.bi-truck-front::before { content: "\f821"; } -.bi-ubuntu::before { content: "\f822"; } -.bi-unindent::before { content: "\f823"; } -.bi-unity::before { content: "\f824"; } -.bi-universal-access-circle::before { content: "\f825"; } -.bi-universal-access::before { content: "\f826"; } -.bi-virus::before { content: "\f827"; } -.bi-virus2::before { content: "\f828"; } -.bi-wechat::before { content: "\f829"; } -.bi-yelp::before { content: "\f82a"; } -.bi-sign-stop-fill::before { content: "\f82b"; } -.bi-sign-stop-lights-fill::before { content: "\f82c"; } -.bi-sign-stop-lights::before { content: "\f82d"; } -.bi-sign-stop::before { content: "\f82e"; } -.bi-sign-turn-left-fill::before { content: "\f82f"; } -.bi-sign-turn-left::before { content: "\f830"; } -.bi-sign-turn-right-fill::before { content: "\f831"; } -.bi-sign-turn-right::before { content: "\f832"; } -.bi-sign-turn-slight-left-fill::before { content: "\f833"; } -.bi-sign-turn-slight-left::before { content: "\f834"; } -.bi-sign-turn-slight-right-fill::before { content: "\f835"; } -.bi-sign-turn-slight-right::before { content: "\f836"; } -.bi-sign-yield-fill::before { content: "\f837"; } -.bi-sign-yield::before { content: "\f838"; } -.bi-ev-station-fill::before { content: "\f839"; } -.bi-ev-station::before { content: "\f83a"; } -.bi-fuel-pump-diesel-fill::before { content: "\f83b"; } -.bi-fuel-pump-diesel::before { content: "\f83c"; } -.bi-fuel-pump-fill::before { content: "\f83d"; } -.bi-fuel-pump::before { content: "\f83e"; } -.bi-0-circle-fill::before { content: "\f83f"; } -.bi-0-circle::before { content: "\f840"; } -.bi-0-square-fill::before { content: "\f841"; } -.bi-0-square::before { content: "\f842"; } -.bi-rocket-fill::before { content: "\f843"; } -.bi-rocket-takeoff-fill::before { content: "\f844"; } -.bi-rocket-takeoff::before { content: "\f845"; } -.bi-rocket::before { content: "\f846"; } -.bi-stripe::before { content: "\f847"; } -.bi-subscript::before { content: "\f848"; } -.bi-superscript::before { content: "\f849"; } -.bi-trello::before { content: "\f84a"; } -.bi-envelope-at-fill::before { content: "\f84b"; } -.bi-envelope-at::before { content: "\f84c"; } -.bi-regex::before { content: "\f84d"; } -.bi-text-wrap::before { content: "\f84e"; } -.bi-sign-dead-end-fill::before { content: "\f84f"; } -.bi-sign-dead-end::before { content: "\f850"; } -.bi-sign-do-not-enter-fill::before { content: "\f851"; } -.bi-sign-do-not-enter::before { content: "\f852"; } -.bi-sign-intersection-fill::before { content: "\f853"; } -.bi-sign-intersection-side-fill::before { content: "\f854"; } -.bi-sign-intersection-side::before { content: "\f855"; } -.bi-sign-intersection-t-fill::before { content: "\f856"; } -.bi-sign-intersection-t::before { content: "\f857"; } -.bi-sign-intersection-y-fill::before { content: "\f858"; } -.bi-sign-intersection-y::before { content: "\f859"; } -.bi-sign-intersection::before { content: "\f85a"; } -.bi-sign-merge-left-fill::before { content: "\f85b"; } -.bi-sign-merge-left::before { content: "\f85c"; } -.bi-sign-merge-right-fill::before { content: "\f85d"; } -.bi-sign-merge-right::before { content: "\f85e"; } -.bi-sign-no-left-turn-fill::before { content: "\f85f"; } -.bi-sign-no-left-turn::before { content: "\f860"; } -.bi-sign-no-parking-fill::before { content: "\f861"; } -.bi-sign-no-parking::before { content: "\f862"; } -.bi-sign-no-right-turn-fill::before { content: "\f863"; } -.bi-sign-no-right-turn::before { content: "\f864"; } -.bi-sign-railroad-fill::before { content: "\f865"; } -.bi-sign-railroad::before { content: "\f866"; } -.bi-building-add::before { content: "\f867"; } -.bi-building-check::before { content: "\f868"; } -.bi-building-dash::before { content: "\f869"; } -.bi-building-down::before { content: "\f86a"; } -.bi-building-exclamation::before { content: "\f86b"; } -.bi-building-fill-add::before { content: "\f86c"; } -.bi-building-fill-check::before { content: "\f86d"; } -.bi-building-fill-dash::before { content: "\f86e"; } -.bi-building-fill-down::before { content: "\f86f"; } -.bi-building-fill-exclamation::before { content: "\f870"; } -.bi-building-fill-gear::before { content: "\f871"; } -.bi-building-fill-lock::before { content: "\f872"; } -.bi-building-fill-slash::before { content: "\f873"; } -.bi-building-fill-up::before { content: "\f874"; } -.bi-building-fill-x::before { content: "\f875"; } -.bi-building-fill::before { content: "\f876"; } -.bi-building-gear::before { content: "\f877"; } -.bi-building-lock::before { content: "\f878"; } -.bi-building-slash::before { content: "\f879"; } -.bi-building-up::before { content: "\f87a"; } -.bi-building-x::before { content: "\f87b"; } -.bi-buildings-fill::before { content: "\f87c"; } -.bi-buildings::before { content: "\f87d"; } -.bi-bus-front-fill::before { content: "\f87e"; } -.bi-bus-front::before { content: "\f87f"; } -.bi-ev-front-fill::before { content: "\f880"; } -.bi-ev-front::before { content: "\f881"; } -.bi-globe-americas::before { content: "\f882"; } -.bi-globe-asia-australia::before { content: "\f883"; } -.bi-globe-central-south-asia::before { content: "\f884"; } -.bi-globe-europe-africa::before { content: "\f885"; } -.bi-house-add-fill::before { content: "\f886"; } -.bi-house-add::before { content: "\f887"; } -.bi-house-check-fill::before { content: "\f888"; } -.bi-house-check::before { content: "\f889"; } -.bi-house-dash-fill::before { content: "\f88a"; } -.bi-house-dash::before { content: "\f88b"; } -.bi-house-down-fill::before { content: "\f88c"; } -.bi-house-down::before { content: "\f88d"; } -.bi-house-exclamation-fill::before { content: "\f88e"; } -.bi-house-exclamation::before { content: "\f88f"; } -.bi-house-gear-fill::before { content: "\f890"; } -.bi-house-gear::before { content: "\f891"; } -.bi-house-lock-fill::before { content: "\f892"; } -.bi-house-lock::before { content: "\f893"; } -.bi-house-slash-fill::before { content: "\f894"; } -.bi-house-slash::before { content: "\f895"; } -.bi-house-up-fill::before { content: "\f896"; } -.bi-house-up::before { content: "\f897"; } -.bi-house-x-fill::before { content: "\f898"; } -.bi-house-x::before { content: "\f899"; } -.bi-person-add::before { content: "\f89a"; } -.bi-person-down::before { content: "\f89b"; } -.bi-person-exclamation::before { content: "\f89c"; } -.bi-person-fill-add::before { content: "\f89d"; } -.bi-person-fill-check::before { content: "\f89e"; } -.bi-person-fill-dash::before { content: "\f89f"; } -.bi-person-fill-down::before { content: "\f8a0"; } -.bi-person-fill-exclamation::before { content: "\f8a1"; } -.bi-person-fill-gear::before { content: "\f8a2"; } -.bi-person-fill-lock::before { content: "\f8a3"; } -.bi-person-fill-slash::before { content: "\f8a4"; } -.bi-person-fill-up::before { content: "\f8a5"; } -.bi-person-fill-x::before { content: "\f8a6"; } -.bi-person-gear::before { content: "\f8a7"; } -.bi-person-lock::before { content: "\f8a8"; } -.bi-person-slash::before { content: "\f8a9"; } -.bi-person-up::before { content: "\f8aa"; } -.bi-scooter::before { content: "\f8ab"; } -.bi-taxi-front-fill::before { content: "\f8ac"; } -.bi-taxi-front::before { content: "\f8ad"; } -.bi-amd::before { content: "\f8ae"; } -.bi-database-add::before { content: "\f8af"; } -.bi-database-check::before { content: "\f8b0"; } -.bi-database-dash::before { content: "\f8b1"; } -.bi-database-down::before { content: "\f8b2"; } -.bi-database-exclamation::before { content: "\f8b3"; } -.bi-database-fill-add::before { content: "\f8b4"; } -.bi-database-fill-check::before { content: "\f8b5"; } -.bi-database-fill-dash::before { content: "\f8b6"; } -.bi-database-fill-down::before { content: "\f8b7"; } -.bi-database-fill-exclamation::before { content: "\f8b8"; } -.bi-database-fill-gear::before { content: "\f8b9"; } -.bi-database-fill-lock::before { content: "\f8ba"; } -.bi-database-fill-slash::before { content: "\f8bb"; } -.bi-database-fill-up::before { content: "\f8bc"; } -.bi-database-fill-x::before { content: "\f8bd"; } -.bi-database-fill::before { content: "\f8be"; } -.bi-database-gear::before { content: "\f8bf"; } -.bi-database-lock::before { content: "\f8c0"; } -.bi-database-slash::before { content: "\f8c1"; } -.bi-database-up::before { content: "\f8c2"; } -.bi-database-x::before { content: "\f8c3"; } -.bi-database::before { content: "\f8c4"; } -.bi-houses-fill::before { content: "\f8c5"; } -.bi-houses::before { content: "\f8c6"; } -.bi-nvidia::before { content: "\f8c7"; } -.bi-person-vcard-fill::before { content: "\f8c8"; } -.bi-person-vcard::before { content: "\f8c9"; } -.bi-sina-weibo::before { content: "\f8ca"; } -.bi-tencent-qq::before { content: "\f8cb"; } -.bi-wikipedia::before { content: "\f8cc"; } -.bi-alphabet-uppercase::before { content: "\f2a5"; } -.bi-alphabet::before { content: "\f68a"; } -.bi-amazon::before { content: "\f68d"; } -.bi-arrows-collapse-vertical::before { content: "\f690"; } -.bi-arrows-expand-vertical::before { content: "\f695"; } -.bi-arrows-vertical::before { content: "\f698"; } -.bi-arrows::before { content: "\f6a2"; } -.bi-ban-fill::before { content: "\f6a3"; } -.bi-ban::before { content: "\f6b6"; } -.bi-bing::before { content: "\f6c2"; } -.bi-cake::before { content: "\f6e0"; } -.bi-cake2::before { content: "\f6ed"; } -.bi-cookie::before { content: "\f6ee"; } -.bi-copy::before { content: "\f759"; } -.bi-crosshair::before { content: "\f769"; } -.bi-crosshair2::before { content: "\f794"; } -.bi-emoji-astonished-fill::before { content: "\f795"; } -.bi-emoji-astonished::before { content: "\f79a"; } -.bi-emoji-grimace-fill::before { content: "\f79b"; } -.bi-emoji-grimace::before { content: "\f7a0"; } -.bi-emoji-grin-fill::before { content: "\f7a1"; } -.bi-emoji-grin::before { content: "\f7a6"; } -.bi-emoji-surprise-fill::before { content: "\f7a7"; } -.bi-emoji-surprise::before { content: "\f7ac"; } -.bi-emoji-tear-fill::before { content: "\f7ad"; } -.bi-emoji-tear::before { content: "\f7b2"; } -.bi-envelope-arrow-down-fill::before { content: "\f7b3"; } -.bi-envelope-arrow-down::before { content: "\f7b8"; } -.bi-envelope-arrow-up-fill::before { content: "\f7b9"; } -.bi-envelope-arrow-up::before { content: "\f7be"; } -.bi-feather::before { content: "\f7bf"; } -.bi-feather2::before { content: "\f7c4"; } -.bi-floppy-fill::before { content: "\f7c5"; } -.bi-floppy::before { content: "\f7d8"; } -.bi-floppy2-fill::before { content: "\f7d9"; } -.bi-floppy2::before { content: "\f7e4"; } -.bi-gitlab::before { content: "\f7e5"; } -.bi-highlighter::before { content: "\f7f8"; } -.bi-marker-tip::before { content: "\f802"; } -.bi-nvme-fill::before { content: "\f803"; } -.bi-nvme::before { content: "\f80c"; } -.bi-opencollective::before { content: "\f80d"; } -.bi-pci-card-network::before { content: "\f8cd"; } -.bi-pci-card-sound::before { content: "\f8ce"; } -.bi-radar::before { content: "\f8cf"; } -.bi-send-arrow-down-fill::before { content: "\f8d0"; } -.bi-send-arrow-down::before { content: "\f8d1"; } -.bi-send-arrow-up-fill::before { content: "\f8d2"; } -.bi-send-arrow-up::before { content: "\f8d3"; } -.bi-sim-slash-fill::before { content: "\f8d4"; } -.bi-sim-slash::before { content: "\f8d5"; } -.bi-sourceforge::before { content: "\f8d6"; } -.bi-substack::before { content: "\f8d7"; } -.bi-threads-fill::before { content: "\f8d8"; } -.bi-threads::before { content: "\f8d9"; } -.bi-transparency::before { content: "\f8da"; } -.bi-twitter-x::before { content: "\f8db"; } -.bi-type-h4::before { content: "\f8dc"; } -.bi-type-h5::before { content: "\f8dd"; } -.bi-type-h6::before { content: "\f8de"; } -.bi-backpack-fill::before { content: "\f8df"; } -.bi-backpack::before { content: "\f8e0"; } -.bi-backpack2-fill::before { content: "\f8e1"; } -.bi-backpack2::before { content: "\f8e2"; } -.bi-backpack3-fill::before { content: "\f8e3"; } -.bi-backpack3::before { content: "\f8e4"; } -.bi-backpack4-fill::before { content: "\f8e5"; } -.bi-backpack4::before { content: "\f8e6"; } -.bi-brilliance::before { content: "\f8e7"; } -.bi-cake-fill::before { content: "\f8e8"; } -.bi-cake2-fill::before { content: "\f8e9"; } -.bi-duffle-fill::before { content: "\f8ea"; } -.bi-duffle::before { content: "\f8eb"; } -.bi-exposure::before { content: "\f8ec"; } -.bi-gender-neuter::before { content: "\f8ed"; } -.bi-highlights::before { content: "\f8ee"; } -.bi-luggage-fill::before { content: "\f8ef"; } -.bi-luggage::before { content: "\f8f0"; } -.bi-mailbox-flag::before { content: "\f8f1"; } -.bi-mailbox2-flag::before { content: "\f8f2"; } -.bi-noise-reduction::before { content: "\f8f3"; } -.bi-passport-fill::before { content: "\f8f4"; } -.bi-passport::before { content: "\f8f5"; } -.bi-person-arms-up::before { content: "\f8f6"; } -.bi-person-raised-hand::before { content: "\f8f7"; } -.bi-person-standing-dress::before { content: "\f8f8"; } -.bi-person-standing::before { content: "\f8f9"; } -.bi-person-walking::before { content: "\f8fa"; } -.bi-person-wheelchair::before { content: "\f8fb"; } -.bi-shadows::before { content: "\f8fc"; } -.bi-suitcase-fill::before { content: "\f8fd"; } -.bi-suitcase-lg-fill::before { content: "\f8fe"; } -.bi-suitcase-lg::before { content: "\f8ff"; } -.bi-suitcase::before { content: "\f900"; } -.bi-suitcase2-fill::before { content: "\f901"; } -.bi-suitcase2::before { content: "\f902"; } -.bi-vignette::before { content: "\f903"; } diff --git a/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/uncertainty_files/libs/bootstrap/bootstrap-icons.woff b/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/uncertainty_files/libs/bootstrap/bootstrap-icons.woff deleted file mode 100644 index dbeeb0556..000000000 Binary files a/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/uncertainty_files/libs/bootstrap/bootstrap-icons.woff and /dev/null differ diff --git a/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/uncertainty_files/libs/bootstrap/bootstrap.min.css b/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/uncertainty_files/libs/bootstrap/bootstrap.min.css deleted file mode 100644 index d6947f2ce..000000000 --- a/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/uncertainty_files/libs/bootstrap/bootstrap.min.css +++ /dev/null @@ -1,12 +0,0 @@ -/*! - * Bootstrap v5.3.1 (https://getbootstrap.com/) - * Copyright 2011-2023 The Bootstrap Authors - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) - */:root,[data-bs-theme=light]{--bs-blue: #0d6efd;--bs-indigo: #6610f2;--bs-purple: #6f42c1;--bs-pink: #d63384;--bs-red: #dc3545;--bs-orange: #fd7e14;--bs-yellow: #ffc107;--bs-green: #198754;--bs-teal: #20c997;--bs-cyan: #0dcaf0;--bs-black: #000;--bs-white: #ffffff;--bs-gray: #6c757d;--bs-gray-dark: #343a40;--bs-gray-100: #f8f9fa;--bs-gray-200: #e9ecef;--bs-gray-300: #dee2e6;--bs-gray-400: #ced4da;--bs-gray-500: #adb5bd;--bs-gray-600: #6c757d;--bs-gray-700: #495057;--bs-gray-800: #343a40;--bs-gray-900: #212529;--bs-default: #dee2e6;--bs-primary: #0d6efd;--bs-secondary: #6c757d;--bs-success: #198754;--bs-info: #0dcaf0;--bs-warning: #ffc107;--bs-danger: #dc3545;--bs-light: #f8f9fa;--bs-dark: #212529;--bs-default-rgb: 222, 226, 230;--bs-primary-rgb: 13, 110, 253;--bs-secondary-rgb: 108, 117, 125;--bs-success-rgb: 25, 135, 84;--bs-info-rgb: 13, 202, 240;--bs-warning-rgb: 255, 193, 7;--bs-danger-rgb: 220, 53, 69;--bs-light-rgb: 248, 249, 250;--bs-dark-rgb: 33, 37, 41;--bs-primary-text-emphasis: #052c65;--bs-secondary-text-emphasis: #2b2f32;--bs-success-text-emphasis: #0a3622;--bs-info-text-emphasis: #055160;--bs-warning-text-emphasis: #664d03;--bs-danger-text-emphasis: #58151c;--bs-light-text-emphasis: #495057;--bs-dark-text-emphasis: #495057;--bs-primary-bg-subtle: #cfe2ff;--bs-secondary-bg-subtle: #e2e3e5;--bs-success-bg-subtle: #d1e7dd;--bs-info-bg-subtle: #cff4fc;--bs-warning-bg-subtle: #fff3cd;--bs-danger-bg-subtle: #f8d7da;--bs-light-bg-subtle: #fcfcfd;--bs-dark-bg-subtle: #ced4da;--bs-primary-border-subtle: #9ec5fe;--bs-secondary-border-subtle: #c4c8cb;--bs-success-border-subtle: #a3cfbb;--bs-info-border-subtle: #9eeaf9;--bs-warning-border-subtle: #ffe69c;--bs-danger-border-subtle: #f1aeb5;--bs-light-border-subtle: #e9ecef;--bs-dark-border-subtle: #adb5bd;--bs-white-rgb: 255, 255, 255;--bs-black-rgb: 0, 0, 0;--bs-font-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));--bs-root-font-size: 17px;--bs-body-font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--bs-body-font-size:1rem;--bs-body-font-weight: 400;--bs-body-line-height: 1.5;--bs-body-color: #212529;--bs-body-color-rgb: 33, 37, 41;--bs-body-bg: #ffffff;--bs-body-bg-rgb: 255, 255, 255;--bs-emphasis-color: #000;--bs-emphasis-color-rgb: 0, 0, 0;--bs-secondary-color: rgba(33, 37, 41, 0.75);--bs-secondary-color-rgb: 33, 37, 41;--bs-secondary-bg: #e9ecef;--bs-secondary-bg-rgb: 233, 236, 239;--bs-tertiary-color: rgba(33, 37, 41, 0.5);--bs-tertiary-color-rgb: 33, 37, 41;--bs-tertiary-bg: #f8f9fa;--bs-tertiary-bg-rgb: 248, 249, 250;--bs-heading-color: inherit;--bs-link-color: #0d6efd;--bs-link-color-rgb: 13, 110, 253;--bs-link-decoration: underline;--bs-link-hover-color: #0a58ca;--bs-link-hover-color-rgb: 10, 88, 202;--bs-code-color: #7d12ba;--bs-highlight-bg: #fff3cd;--bs-border-width: 1px;--bs-border-style: solid;--bs-border-color: #dee2e6;--bs-border-color-translucent: rgba(0, 0, 0, 0.175);--bs-border-radius: 0.375rem;--bs-border-radius-sm: 0.25rem;--bs-border-radius-lg: 0.5rem;--bs-border-radius-xl: 1rem;--bs-border-radius-xxl: 2rem;--bs-border-radius-2xl: var(--bs-border-radius-xxl);--bs-border-radius-pill: 50rem;--bs-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);--bs-box-shadow-sm: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);--bs-box-shadow-lg: 0 1rem 3rem rgba(0, 0, 0, 0.175);--bs-box-shadow-inset: inset 0 1px 2px rgba(0, 0, 0, 0.075);--bs-focus-ring-width: 0.25rem;--bs-focus-ring-opacity: 0.25;--bs-focus-ring-color: rgba(13, 110, 253, 0.25);--bs-form-valid-color: #198754;--bs-form-valid-border-color: #198754;--bs-form-invalid-color: #dc3545;--bs-form-invalid-border-color: #dc3545}[data-bs-theme=dark]{color-scheme:dark;--bs-body-color: #dee2e6;--bs-body-color-rgb: 222, 226, 230;--bs-body-bg: #212529;--bs-body-bg-rgb: 33, 37, 41;--bs-emphasis-color: #ffffff;--bs-emphasis-color-rgb: 255, 255, 255;--bs-secondary-color: rgba(222, 226, 230, 0.75);--bs-secondary-color-rgb: 222, 226, 230;--bs-secondary-bg: #343a40;--bs-secondary-bg-rgb: 52, 58, 64;--bs-tertiary-color: rgba(222, 226, 230, 0.5);--bs-tertiary-color-rgb: 222, 226, 230;--bs-tertiary-bg: #2b3035;--bs-tertiary-bg-rgb: 43, 48, 53;--bs-primary-text-emphasis: #6ea8fe;--bs-secondary-text-emphasis: #a7acb1;--bs-success-text-emphasis: #75b798;--bs-info-text-emphasis: #6edff6;--bs-warning-text-emphasis: #ffda6a;--bs-danger-text-emphasis: #ea868f;--bs-light-text-emphasis: #f8f9fa;--bs-dark-text-emphasis: #dee2e6;--bs-primary-bg-subtle: #031633;--bs-secondary-bg-subtle: #161719;--bs-success-bg-subtle: #051b11;--bs-info-bg-subtle: #032830;--bs-warning-bg-subtle: #332701;--bs-danger-bg-subtle: #2c0b0e;--bs-light-bg-subtle: #343a40;--bs-dark-bg-subtle: #1a1d20;--bs-primary-border-subtle: #084298;--bs-secondary-border-subtle: #41464b;--bs-success-border-subtle: #0f5132;--bs-info-border-subtle: #087990;--bs-warning-border-subtle: #997404;--bs-danger-border-subtle: #842029;--bs-light-border-subtle: #495057;--bs-dark-border-subtle: #343a40;--bs-heading-color: inherit;--bs-link-color: #6ea8fe;--bs-link-hover-color: #8bb9fe;--bs-link-color-rgb: 110, 168, 254;--bs-link-hover-color-rgb: 139, 185, 254;--bs-code-color: white;--bs-border-color: #495057;--bs-border-color-translucent: rgba(255, 255, 255, 0.15);--bs-form-valid-color: #75b798;--bs-form-valid-border-color: #75b798;--bs-form-invalid-color: #ea868f;--bs-form-invalid-border-color: #ea868f}*,*::before,*::after{box-sizing:border-box}:root{font-size:var(--bs-root-font-size)}body{margin:0;font-family:var(--bs-body-font-family);font-size:var(--bs-body-font-size);font-weight:var(--bs-body-font-weight);line-height:var(--bs-body-line-height);color:var(--bs-body-color);text-align:var(--bs-body-text-align);background-color:var(--bs-body-bg);-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:rgba(0,0,0,0)}hr{margin:1rem 0;color:inherit;border:0;border-top:1px solid;opacity:.25}h6,.h6,h5,.h5,h4,.h4,h3,.h3,h2,.h2,h1,.h1{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2;color:var(--bs-heading-color)}h1,.h1{font-size:calc(1.325rem + 0.9vw)}@media(min-width: 1200px){h1,.h1{font-size:2rem}}h2,.h2{font-size:calc(1.29rem + 0.48vw)}@media(min-width: 1200px){h2,.h2{font-size:1.65rem}}h3,.h3{font-size:calc(1.27rem + 0.24vw)}@media(min-width: 1200px){h3,.h3{font-size:1.45rem}}h4,.h4{font-size:1.25rem}h5,.h5{font-size:1.1rem}h6,.h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[title]{text-decoration:underline dotted;-webkit-text-decoration:underline dotted;-moz-text-decoration:underline dotted;-ms-text-decoration:underline dotted;-o-text-decoration:underline dotted;cursor:help;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}ol,ul,dl{margin-top:0;margin-bottom:1rem}ol ol,ul ul,ol ul,ul ol{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem;padding:.625rem 1.25rem;border-left:.25rem solid #e9ecef}blockquote p:last-child,blockquote ul:last-child,blockquote ol:last-child{margin-bottom:0}b,strong{font-weight:bolder}small,.small{font-size:0.875em}mark,.mark{padding:.1875em;background-color:var(--bs-highlight-bg)}sub,sup{position:relative;font-size:0.75em;line-height:0;vertical-align:baseline}sub{bottom:-0.25em}sup{top:-0.5em}a{color:rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 1));text-decoration:underline;-webkit-text-decoration:underline;-moz-text-decoration:underline;-ms-text-decoration:underline;-o-text-decoration:underline}a:hover{--bs-link-color-rgb: var(--bs-link-hover-color-rgb)}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}pre,code,kbd,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:0.875em;color:#000;background-color:#f8f9fa;padding:.5rem;border:1px solid var(--bs-border-color, #dee2e6);border-radius:.375rem}pre code{background-color:rgba(0,0,0,0);font-size:inherit;color:inherit;word-break:normal}code{font-size:0.875em;color:var(--bs-code-color);background-color:#f8f9fa;border-radius:.375rem;padding:.125rem .25rem;word-wrap:break-word}a>code{color:inherit}kbd{padding:.4rem .4rem;font-size:0.875em;color:#fff;background-color:#212529;border-radius:.25rem}kbd kbd{padding:0;font-size:1em}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:rgba(33,37,41,.75);text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}thead,tbody,tfoot,tr,td,th{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}input,button,select,optgroup,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]:not([type=date]):not([type=datetime-local]):not([type=month]):not([type=week]):not([type=time])::-webkit-calendar-picker-indicator{display:none !important}button,[type=button],[type=reset],[type=submit]{-webkit-appearance:button}button:not(:disabled),[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:left;width:100%;padding:0;margin-bottom:.5rem;font-size:calc(1.275rem + 0.3vw);line-height:inherit}@media(min-width: 1200px){legend{font-size:1.5rem}}legend+*{clear:left}::-webkit-datetime-edit-fields-wrapper,::-webkit-datetime-edit-text,::-webkit-datetime-edit-minute,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-year-field{padding:0}::-webkit-inner-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::file-selector-button{font:inherit;-webkit-appearance:button}output{display:inline-block}iframe{border:0}summary{display:list-item;cursor:pointer}progress{vertical-align:baseline}[hidden]{display:none !important}.lead{font-size:1.25rem;font-weight:300}.display-1{font-size:calc(1.625rem + 4.5vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-1{font-size:5rem}}.display-2{font-size:calc(1.575rem + 3.9vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-2{font-size:4.5rem}}.display-3{font-size:calc(1.525rem + 3.3vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-3{font-size:4rem}}.display-4{font-size:calc(1.475rem + 2.7vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-4{font-size:3.5rem}}.display-5{font-size:calc(1.425rem + 2.1vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-5{font-size:3rem}}.display-6{font-size:calc(1.375rem + 1.5vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-6{font-size:2.5rem}}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:.5rem}.initialism{font-size:0.875em;text-transform:uppercase}.blockquote{margin-bottom:1rem;font-size:1.25rem}.blockquote>:last-child{margin-bottom:0}.blockquote-footer{margin-top:-1rem;margin-bottom:1rem;font-size:0.875em;color:#6c757d}.blockquote-footer::before{content:"— "}.img-fluid{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:#fff;border:1px solid #dee2e6;border-radius:.375rem;max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:0.875em;color:rgba(33,37,41,.75)}.container,.container-fluid,.container-xxl,.container-xl,.container-lg,.container-md,.container-sm{--bs-gutter-x: 1.5rem;--bs-gutter-y: 0;width:100%;padding-right:calc(var(--bs-gutter-x)*.5);padding-left:calc(var(--bs-gutter-x)*.5);margin-right:auto;margin-left:auto}@media(min-width: 576px){.container-sm,.container{max-width:540px}}@media(min-width: 768px){.container-md,.container-sm,.container{max-width:720px}}@media(min-width: 992px){.container-lg,.container-md,.container-sm,.container{max-width:960px}}@media(min-width: 1200px){.container-xl,.container-lg,.container-md,.container-sm,.container{max-width:1140px}}@media(min-width: 1400px){.container-xxl,.container-xl,.container-lg,.container-md,.container-sm,.container{max-width:1320px}}:root{--bs-breakpoint-xs: 0;--bs-breakpoint-sm: 576px;--bs-breakpoint-md: 768px;--bs-breakpoint-lg: 992px;--bs-breakpoint-xl: 1200px;--bs-breakpoint-xxl: 1400px}.grid{display:grid;grid-template-rows:repeat(var(--bs-rows, 1), 1fr);grid-template-columns:repeat(var(--bs-columns, 12), 1fr);gap:var(--bs-gap, 1.5rem)}.grid .g-col-1{grid-column:auto/span 1}.grid .g-col-2{grid-column:auto/span 2}.grid .g-col-3{grid-column:auto/span 3}.grid .g-col-4{grid-column:auto/span 4}.grid .g-col-5{grid-column:auto/span 5}.grid .g-col-6{grid-column:auto/span 6}.grid .g-col-7{grid-column:auto/span 7}.grid .g-col-8{grid-column:auto/span 8}.grid .g-col-9{grid-column:auto/span 9}.grid .g-col-10{grid-column:auto/span 10}.grid .g-col-11{grid-column:auto/span 11}.grid .g-col-12{grid-column:auto/span 12}.grid .g-start-1{grid-column-start:1}.grid .g-start-2{grid-column-start:2}.grid .g-start-3{grid-column-start:3}.grid .g-start-4{grid-column-start:4}.grid .g-start-5{grid-column-start:5}.grid .g-start-6{grid-column-start:6}.grid .g-start-7{grid-column-start:7}.grid .g-start-8{grid-column-start:8}.grid .g-start-9{grid-column-start:9}.grid .g-start-10{grid-column-start:10}.grid .g-start-11{grid-column-start:11}@media(min-width: 576px){.grid .g-col-sm-1{grid-column:auto/span 1}.grid .g-col-sm-2{grid-column:auto/span 2}.grid .g-col-sm-3{grid-column:auto/span 3}.grid .g-col-sm-4{grid-column:auto/span 4}.grid .g-col-sm-5{grid-column:auto/span 5}.grid .g-col-sm-6{grid-column:auto/span 6}.grid .g-col-sm-7{grid-column:auto/span 7}.grid .g-col-sm-8{grid-column:auto/span 8}.grid .g-col-sm-9{grid-column:auto/span 9}.grid .g-col-sm-10{grid-column:auto/span 10}.grid .g-col-sm-11{grid-column:auto/span 11}.grid .g-col-sm-12{grid-column:auto/span 12}.grid .g-start-sm-1{grid-column-start:1}.grid .g-start-sm-2{grid-column-start:2}.grid .g-start-sm-3{grid-column-start:3}.grid .g-start-sm-4{grid-column-start:4}.grid .g-start-sm-5{grid-column-start:5}.grid .g-start-sm-6{grid-column-start:6}.grid .g-start-sm-7{grid-column-start:7}.grid .g-start-sm-8{grid-column-start:8}.grid .g-start-sm-9{grid-column-start:9}.grid .g-start-sm-10{grid-column-start:10}.grid .g-start-sm-11{grid-column-start:11}}@media(min-width: 768px){.grid .g-col-md-1{grid-column:auto/span 1}.grid .g-col-md-2{grid-column:auto/span 2}.grid .g-col-md-3{grid-column:auto/span 3}.grid .g-col-md-4{grid-column:auto/span 4}.grid .g-col-md-5{grid-column:auto/span 5}.grid .g-col-md-6{grid-column:auto/span 6}.grid .g-col-md-7{grid-column:auto/span 7}.grid .g-col-md-8{grid-column:auto/span 8}.grid .g-col-md-9{grid-column:auto/span 9}.grid .g-col-md-10{grid-column:auto/span 10}.grid .g-col-md-11{grid-column:auto/span 11}.grid .g-col-md-12{grid-column:auto/span 12}.grid .g-start-md-1{grid-column-start:1}.grid .g-start-md-2{grid-column-start:2}.grid .g-start-md-3{grid-column-start:3}.grid .g-start-md-4{grid-column-start:4}.grid .g-start-md-5{grid-column-start:5}.grid .g-start-md-6{grid-column-start:6}.grid .g-start-md-7{grid-column-start:7}.grid .g-start-md-8{grid-column-start:8}.grid .g-start-md-9{grid-column-start:9}.grid .g-start-md-10{grid-column-start:10}.grid .g-start-md-11{grid-column-start:11}}@media(min-width: 992px){.grid .g-col-lg-1{grid-column:auto/span 1}.grid .g-col-lg-2{grid-column:auto/span 2}.grid .g-col-lg-3{grid-column:auto/span 3}.grid .g-col-lg-4{grid-column:auto/span 4}.grid .g-col-lg-5{grid-column:auto/span 5}.grid .g-col-lg-6{grid-column:auto/span 6}.grid .g-col-lg-7{grid-column:auto/span 7}.grid .g-col-lg-8{grid-column:auto/span 8}.grid .g-col-lg-9{grid-column:auto/span 9}.grid .g-col-lg-10{grid-column:auto/span 10}.grid .g-col-lg-11{grid-column:auto/span 11}.grid .g-col-lg-12{grid-column:auto/span 12}.grid .g-start-lg-1{grid-column-start:1}.grid .g-start-lg-2{grid-column-start:2}.grid .g-start-lg-3{grid-column-start:3}.grid .g-start-lg-4{grid-column-start:4}.grid .g-start-lg-5{grid-column-start:5}.grid .g-start-lg-6{grid-column-start:6}.grid .g-start-lg-7{grid-column-start:7}.grid .g-start-lg-8{grid-column-start:8}.grid .g-start-lg-9{grid-column-start:9}.grid .g-start-lg-10{grid-column-start:10}.grid .g-start-lg-11{grid-column-start:11}}@media(min-width: 1200px){.grid .g-col-xl-1{grid-column:auto/span 1}.grid .g-col-xl-2{grid-column:auto/span 2}.grid .g-col-xl-3{grid-column:auto/span 3}.grid .g-col-xl-4{grid-column:auto/span 4}.grid .g-col-xl-5{grid-column:auto/span 5}.grid .g-col-xl-6{grid-column:auto/span 6}.grid .g-col-xl-7{grid-column:auto/span 7}.grid .g-col-xl-8{grid-column:auto/span 8}.grid .g-col-xl-9{grid-column:auto/span 9}.grid .g-col-xl-10{grid-column:auto/span 10}.grid .g-col-xl-11{grid-column:auto/span 11}.grid .g-col-xl-12{grid-column:auto/span 12}.grid .g-start-xl-1{grid-column-start:1}.grid .g-start-xl-2{grid-column-start:2}.grid .g-start-xl-3{grid-column-start:3}.grid .g-start-xl-4{grid-column-start:4}.grid .g-start-xl-5{grid-column-start:5}.grid .g-start-xl-6{grid-column-start:6}.grid .g-start-xl-7{grid-column-start:7}.grid .g-start-xl-8{grid-column-start:8}.grid .g-start-xl-9{grid-column-start:9}.grid .g-start-xl-10{grid-column-start:10}.grid .g-start-xl-11{grid-column-start:11}}@media(min-width: 1400px){.grid .g-col-xxl-1{grid-column:auto/span 1}.grid .g-col-xxl-2{grid-column:auto/span 2}.grid .g-col-xxl-3{grid-column:auto/span 3}.grid .g-col-xxl-4{grid-column:auto/span 4}.grid .g-col-xxl-5{grid-column:auto/span 5}.grid .g-col-xxl-6{grid-column:auto/span 6}.grid .g-col-xxl-7{grid-column:auto/span 7}.grid .g-col-xxl-8{grid-column:auto/span 8}.grid .g-col-xxl-9{grid-column:auto/span 9}.grid .g-col-xxl-10{grid-column:auto/span 10}.grid .g-col-xxl-11{grid-column:auto/span 11}.grid .g-col-xxl-12{grid-column:auto/span 12}.grid .g-start-xxl-1{grid-column-start:1}.grid .g-start-xxl-2{grid-column-start:2}.grid .g-start-xxl-3{grid-column-start:3}.grid .g-start-xxl-4{grid-column-start:4}.grid .g-start-xxl-5{grid-column-start:5}.grid .g-start-xxl-6{grid-column-start:6}.grid .g-start-xxl-7{grid-column-start:7}.grid .g-start-xxl-8{grid-column-start:8}.grid .g-start-xxl-9{grid-column-start:9}.grid .g-start-xxl-10{grid-column-start:10}.grid .g-start-xxl-11{grid-column-start:11}}.table{--bs-table-color-type: initial;--bs-table-bg-type: initial;--bs-table-color-state: initial;--bs-table-bg-state: initial;--bs-table-color: #212529;--bs-table-bg: #ffffff;--bs-table-border-color: #dee2e6;--bs-table-accent-bg: transparent;--bs-table-striped-color: #212529;--bs-table-striped-bg: rgba(0, 0, 0, 0.05);--bs-table-active-color: #212529;--bs-table-active-bg: rgba(0, 0, 0, 0.1);--bs-table-hover-color: #212529;--bs-table-hover-bg: rgba(0, 0, 0, 0.075);width:100%;margin-bottom:1rem;vertical-align:top;border-color:var(--bs-table-border-color)}.table>:not(caption)>*>*{padding:.5rem .5rem;color:var(--bs-table-color-state, var(--bs-table-color-type, var(--bs-table-color)));background-color:var(--bs-table-bg);border-bottom-width:1px;box-shadow:inset 0 0 0 9999px var(--bs-table-bg-state, var(--bs-table-bg-type, var(--bs-table-accent-bg)))}.table>tbody{vertical-align:inherit}.table>thead{vertical-align:bottom}.table-group-divider{border-top:calc(1px*2) solid #9ba5ae}.caption-top{caption-side:top}.table-sm>:not(caption)>*>*{padding:.25rem .25rem}.table-bordered>:not(caption)>*{border-width:1px 0}.table-bordered>:not(caption)>*>*{border-width:0 1px}.table-borderless>:not(caption)>*>*{border-bottom-width:0}.table-borderless>:not(:first-child){border-top-width:0}.table-striped>tbody>tr:nth-of-type(odd)>*{--bs-table-color-type: var(--bs-table-striped-color);--bs-table-bg-type: var(--bs-table-striped-bg)}.table-striped-columns>:not(caption)>tr>:nth-child(even){--bs-table-color-type: var(--bs-table-striped-color);--bs-table-bg-type: var(--bs-table-striped-bg)}.table-active{--bs-table-color-state: var(--bs-table-active-color);--bs-table-bg-state: var(--bs-table-active-bg)}.table-hover>tbody>tr:hover>*{--bs-table-color-state: var(--bs-table-hover-color);--bs-table-bg-state: var(--bs-table-hover-bg)}.table-primary{--bs-table-color: #000;--bs-table-bg: #cfe2ff;--bs-table-border-color: #bacbe6;--bs-table-striped-bg: #c5d7f2;--bs-table-striped-color: #000;--bs-table-active-bg: #bacbe6;--bs-table-active-color: #000;--bs-table-hover-bg: #bfd1ec;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-secondary{--bs-table-color: #000;--bs-table-bg: #e2e3e5;--bs-table-border-color: #cbccce;--bs-table-striped-bg: #d7d8da;--bs-table-striped-color: #000;--bs-table-active-bg: #cbccce;--bs-table-active-color: #000;--bs-table-hover-bg: #d1d2d4;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-success{--bs-table-color: #000;--bs-table-bg: #d1e7dd;--bs-table-border-color: #bcd0c7;--bs-table-striped-bg: #c7dbd2;--bs-table-striped-color: #000;--bs-table-active-bg: #bcd0c7;--bs-table-active-color: #000;--bs-table-hover-bg: #c1d6cc;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-info{--bs-table-color: #000;--bs-table-bg: #cff4fc;--bs-table-border-color: #badce3;--bs-table-striped-bg: #c5e8ef;--bs-table-striped-color: #000;--bs-table-active-bg: #badce3;--bs-table-active-color: #000;--bs-table-hover-bg: #bfe2e9;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-warning{--bs-table-color: #000;--bs-table-bg: #fff3cd;--bs-table-border-color: #e6dbb9;--bs-table-striped-bg: #f2e7c3;--bs-table-striped-color: #000;--bs-table-active-bg: #e6dbb9;--bs-table-active-color: #000;--bs-table-hover-bg: #ece1be;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-danger{--bs-table-color: #000;--bs-table-bg: #f8d7da;--bs-table-border-color: #dfc2c4;--bs-table-striped-bg: #eccccf;--bs-table-striped-color: #000;--bs-table-active-bg: #dfc2c4;--bs-table-active-color: #000;--bs-table-hover-bg: #e5c7ca;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-light{--bs-table-color: #000;--bs-table-bg: #f8f9fa;--bs-table-border-color: #dfe0e1;--bs-table-striped-bg: #ecedee;--bs-table-striped-color: #000;--bs-table-active-bg: #dfe0e1;--bs-table-active-color: #000;--bs-table-hover-bg: #e5e6e7;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-dark{--bs-table-color: #ffffff;--bs-table-bg: #212529;--bs-table-border-color: #373b3e;--bs-table-striped-bg: #2c3034;--bs-table-striped-color: #ffffff;--bs-table-active-bg: #373b3e;--bs-table-active-color: #ffffff;--bs-table-hover-bg: #323539;--bs-table-hover-color: #ffffff;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-responsive{overflow-x:auto;-webkit-overflow-scrolling:touch}@media(max-width: 575.98px){.table-responsive-sm{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media(max-width: 767.98px){.table-responsive-md{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media(max-width: 991.98px){.table-responsive-lg{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media(max-width: 1199.98px){.table-responsive-xl{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media(max-width: 1399.98px){.table-responsive-xxl{overflow-x:auto;-webkit-overflow-scrolling:touch}}.form-label,.shiny-input-container .control-label{margin-bottom:.5rem}.col-form-label{padding-top:calc(0.375rem + 1px);padding-bottom:calc(0.375rem + 1px);margin-bottom:0;font-size:inherit;line-height:1.5}.col-form-label-lg{padding-top:calc(0.5rem + 1px);padding-bottom:calc(0.5rem + 1px);font-size:1.25rem}.col-form-label-sm{padding-top:calc(0.25rem + 1px);padding-bottom:calc(0.25rem + 1px);font-size:0.875rem}.form-text{margin-top:.25rem;font-size:0.875em;color:rgba(33,37,41,.75)}.form-control{display:block;width:100%;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#212529;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none;background-color:#fff;background-clip:padding-box;border:1px solid #dee2e6;border-radius:.375rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.form-control{transition:none}}.form-control[type=file]{overflow:hidden}.form-control[type=file]:not(:disabled):not([readonly]){cursor:pointer}.form-control:focus{color:#212529;background-color:#fff;border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-control::-webkit-date-and-time-value{min-width:85px;height:1.5em;margin:0}.form-control::-webkit-datetime-edit{display:block;padding:0}.form-control::placeholder{color:rgba(33,37,41,.75);opacity:1}.form-control:disabled{background-color:#e9ecef;opacity:1}.form-control::file-selector-button{padding:.375rem .75rem;margin:-0.375rem -0.75rem;margin-inline-end:.75rem;color:#212529;background-color:#f8f9fa;pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:1px;border-radius:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.form-control::file-selector-button{transition:none}}.form-control:hover:not(:disabled):not([readonly])::file-selector-button{background-color:#e9ecef}.form-control-plaintext{display:block;width:100%;padding:.375rem 0;margin-bottom:0;line-height:1.5;color:#212529;background-color:rgba(0,0,0,0);border:solid rgba(0,0,0,0);border-width:1px 0}.form-control-plaintext:focus{outline:0}.form-control-plaintext.form-control-sm,.form-control-plaintext.form-control-lg{padding-right:0;padding-left:0}.form-control-sm{min-height:calc(1.5em + 0.5rem + calc(1px * 2));padding:.25rem .5rem;font-size:0.875rem;border-radius:.25rem}.form-control-sm::file-selector-button{padding:.25rem .5rem;margin:-0.25rem -0.5rem;margin-inline-end:.5rem}.form-control-lg{min-height:calc(1.5em + 1rem + calc(1px * 2));padding:.5rem 1rem;font-size:1.25rem;border-radius:.5rem}.form-control-lg::file-selector-button{padding:.5rem 1rem;margin:-0.5rem -1rem;margin-inline-end:1rem}textarea.form-control{min-height:calc(1.5em + 0.75rem + calc(1px * 2))}textarea.form-control-sm{min-height:calc(1.5em + 0.5rem + calc(1px * 2))}textarea.form-control-lg{min-height:calc(1.5em + 1rem + calc(1px * 2))}.form-control-color{width:3rem;height:calc(1.5em + 0.75rem + calc(1px * 2));padding:.375rem}.form-control-color:not(:disabled):not([readonly]){cursor:pointer}.form-control-color::-moz-color-swatch{border:0 !important;border-radius:.375rem}.form-control-color::-webkit-color-swatch{border:0 !important;border-radius:.375rem}.form-control-color.form-control-sm{height:calc(1.5em + 0.5rem + calc(1px * 2))}.form-control-color.form-control-lg{height:calc(1.5em + 1rem + calc(1px * 2))}.form-select{--bs-form-select-bg-img: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e");display:block;width:100%;padding:.375rem 2.25rem .375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#212529;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none;background-color:#fff;background-image:var(--bs-form-select-bg-img),var(--bs-form-select-bg-icon, none);background-repeat:no-repeat;background-position:right .75rem center;background-size:16px 12px;border:1px solid #dee2e6;border-radius:.375rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.form-select{transition:none}}.form-select:focus{border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-select[multiple],.form-select[size]:not([size="1"]){padding-right:.75rem;background-image:none}.form-select:disabled{background-color:#e9ecef}.form-select:-moz-focusring{color:rgba(0,0,0,0);text-shadow:0 0 0 #212529}.form-select-sm{padding-top:.25rem;padding-bottom:.25rem;padding-left:.5rem;font-size:0.875rem;border-radius:.25rem}.form-select-lg{padding-top:.5rem;padding-bottom:.5rem;padding-left:1rem;font-size:1.25rem;border-radius:.5rem}[data-bs-theme=dark] .form-select{--bs-form-select-bg-img: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23dee2e6' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e")}.form-check,.shiny-input-container .checkbox,.shiny-input-container .radio{display:block;min-height:1.5rem;padding-left:0;margin-bottom:.125rem}.form-check .form-check-input,.form-check .shiny-input-container .checkbox input,.form-check .shiny-input-container .radio input,.shiny-input-container .checkbox .form-check-input,.shiny-input-container .checkbox .shiny-input-container .checkbox input,.shiny-input-container .checkbox .shiny-input-container .radio input,.shiny-input-container .radio .form-check-input,.shiny-input-container .radio .shiny-input-container .checkbox input,.shiny-input-container .radio .shiny-input-container .radio input{float:left;margin-left:0}.form-check-reverse{padding-right:0;padding-left:0;text-align:right}.form-check-reverse .form-check-input{float:right;margin-right:0;margin-left:0}.form-check-input,.shiny-input-container .checkbox input,.shiny-input-container .checkbox-inline input,.shiny-input-container .radio input,.shiny-input-container .radio-inline input{--bs-form-check-bg: #ffffff;width:1em;height:1em;margin-top:.25em;vertical-align:top;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none;background-color:var(--bs-form-check-bg);background-image:var(--bs-form-check-bg-image);background-repeat:no-repeat;background-position:center;background-size:contain;border:1px solid #dee2e6;print-color-adjust:exact}.form-check-input[type=checkbox],.shiny-input-container .checkbox input[type=checkbox],.shiny-input-container .checkbox-inline input[type=checkbox],.shiny-input-container .radio input[type=checkbox],.shiny-input-container .radio-inline input[type=checkbox]{border-radius:.25em}.form-check-input[type=radio],.shiny-input-container .checkbox input[type=radio],.shiny-input-container .checkbox-inline input[type=radio],.shiny-input-container .radio input[type=radio],.shiny-input-container .radio-inline input[type=radio]{border-radius:50%}.form-check-input:active,.shiny-input-container .checkbox input:active,.shiny-input-container .checkbox-inline input:active,.shiny-input-container .radio input:active,.shiny-input-container .radio-inline input:active{filter:brightness(90%)}.form-check-input:focus,.shiny-input-container .checkbox input:focus,.shiny-input-container .checkbox-inline input:focus,.shiny-input-container .radio input:focus,.shiny-input-container .radio-inline input:focus{border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-check-input:checked,.shiny-input-container .checkbox input:checked,.shiny-input-container .checkbox-inline input:checked,.shiny-input-container .radio input:checked,.shiny-input-container .radio-inline input:checked{background-color:#0d6efd;border-color:#0d6efd}.form-check-input:checked[type=checkbox],.shiny-input-container .checkbox input:checked[type=checkbox],.shiny-input-container .checkbox-inline input:checked[type=checkbox],.shiny-input-container .radio input:checked[type=checkbox],.shiny-input-container .radio-inline input:checked[type=checkbox]{--bs-form-check-bg-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23ffffff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='m6 10 3 3 6-6'/%3e%3c/svg%3e")}.form-check-input:checked[type=radio],.shiny-input-container .checkbox input:checked[type=radio],.shiny-input-container .checkbox-inline input:checked[type=radio],.shiny-input-container .radio input:checked[type=radio],.shiny-input-container .radio-inline input:checked[type=radio]{--bs-form-check-bg-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='2' fill='%23ffffff'/%3e%3c/svg%3e")}.form-check-input[type=checkbox]:indeterminate,.shiny-input-container .checkbox input[type=checkbox]:indeterminate,.shiny-input-container .checkbox-inline input[type=checkbox]:indeterminate,.shiny-input-container .radio input[type=checkbox]:indeterminate,.shiny-input-container .radio-inline input[type=checkbox]:indeterminate{background-color:#0d6efd;border-color:#0d6efd;--bs-form-check-bg-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23ffffff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10h8'/%3e%3c/svg%3e")}.form-check-input:disabled,.shiny-input-container .checkbox input:disabled,.shiny-input-container .checkbox-inline input:disabled,.shiny-input-container .radio input:disabled,.shiny-input-container .radio-inline input:disabled{pointer-events:none;filter:none;opacity:.5}.form-check-input[disabled]~.form-check-label,.form-check-input[disabled]~span,.form-check-input:disabled~.form-check-label,.form-check-input:disabled~span,.shiny-input-container .checkbox input[disabled]~.form-check-label,.shiny-input-container .checkbox input[disabled]~span,.shiny-input-container .checkbox input:disabled~.form-check-label,.shiny-input-container .checkbox input:disabled~span,.shiny-input-container .checkbox-inline input[disabled]~.form-check-label,.shiny-input-container .checkbox-inline input[disabled]~span,.shiny-input-container .checkbox-inline input:disabled~.form-check-label,.shiny-input-container .checkbox-inline input:disabled~span,.shiny-input-container .radio input[disabled]~.form-check-label,.shiny-input-container .radio input[disabled]~span,.shiny-input-container .radio input:disabled~.form-check-label,.shiny-input-container .radio input:disabled~span,.shiny-input-container .radio-inline input[disabled]~.form-check-label,.shiny-input-container .radio-inline input[disabled]~span,.shiny-input-container .radio-inline input:disabled~.form-check-label,.shiny-input-container .radio-inline input:disabled~span{cursor:default;opacity:.5}.form-check-label,.shiny-input-container .checkbox label,.shiny-input-container .checkbox-inline label,.shiny-input-container .radio label,.shiny-input-container .radio-inline label{cursor:pointer}.form-switch{padding-left:2.5em}.form-switch .form-check-input{--bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%280, 0, 0, 0.25%29'/%3e%3c/svg%3e");width:2em;margin-left:-2.5em;background-image:var(--bs-form-switch-bg);background-position:left center;border-radius:2em;transition:background-position .15s ease-in-out}@media(prefers-reduced-motion: reduce){.form-switch .form-check-input{transition:none}}.form-switch .form-check-input:focus{--bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%2386b7fe'/%3e%3c/svg%3e")}.form-switch .form-check-input:checked{background-position:right center;--bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23ffffff'/%3e%3c/svg%3e")}.form-switch.form-check-reverse{padding-right:2.5em;padding-left:0}.form-switch.form-check-reverse .form-check-input{margin-right:-2.5em;margin-left:0}.form-check-inline{display:inline-block;margin-right:1rem}.btn-check{position:absolute;clip:rect(0, 0, 0, 0);pointer-events:none}.btn-check[disabled]+.btn,.btn-check:disabled+.btn{pointer-events:none;filter:none;opacity:.65}[data-bs-theme=dark] .form-switch .form-check-input:not(:checked):not(:focus){--bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%28255, 255, 255, 0.25%29'/%3e%3c/svg%3e")}.form-range{width:100%;height:1.5rem;padding:0;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none;background-color:rgba(0,0,0,0)}.form-range:focus{outline:0}.form-range:focus::-webkit-slider-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(13,110,253,.25)}.form-range:focus::-moz-range-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(13,110,253,.25)}.form-range::-moz-focus-outer{border:0}.form-range::-webkit-slider-thumb{width:1rem;height:1rem;margin-top:-0.25rem;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none;background-color:#0d6efd;border:0;border-radius:1rem;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.form-range::-webkit-slider-thumb{transition:none}}.form-range::-webkit-slider-thumb:active{background-color:#b6d4fe}.form-range::-webkit-slider-runnable-track{width:100%;height:.5rem;color:rgba(0,0,0,0);cursor:pointer;background-color:#f8f9fa;border-color:rgba(0,0,0,0);border-radius:1rem}.form-range::-moz-range-thumb{width:1rem;height:1rem;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none;background-color:#0d6efd;border:0;border-radius:1rem;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.form-range::-moz-range-thumb{transition:none}}.form-range::-moz-range-thumb:active{background-color:#b6d4fe}.form-range::-moz-range-track{width:100%;height:.5rem;color:rgba(0,0,0,0);cursor:pointer;background-color:#f8f9fa;border-color:rgba(0,0,0,0);border-radius:1rem}.form-range:disabled{pointer-events:none}.form-range:disabled::-webkit-slider-thumb{background-color:rgba(33,37,41,.75)}.form-range:disabled::-moz-range-thumb{background-color:rgba(33,37,41,.75)}.form-floating{position:relative}.form-floating>.form-control,.form-floating>.form-control-plaintext,.form-floating>.form-select{height:calc(3.5rem + calc(1px * 2));min-height:calc(3.5rem + calc(1px * 2));line-height:1.25}.form-floating>label{position:absolute;top:0;left:0;z-index:2;height:100%;padding:1rem .75rem;overflow:hidden;text-align:start;text-overflow:ellipsis;white-space:nowrap;pointer-events:none;border:1px solid rgba(0,0,0,0);transform-origin:0 0;transition:opacity .1s ease-in-out,transform .1s ease-in-out}@media(prefers-reduced-motion: reduce){.form-floating>label{transition:none}}.form-floating>.form-control,.form-floating>.form-control-plaintext{padding:1rem .75rem}.form-floating>.form-control::placeholder,.form-floating>.form-control-plaintext::placeholder{color:rgba(0,0,0,0)}.form-floating>.form-control:focus,.form-floating>.form-control:not(:placeholder-shown),.form-floating>.form-control-plaintext:focus,.form-floating>.form-control-plaintext:not(:placeholder-shown){padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:-webkit-autofill,.form-floating>.form-control-plaintext:-webkit-autofill{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-select{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:focus~label,.form-floating>.form-control:not(:placeholder-shown)~label,.form-floating>.form-control-plaintext~label,.form-floating>.form-select~label{color:rgba(var(--bs-body-color-rgb), 0.65);transform:scale(0.85) translateY(-0.5rem) translateX(0.15rem)}.form-floating>.form-control:focus~label::after,.form-floating>.form-control:not(:placeholder-shown)~label::after,.form-floating>.form-control-plaintext~label::after,.form-floating>.form-select~label::after{position:absolute;inset:1rem .375rem;z-index:-1;height:1.5em;content:"";background-color:#fff;border-radius:.375rem}.form-floating>.form-control:-webkit-autofill~label{color:rgba(var(--bs-body-color-rgb), 0.65);transform:scale(0.85) translateY(-0.5rem) translateX(0.15rem)}.form-floating>.form-control-plaintext~label{border-width:1px 0}.form-floating>:disabled~label,.form-floating>.form-control:disabled~label{color:#6c757d}.form-floating>:disabled~label::after,.form-floating>.form-control:disabled~label::after{background-color:#e9ecef}.input-group{position:relative;display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;align-items:stretch;-webkit-align-items:stretch;width:100%}.input-group>.form-control,.input-group>.form-select,.input-group>.form-floating{position:relative;flex:1 1 auto;-webkit-flex:1 1 auto;width:1%;min-width:0}.input-group>.form-control:focus,.input-group>.form-select:focus,.input-group>.form-floating:focus-within{z-index:5}.input-group .btn{position:relative;z-index:2}.input-group .btn:focus{z-index:5}.input-group-text{display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:center;white-space:nowrap;background-color:#f8f9fa;border:1px solid #dee2e6;border-radius:.375rem}.input-group-lg>.form-control,.input-group-lg>.form-select,.input-group-lg>.input-group-text,.input-group-lg>.btn{padding:.5rem 1rem;font-size:1.25rem;border-radius:.5rem}.input-group-sm>.form-control,.input-group-sm>.form-select,.input-group-sm>.input-group-text,.input-group-sm>.btn{padding:.25rem .5rem;font-size:0.875rem;border-radius:.25rem}.input-group-lg>.form-select,.input-group-sm>.form-select{padding-right:3rem}.input-group:not(.has-validation)>:not(:last-child):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating),.input-group:not(.has-validation)>.dropdown-toggle:nth-last-child(n+3),.input-group:not(.has-validation)>.form-floating:not(:last-child)>.form-control,.input-group:not(.has-validation)>.form-floating:not(:last-child)>.form-select{border-top-right-radius:0;border-bottom-right-radius:0}.input-group.has-validation>:nth-last-child(n+3):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating),.input-group.has-validation>.dropdown-toggle:nth-last-child(n+4),.input-group.has-validation>.form-floating:nth-last-child(n+3)>.form-control,.input-group.has-validation>.form-floating:nth-last-child(n+3)>.form-select{border-top-right-radius:0;border-bottom-right-radius:0}.input-group>:not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback){margin-left:calc(1px*-1);border-top-left-radius:0;border-bottom-left-radius:0}.input-group>.form-floating:not(:first-child)>.form-control,.input-group>.form-floating:not(:first-child)>.form-select{border-top-left-radius:0;border-bottom-left-radius:0}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:0.875em;color:#198754}.valid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:0.875rem;color:#fff;background-color:#198754;border-radius:.375rem}.was-validated :valid~.valid-feedback,.was-validated :valid~.valid-tooltip,.is-valid~.valid-feedback,.is-valid~.valid-tooltip{display:block}.was-validated .form-control:valid,.form-control.is-valid{border-color:#198754;padding-right:calc(1.5em + 0.75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(0.375em + 0.1875rem) center;background-size:calc(0.75em + 0.375rem) calc(0.75em + 0.375rem)}.was-validated .form-control:valid:focus,.form-control.is-valid:focus{border-color:#198754;box-shadow:0 0 0 .25rem rgba(25,135,84,.25)}.was-validated textarea.form-control:valid,textarea.form-control.is-valid{padding-right:calc(1.5em + 0.75rem);background-position:top calc(0.375em + 0.1875rem) right calc(0.375em + 0.1875rem)}.was-validated .form-select:valid,.form-select.is-valid{border-color:#198754}.was-validated .form-select:valid:not([multiple]):not([size]),.was-validated .form-select:valid:not([multiple])[size="1"],.form-select.is-valid:not([multiple]):not([size]),.form-select.is-valid:not([multiple])[size="1"]{--bs-form-select-bg-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");padding-right:4.125rem;background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(0.75em + 0.375rem) calc(0.75em + 0.375rem)}.was-validated .form-select:valid:focus,.form-select.is-valid:focus{border-color:#198754;box-shadow:0 0 0 .25rem rgba(25,135,84,.25)}.was-validated .form-control-color:valid,.form-control-color.is-valid{width:calc(3rem + calc(1.5em + 0.75rem))}.was-validated .form-check-input:valid,.form-check-input.is-valid{border-color:#198754}.was-validated .form-check-input:valid:checked,.form-check-input.is-valid:checked{background-color:#198754}.was-validated .form-check-input:valid:focus,.form-check-input.is-valid:focus{box-shadow:0 0 0 .25rem rgba(25,135,84,.25)}.was-validated .form-check-input:valid~.form-check-label,.form-check-input.is-valid~.form-check-label{color:#198754}.form-check-inline .form-check-input~.valid-feedback{margin-left:.5em}.was-validated .input-group>.form-control:not(:focus):valid,.input-group>.form-control:not(:focus).is-valid,.was-validated .input-group>.form-select:not(:focus):valid,.input-group>.form-select:not(:focus).is-valid,.was-validated .input-group>.form-floating:not(:focus-within):valid,.input-group>.form-floating:not(:focus-within).is-valid{z-index:3}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:0.875em;color:#dc3545}.invalid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:0.875rem;color:#fff;background-color:#dc3545;border-radius:.375rem}.was-validated :invalid~.invalid-feedback,.was-validated :invalid~.invalid-tooltip,.is-invalid~.invalid-feedback,.is-invalid~.invalid-tooltip{display:block}.was-validated .form-control:invalid,.form-control.is-invalid{border-color:#dc3545;padding-right:calc(1.5em + 0.75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(0.375em + 0.1875rem) center;background-size:calc(0.75em + 0.375rem) calc(0.75em + 0.375rem)}.was-validated .form-control:invalid:focus,.form-control.is-invalid:focus{border-color:#dc3545;box-shadow:0 0 0 .25rem rgba(220,53,69,.25)}.was-validated textarea.form-control:invalid,textarea.form-control.is-invalid{padding-right:calc(1.5em + 0.75rem);background-position:top calc(0.375em + 0.1875rem) right calc(0.375em + 0.1875rem)}.was-validated .form-select:invalid,.form-select.is-invalid{border-color:#dc3545}.was-validated .form-select:invalid:not([multiple]):not([size]),.was-validated .form-select:invalid:not([multiple])[size="1"],.form-select.is-invalid:not([multiple]):not([size]),.form-select.is-invalid:not([multiple])[size="1"]{--bs-form-select-bg-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");padding-right:4.125rem;background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(0.75em + 0.375rem) calc(0.75em + 0.375rem)}.was-validated .form-select:invalid:focus,.form-select.is-invalid:focus{border-color:#dc3545;box-shadow:0 0 0 .25rem rgba(220,53,69,.25)}.was-validated .form-control-color:invalid,.form-control-color.is-invalid{width:calc(3rem + calc(1.5em + 0.75rem))}.was-validated .form-check-input:invalid,.form-check-input.is-invalid{border-color:#dc3545}.was-validated .form-check-input:invalid:checked,.form-check-input.is-invalid:checked{background-color:#dc3545}.was-validated .form-check-input:invalid:focus,.form-check-input.is-invalid:focus{box-shadow:0 0 0 .25rem rgba(220,53,69,.25)}.was-validated .form-check-input:invalid~.form-check-label,.form-check-input.is-invalid~.form-check-label{color:#dc3545}.form-check-inline .form-check-input~.invalid-feedback{margin-left:.5em}.was-validated .input-group>.form-control:not(:focus):invalid,.input-group>.form-control:not(:focus).is-invalid,.was-validated .input-group>.form-select:not(:focus):invalid,.input-group>.form-select:not(:focus).is-invalid,.was-validated .input-group>.form-floating:not(:focus-within):invalid,.input-group>.form-floating:not(:focus-within).is-invalid{z-index:4}.btn{--bs-btn-padding-x: 0.75rem;--bs-btn-padding-y: 0.375rem;--bs-btn-font-family: ;--bs-btn-font-size:1rem;--bs-btn-font-weight: 400;--bs-btn-line-height: 1.5;--bs-btn-color: #212529;--bs-btn-bg: transparent;--bs-btn-border-width: 1px;--bs-btn-border-color: transparent;--bs-btn-border-radius: 0.375rem;--bs-btn-hover-border-color: transparent;--bs-btn-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075);--bs-btn-disabled-opacity: 0.65;--bs-btn-focus-box-shadow: 0 0 0 0.25rem rgba(var(--bs-btn-focus-shadow-rgb), .5);display:inline-block;padding:var(--bs-btn-padding-y) var(--bs-btn-padding-x);font-family:var(--bs-btn-font-family);font-size:var(--bs-btn-font-size);font-weight:var(--bs-btn-font-weight);line-height:var(--bs-btn-line-height);color:var(--bs-btn-color);text-align:center;text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;vertical-align:middle;cursor:pointer;user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;border:var(--bs-btn-border-width) solid var(--bs-btn-border-color);border-radius:var(--bs-btn-border-radius);background-color:var(--bs-btn-bg);transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.btn{transition:none}}.btn:hover{color:var(--bs-btn-hover-color);background-color:var(--bs-btn-hover-bg);border-color:var(--bs-btn-hover-border-color)}.btn-check+.btn:hover{color:var(--bs-btn-color);background-color:var(--bs-btn-bg);border-color:var(--bs-btn-border-color)}.btn:focus-visible{color:var(--bs-btn-hover-color);background-color:var(--bs-btn-hover-bg);border-color:var(--bs-btn-hover-border-color);outline:0;box-shadow:var(--bs-btn-focus-box-shadow)}.btn-check:focus-visible+.btn{border-color:var(--bs-btn-hover-border-color);outline:0;box-shadow:var(--bs-btn-focus-box-shadow)}.btn-check:checked+.btn,:not(.btn-check)+.btn:active,.btn:first-child:active,.btn.active,.btn.show{color:var(--bs-btn-active-color);background-color:var(--bs-btn-active-bg);border-color:var(--bs-btn-active-border-color)}.btn-check:checked+.btn:focus-visible,:not(.btn-check)+.btn:active:focus-visible,.btn:first-child:active:focus-visible,.btn.active:focus-visible,.btn.show:focus-visible{box-shadow:var(--bs-btn-focus-box-shadow)}.btn:disabled,.btn.disabled,fieldset:disabled .btn{color:var(--bs-btn-disabled-color);pointer-events:none;background-color:var(--bs-btn-disabled-bg);border-color:var(--bs-btn-disabled-border-color);opacity:var(--bs-btn-disabled-opacity)}.btn-default{--bs-btn-color: #000;--bs-btn-bg: #dee2e6;--bs-btn-border-color: #dee2e6;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #e3e6ea;--bs-btn-hover-border-color: #e1e5e9;--bs-btn-focus-shadow-rgb: 189, 192, 196;--bs-btn-active-color: #000;--bs-btn-active-bg: #e5e8eb;--bs-btn-active-border-color: #e1e5e9;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #000;--bs-btn-disabled-bg: #dee2e6;--bs-btn-disabled-border-color: #dee2e6}.btn-primary{--bs-btn-color: #ffffff;--bs-btn-bg: #0d6efd;--bs-btn-border-color: #0d6efd;--bs-btn-hover-color: #ffffff;--bs-btn-hover-bg: #0b5ed7;--bs-btn-hover-border-color: #0a58ca;--bs-btn-focus-shadow-rgb: 49, 132, 253;--bs-btn-active-color: #ffffff;--bs-btn-active-bg: #0a58ca;--bs-btn-active-border-color: #0a53be;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #ffffff;--bs-btn-disabled-bg: #0d6efd;--bs-btn-disabled-border-color: #0d6efd}.btn-secondary{--bs-btn-color: #ffffff;--bs-btn-bg: #6c757d;--bs-btn-border-color: #6c757d;--bs-btn-hover-color: #ffffff;--bs-btn-hover-bg: #5c636a;--bs-btn-hover-border-color: #565e64;--bs-btn-focus-shadow-rgb: 130, 138, 145;--bs-btn-active-color: #ffffff;--bs-btn-active-bg: #565e64;--bs-btn-active-border-color: #51585e;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #ffffff;--bs-btn-disabled-bg: #6c757d;--bs-btn-disabled-border-color: #6c757d}.btn-success{--bs-btn-color: #ffffff;--bs-btn-bg: #198754;--bs-btn-border-color: #198754;--bs-btn-hover-color: #ffffff;--bs-btn-hover-bg: #157347;--bs-btn-hover-border-color: #146c43;--bs-btn-focus-shadow-rgb: 60, 153, 110;--bs-btn-active-color: #ffffff;--bs-btn-active-bg: #146c43;--bs-btn-active-border-color: #13653f;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #ffffff;--bs-btn-disabled-bg: #198754;--bs-btn-disabled-border-color: #198754}.btn-info{--bs-btn-color: #000;--bs-btn-bg: #0dcaf0;--bs-btn-border-color: #0dcaf0;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #31d2f2;--bs-btn-hover-border-color: #25cff2;--bs-btn-focus-shadow-rgb: 11, 172, 204;--bs-btn-active-color: #000;--bs-btn-active-bg: #3dd5f3;--bs-btn-active-border-color: #25cff2;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #000;--bs-btn-disabled-bg: #0dcaf0;--bs-btn-disabled-border-color: #0dcaf0}.btn-warning{--bs-btn-color: #000;--bs-btn-bg: #ffc107;--bs-btn-border-color: #ffc107;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #ffca2c;--bs-btn-hover-border-color: #ffc720;--bs-btn-focus-shadow-rgb: 217, 164, 6;--bs-btn-active-color: #000;--bs-btn-active-bg: #ffcd39;--bs-btn-active-border-color: #ffc720;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #000;--bs-btn-disabled-bg: #ffc107;--bs-btn-disabled-border-color: #ffc107}.btn-danger{--bs-btn-color: #ffffff;--bs-btn-bg: #dc3545;--bs-btn-border-color: #dc3545;--bs-btn-hover-color: #ffffff;--bs-btn-hover-bg: #bb2d3b;--bs-btn-hover-border-color: #b02a37;--bs-btn-focus-shadow-rgb: 225, 83, 97;--bs-btn-active-color: #ffffff;--bs-btn-active-bg: #b02a37;--bs-btn-active-border-color: #a52834;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #ffffff;--bs-btn-disabled-bg: #dc3545;--bs-btn-disabled-border-color: #dc3545}.btn-light{--bs-btn-color: #000;--bs-btn-bg: #f8f9fa;--bs-btn-border-color: #f8f9fa;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #d3d4d5;--bs-btn-hover-border-color: #c6c7c8;--bs-btn-focus-shadow-rgb: 211, 212, 213;--bs-btn-active-color: #000;--bs-btn-active-bg: #c6c7c8;--bs-btn-active-border-color: #babbbc;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #000;--bs-btn-disabled-bg: #f8f9fa;--bs-btn-disabled-border-color: #f8f9fa}.btn-dark{--bs-btn-color: #ffffff;--bs-btn-bg: #212529;--bs-btn-border-color: #212529;--bs-btn-hover-color: #ffffff;--bs-btn-hover-bg: #424649;--bs-btn-hover-border-color: #373b3e;--bs-btn-focus-shadow-rgb: 66, 70, 73;--bs-btn-active-color: #ffffff;--bs-btn-active-bg: #4d5154;--bs-btn-active-border-color: #373b3e;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #ffffff;--bs-btn-disabled-bg: #212529;--bs-btn-disabled-border-color: #212529}.btn-outline-default{--bs-btn-color: #dee2e6;--bs-btn-border-color: #dee2e6;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #dee2e6;--bs-btn-hover-border-color: #dee2e6;--bs-btn-focus-shadow-rgb: 222, 226, 230;--bs-btn-active-color: #000;--bs-btn-active-bg: #dee2e6;--bs-btn-active-border-color: #dee2e6;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #dee2e6;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #dee2e6;--bs-btn-bg: transparent;--bs-gradient: none}.btn-outline-primary{--bs-btn-color: #0d6efd;--bs-btn-border-color: #0d6efd;--bs-btn-hover-color: #ffffff;--bs-btn-hover-bg: #0d6efd;--bs-btn-hover-border-color: #0d6efd;--bs-btn-focus-shadow-rgb: 13, 110, 253;--bs-btn-active-color: #ffffff;--bs-btn-active-bg: #0d6efd;--bs-btn-active-border-color: #0d6efd;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #0d6efd;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #0d6efd;--bs-btn-bg: transparent;--bs-gradient: none}.btn-outline-secondary{--bs-btn-color: #6c757d;--bs-btn-border-color: #6c757d;--bs-btn-hover-color: #ffffff;--bs-btn-hover-bg: #6c757d;--bs-btn-hover-border-color: #6c757d;--bs-btn-focus-shadow-rgb: 108, 117, 125;--bs-btn-active-color: #ffffff;--bs-btn-active-bg: #6c757d;--bs-btn-active-border-color: #6c757d;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #6c757d;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #6c757d;--bs-btn-bg: transparent;--bs-gradient: none}.btn-outline-success{--bs-btn-color: #198754;--bs-btn-border-color: #198754;--bs-btn-hover-color: #ffffff;--bs-btn-hover-bg: #198754;--bs-btn-hover-border-color: #198754;--bs-btn-focus-shadow-rgb: 25, 135, 84;--bs-btn-active-color: #ffffff;--bs-btn-active-bg: #198754;--bs-btn-active-border-color: #198754;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #198754;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #198754;--bs-btn-bg: transparent;--bs-gradient: none}.btn-outline-info{--bs-btn-color: #0dcaf0;--bs-btn-border-color: #0dcaf0;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #0dcaf0;--bs-btn-hover-border-color: #0dcaf0;--bs-btn-focus-shadow-rgb: 13, 202, 240;--bs-btn-active-color: #000;--bs-btn-active-bg: #0dcaf0;--bs-btn-active-border-color: #0dcaf0;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #0dcaf0;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #0dcaf0;--bs-btn-bg: transparent;--bs-gradient: none}.btn-outline-warning{--bs-btn-color: #ffc107;--bs-btn-border-color: #ffc107;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #ffc107;--bs-btn-hover-border-color: #ffc107;--bs-btn-focus-shadow-rgb: 255, 193, 7;--bs-btn-active-color: #000;--bs-btn-active-bg: #ffc107;--bs-btn-active-border-color: #ffc107;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #ffc107;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #ffc107;--bs-btn-bg: transparent;--bs-gradient: none}.btn-outline-danger{--bs-btn-color: #dc3545;--bs-btn-border-color: #dc3545;--bs-btn-hover-color: #ffffff;--bs-btn-hover-bg: #dc3545;--bs-btn-hover-border-color: #dc3545;--bs-btn-focus-shadow-rgb: 220, 53, 69;--bs-btn-active-color: #ffffff;--bs-btn-active-bg: #dc3545;--bs-btn-active-border-color: #dc3545;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #dc3545;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #dc3545;--bs-btn-bg: transparent;--bs-gradient: none}.btn-outline-light{--bs-btn-color: #f8f9fa;--bs-btn-border-color: #f8f9fa;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #f8f9fa;--bs-btn-hover-border-color: #f8f9fa;--bs-btn-focus-shadow-rgb: 248, 249, 250;--bs-btn-active-color: #000;--bs-btn-active-bg: #f8f9fa;--bs-btn-active-border-color: #f8f9fa;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #f8f9fa;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #f8f9fa;--bs-btn-bg: transparent;--bs-gradient: none}.btn-outline-dark{--bs-btn-color: #212529;--bs-btn-border-color: #212529;--bs-btn-hover-color: #ffffff;--bs-btn-hover-bg: #212529;--bs-btn-hover-border-color: #212529;--bs-btn-focus-shadow-rgb: 33, 37, 41;--bs-btn-active-color: #ffffff;--bs-btn-active-bg: #212529;--bs-btn-active-border-color: #212529;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #212529;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #212529;--bs-btn-bg: transparent;--bs-gradient: none}.btn-link{--bs-btn-font-weight: 400;--bs-btn-color: #0d6efd;--bs-btn-bg: transparent;--bs-btn-border-color: transparent;--bs-btn-hover-color: #0a58ca;--bs-btn-hover-border-color: transparent;--bs-btn-active-color: #0a58ca;--bs-btn-active-border-color: transparent;--bs-btn-disabled-color: #6c757d;--bs-btn-disabled-border-color: transparent;--bs-btn-box-shadow: 0 0 0 #000;--bs-btn-focus-shadow-rgb: 49, 132, 253;text-decoration:underline;-webkit-text-decoration:underline;-moz-text-decoration:underline;-ms-text-decoration:underline;-o-text-decoration:underline}.btn-link:focus-visible{color:var(--bs-btn-color)}.btn-link:hover{color:var(--bs-btn-hover-color)}.btn-lg,.btn-group-lg>.btn{--bs-btn-padding-y: 0.5rem;--bs-btn-padding-x: 1rem;--bs-btn-font-size:1.25rem;--bs-btn-border-radius: 0.5rem}.btn-sm,.btn-group-sm>.btn{--bs-btn-padding-y: 0.25rem;--bs-btn-padding-x: 0.5rem;--bs-btn-font-size:0.875rem;--bs-btn-border-radius: 0.25rem}.fade{transition:opacity .15s linear}@media(prefers-reduced-motion: reduce){.fade{transition:none}}.fade:not(.show){opacity:0}.collapse:not(.show){display:none}.collapsing{height:0;overflow:hidden;transition:height .2s ease}@media(prefers-reduced-motion: reduce){.collapsing{transition:none}}.collapsing.collapse-horizontal{width:0;height:auto;transition:width .35s ease}@media(prefers-reduced-motion: reduce){.collapsing.collapse-horizontal{transition:none}}.dropup,.dropend,.dropdown,.dropstart,.dropup-center,.dropdown-center{position:relative}.dropdown-toggle{white-space:nowrap}.dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid rgba(0,0,0,0);border-bottom:0;border-left:.3em solid rgba(0,0,0,0)}.dropdown-toggle:empty::after{margin-left:0}.dropdown-menu{--bs-dropdown-zindex: 1000;--bs-dropdown-min-width: 10rem;--bs-dropdown-padding-x: 0;--bs-dropdown-padding-y: 0.5rem;--bs-dropdown-spacer: 0.125rem;--bs-dropdown-font-size:1rem;--bs-dropdown-color: #212529;--bs-dropdown-bg: #ffffff;--bs-dropdown-border-color: rgba(0, 0, 0, 0.175);--bs-dropdown-border-radius: 0.375rem;--bs-dropdown-border-width: 1px;--bs-dropdown-inner-border-radius: calc(0.375rem - 1px);--bs-dropdown-divider-bg: rgba(0, 0, 0, 0.175);--bs-dropdown-divider-margin-y: 0.5rem;--bs-dropdown-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);--bs-dropdown-link-color: #212529;--bs-dropdown-link-hover-color: #212529;--bs-dropdown-link-hover-bg: #f8f9fa;--bs-dropdown-link-active-color: #ffffff;--bs-dropdown-link-active-bg: #0d6efd;--bs-dropdown-link-disabled-color: rgba(33, 37, 41, 0.5);--bs-dropdown-item-padding-x: 1rem;--bs-dropdown-item-padding-y: 0.25rem;--bs-dropdown-header-color: #6c757d;--bs-dropdown-header-padding-x: 1rem;--bs-dropdown-header-padding-y: 0.5rem;position:absolute;z-index:var(--bs-dropdown-zindex);display:none;min-width:var(--bs-dropdown-min-width);padding:var(--bs-dropdown-padding-y) var(--bs-dropdown-padding-x);margin:0;font-size:var(--bs-dropdown-font-size);color:var(--bs-dropdown-color);text-align:left;list-style:none;background-color:var(--bs-dropdown-bg);background-clip:padding-box;border:var(--bs-dropdown-border-width) solid var(--bs-dropdown-border-color);border-radius:var(--bs-dropdown-border-radius)}.dropdown-menu[data-bs-popper]{top:100%;left:0;margin-top:var(--bs-dropdown-spacer)}.dropdown-menu-start{--bs-position: start}.dropdown-menu-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-end{--bs-position: end}.dropdown-menu-end[data-bs-popper]{right:0;left:auto}@media(min-width: 576px){.dropdown-menu-sm-start{--bs-position: start}.dropdown-menu-sm-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-sm-end{--bs-position: end}.dropdown-menu-sm-end[data-bs-popper]{right:0;left:auto}}@media(min-width: 768px){.dropdown-menu-md-start{--bs-position: start}.dropdown-menu-md-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-md-end{--bs-position: end}.dropdown-menu-md-end[data-bs-popper]{right:0;left:auto}}@media(min-width: 992px){.dropdown-menu-lg-start{--bs-position: start}.dropdown-menu-lg-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-lg-end{--bs-position: end}.dropdown-menu-lg-end[data-bs-popper]{right:0;left:auto}}@media(min-width: 1200px){.dropdown-menu-xl-start{--bs-position: start}.dropdown-menu-xl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xl-end{--bs-position: end}.dropdown-menu-xl-end[data-bs-popper]{right:0;left:auto}}@media(min-width: 1400px){.dropdown-menu-xxl-start{--bs-position: start}.dropdown-menu-xxl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xxl-end{--bs-position: end}.dropdown-menu-xxl-end[data-bs-popper]{right:0;left:auto}}.dropup .dropdown-menu[data-bs-popper]{top:auto;bottom:100%;margin-top:0;margin-bottom:var(--bs-dropdown-spacer)}.dropup .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid rgba(0,0,0,0);border-bottom:.3em solid;border-left:.3em solid rgba(0,0,0,0)}.dropup .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-menu[data-bs-popper]{top:0;right:auto;left:100%;margin-top:0;margin-left:var(--bs-dropdown-spacer)}.dropend .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid rgba(0,0,0,0);border-right:0;border-bottom:.3em solid rgba(0,0,0,0);border-left:.3em solid}.dropend .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-toggle::after{vertical-align:0}.dropstart .dropdown-menu[data-bs-popper]{top:0;right:100%;left:auto;margin-top:0;margin-right:var(--bs-dropdown-spacer)}.dropstart .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:""}.dropstart .dropdown-toggle::after{display:none}.dropstart .dropdown-toggle::before{display:inline-block;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid rgba(0,0,0,0);border-right:.3em solid;border-bottom:.3em solid rgba(0,0,0,0)}.dropstart .dropdown-toggle:empty::after{margin-left:0}.dropstart .dropdown-toggle::before{vertical-align:0}.dropdown-divider{height:0;margin:var(--bs-dropdown-divider-margin-y) 0;overflow:hidden;border-top:1px solid var(--bs-dropdown-divider-bg);opacity:1}.dropdown-item{display:block;width:100%;padding:var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x);clear:both;font-weight:400;color:var(--bs-dropdown-link-color);text-align:inherit;text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;white-space:nowrap;background-color:rgba(0,0,0,0);border:0;border-radius:var(--bs-dropdown-item-border-radius, 0)}.dropdown-item:hover,.dropdown-item:focus{color:var(--bs-dropdown-link-hover-color);background-color:var(--bs-dropdown-link-hover-bg)}.dropdown-item.active,.dropdown-item:active{color:var(--bs-dropdown-link-active-color);text-decoration:none;background-color:var(--bs-dropdown-link-active-bg)}.dropdown-item.disabled,.dropdown-item:disabled{color:var(--bs-dropdown-link-disabled-color);pointer-events:none;background-color:rgba(0,0,0,0)}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:var(--bs-dropdown-header-padding-y) var(--bs-dropdown-header-padding-x);margin-bottom:0;font-size:0.875rem;color:var(--bs-dropdown-header-color);white-space:nowrap}.dropdown-item-text{display:block;padding:var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x);color:var(--bs-dropdown-link-color)}.dropdown-menu-dark{--bs-dropdown-color: #dee2e6;--bs-dropdown-bg: #343a40;--bs-dropdown-border-color: rgba(0, 0, 0, 0.175);--bs-dropdown-box-shadow: ;--bs-dropdown-link-color: #dee2e6;--bs-dropdown-link-hover-color: #ffffff;--bs-dropdown-divider-bg: rgba(0, 0, 0, 0.175);--bs-dropdown-link-hover-bg: rgba(255, 255, 255, 0.15);--bs-dropdown-link-active-color: #ffffff;--bs-dropdown-link-active-bg: #0d6efd;--bs-dropdown-link-disabled-color: #adb5bd;--bs-dropdown-header-color: #adb5bd}.btn-group,.btn-group-vertical{position:relative;display:inline-flex;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;flex:1 1 auto;-webkit-flex:1 1 auto}.btn-group>.btn-check:checked+.btn,.btn-group>.btn-check:focus+.btn,.btn-group>.btn:hover,.btn-group>.btn:focus,.btn-group>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn-check:checked+.btn,.btn-group-vertical>.btn-check:focus+.btn,.btn-group-vertical>.btn:hover,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn.active{z-index:1}.btn-toolbar{display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;justify-content:flex-start;-webkit-justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group{border-radius:.375rem}.btn-group>:not(.btn-check:first-child)+.btn,.btn-group>.btn-group:not(:first-child){margin-left:calc(1px*-1)}.btn-group>.btn:not(:last-child):not(.dropdown-toggle),.btn-group>.btn.dropdown-toggle-split:first-child,.btn-group>.btn-group:not(:last-child)>.btn{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:nth-child(n+3),.btn-group>:not(.btn-check)+.btn,.btn-group>.btn-group:not(:first-child)>.btn{border-top-left-radius:0;border-bottom-left-radius:0}.dropdown-toggle-split{padding-right:.5625rem;padding-left:.5625rem}.dropdown-toggle-split::after,.dropup .dropdown-toggle-split::after,.dropend .dropdown-toggle-split::after{margin-left:0}.dropstart .dropdown-toggle-split::before{margin-right:0}.btn-sm+.dropdown-toggle-split,.btn-group-sm>.btn+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-lg+.dropdown-toggle-split,.btn-group-lg>.btn+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.btn-group-vertical{flex-direction:column;-webkit-flex-direction:column;align-items:flex-start;-webkit-align-items:flex-start;justify-content:center;-webkit-justify-content:center}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group{width:100%}.btn-group-vertical>.btn:not(:first-child),.btn-group-vertical>.btn-group:not(:first-child){margin-top:calc(1px*-1)}.btn-group-vertical>.btn:not(:last-child):not(.dropdown-toggle),.btn-group-vertical>.btn-group:not(:last-child)>.btn{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn~.btn,.btn-group-vertical>.btn-group:not(:first-child)>.btn{border-top-left-radius:0;border-top-right-radius:0}.nav{--bs-nav-link-padding-x: 1rem;--bs-nav-link-padding-y: 0.5rem;--bs-nav-link-font-weight: ;--bs-nav-link-color: #0d6efd;--bs-nav-link-hover-color: #0a58ca;--bs-nav-link-disabled-color: rgba(33, 37, 41, 0.75);display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:var(--bs-nav-link-padding-y) var(--bs-nav-link-padding-x);font-size:var(--bs-nav-link-font-size);font-weight:var(--bs-nav-link-font-weight);color:var(--bs-nav-link-color);text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;background:none;border:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out}@media(prefers-reduced-motion: reduce){.nav-link{transition:none}}.nav-link:hover,.nav-link:focus{color:var(--bs-nav-link-hover-color)}.nav-link:focus-visible{outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.nav-link.disabled,.nav-link:disabled{color:var(--bs-nav-link-disabled-color);pointer-events:none;cursor:default}.nav-tabs{--bs-nav-tabs-border-width: 1px;--bs-nav-tabs-border-color: #dee2e6;--bs-nav-tabs-border-radius: 0.375rem;--bs-nav-tabs-link-hover-border-color: #e9ecef #e9ecef #dee2e6;--bs-nav-tabs-link-active-color: #000;--bs-nav-tabs-link-active-bg: #ffffff;--bs-nav-tabs-link-active-border-color: #dee2e6 #dee2e6 #ffffff;border-bottom:var(--bs-nav-tabs-border-width) solid var(--bs-nav-tabs-border-color)}.nav-tabs .nav-link{margin-bottom:calc(-1*var(--bs-nav-tabs-border-width));border:var(--bs-nav-tabs-border-width) solid rgba(0,0,0,0);border-top-left-radius:var(--bs-nav-tabs-border-radius);border-top-right-radius:var(--bs-nav-tabs-border-radius)}.nav-tabs .nav-link:hover,.nav-tabs .nav-link:focus{isolation:isolate;border-color:var(--bs-nav-tabs-link-hover-border-color)}.nav-tabs .nav-link.active,.nav-tabs .nav-item.show .nav-link{color:var(--bs-nav-tabs-link-active-color);background-color:var(--bs-nav-tabs-link-active-bg);border-color:var(--bs-nav-tabs-link-active-border-color)}.nav-tabs .dropdown-menu{margin-top:calc(-1*var(--bs-nav-tabs-border-width));border-top-left-radius:0;border-top-right-radius:0}.nav-pills{--bs-nav-pills-border-radius: 0.375rem;--bs-nav-pills-link-active-color: #ffffff;--bs-nav-pills-link-active-bg: #0d6efd}.nav-pills .nav-link{border-radius:var(--bs-nav-pills-border-radius)}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:var(--bs-nav-pills-link-active-color);background-color:var(--bs-nav-pills-link-active-bg)}.nav-underline{--bs-nav-underline-gap: 1rem;--bs-nav-underline-border-width: 0.125rem;--bs-nav-underline-link-active-color: #000;gap:var(--bs-nav-underline-gap)}.nav-underline .nav-link{padding-right:0;padding-left:0;border-bottom:var(--bs-nav-underline-border-width) solid rgba(0,0,0,0)}.nav-underline .nav-link:hover,.nav-underline .nav-link:focus{border-bottom-color:currentcolor}.nav-underline .nav-link.active,.nav-underline .show>.nav-link{font-weight:700;color:var(--bs-nav-underline-link-active-color);border-bottom-color:currentcolor}.nav-fill>.nav-link,.nav-fill .nav-item{flex:1 1 auto;-webkit-flex:1 1 auto;text-align:center}.nav-justified>.nav-link,.nav-justified .nav-item{flex-basis:0;-webkit-flex-basis:0;flex-grow:1;-webkit-flex-grow:1;text-align:center}.nav-fill .nav-item .nav-link,.nav-justified .nav-item .nav-link{width:100%}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{--bs-navbar-padding-x: 0;--bs-navbar-padding-y: 0.5rem;--bs-navbar-color: #fdfefe;--bs-navbar-hover-color: rgba(253, 254, 255, 0.8);--bs-navbar-disabled-color: rgba(253, 254, 254, 0.75);--bs-navbar-active-color: #fdfeff;--bs-navbar-brand-padding-y: 0.3125rem;--bs-navbar-brand-margin-end: 1rem;--bs-navbar-brand-font-size: 1.25rem;--bs-navbar-brand-color: #fdfefe;--bs-navbar-brand-hover-color: #fdfeff;--bs-navbar-nav-link-padding-x: 0.5rem;--bs-navbar-toggler-padding-y: 0.25;--bs-navbar-toggler-padding-x: 0;--bs-navbar-toggler-font-size: 1.25rem;--bs-navbar-toggler-icon-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='%23fdfefe' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e");--bs-navbar-toggler-border-color: rgba(253, 254, 254, 0);--bs-navbar-toggler-border-radius: 0.375rem;--bs-navbar-toggler-focus-width: 0.25rem;--bs-navbar-toggler-transition: box-shadow 0.15s ease-in-out;position:relative;display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;align-items:center;-webkit-align-items:center;justify-content:space-between;-webkit-justify-content:space-between;padding:var(--bs-navbar-padding-y) var(--bs-navbar-padding-x)}.navbar>.container,.navbar>.container-fluid,.navbar>.container-sm,.navbar>.container-md,.navbar>.container-lg,.navbar>.container-xl,.navbar>.container-xxl{display:flex;display:-webkit-flex;flex-wrap:inherit;-webkit-flex-wrap:inherit;align-items:center;-webkit-align-items:center;justify-content:space-between;-webkit-justify-content:space-between}.navbar-brand{padding-top:var(--bs-navbar-brand-padding-y);padding-bottom:var(--bs-navbar-brand-padding-y);margin-right:var(--bs-navbar-brand-margin-end);font-size:var(--bs-navbar-brand-font-size);color:var(--bs-navbar-brand-color);text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;white-space:nowrap}.navbar-brand:hover,.navbar-brand:focus{color:var(--bs-navbar-brand-hover-color)}.navbar-nav{--bs-nav-link-padding-x: 0;--bs-nav-link-padding-y: 0.5rem;--bs-nav-link-font-weight: ;--bs-nav-link-color: var(--bs-navbar-color);--bs-nav-link-hover-color: var(--bs-navbar-hover-color);--bs-nav-link-disabled-color: var(--bs-navbar-disabled-color);display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link.active,.navbar-nav .nav-link.show{color:var(--bs-navbar-active-color)}.navbar-nav .dropdown-menu{position:static}.navbar-text{padding-top:.5rem;padding-bottom:.5rem;color:var(--bs-navbar-color)}.navbar-text a,.navbar-text a:hover,.navbar-text a:focus{color:var(--bs-navbar-active-color)}.navbar-collapse{flex-basis:100%;-webkit-flex-basis:100%;flex-grow:1;-webkit-flex-grow:1;align-items:center;-webkit-align-items:center}.navbar-toggler{padding:var(--bs-navbar-toggler-padding-y) var(--bs-navbar-toggler-padding-x);font-size:var(--bs-navbar-toggler-font-size);line-height:1;color:var(--bs-navbar-color);background-color:rgba(0,0,0,0);border:var(--bs-border-width) solid var(--bs-navbar-toggler-border-color);border-radius:var(--bs-navbar-toggler-border-radius);transition:var(--bs-navbar-toggler-transition)}@media(prefers-reduced-motion: reduce){.navbar-toggler{transition:none}}.navbar-toggler:hover{text-decoration:none}.navbar-toggler:focus{text-decoration:none;outline:0;box-shadow:0 0 0 var(--bs-navbar-toggler-focus-width)}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;background-image:var(--bs-navbar-toggler-icon-bg);background-repeat:no-repeat;background-position:center;background-size:100%}.navbar-nav-scroll{max-height:var(--bs-scroll-height, 75vh);overflow-y:auto}@media(min-width: 576px){.navbar-expand-sm{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand-sm .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-sm .navbar-nav-scroll{overflow:visible}.navbar-expand-sm .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}.navbar-expand-sm .offcanvas{position:static;z-index:auto;flex-grow:1;-webkit-flex-grow:1;width:auto !important;height:auto !important;visibility:visible !important;background-color:rgba(0,0,0,0) !important;border:0 !important;transform:none !important;transition:none}.navbar-expand-sm .offcanvas .offcanvas-header{display:none}.navbar-expand-sm .offcanvas .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}}@media(min-width: 768px){.navbar-expand-md{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand-md .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-md .navbar-nav-scroll{overflow:visible}.navbar-expand-md .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}.navbar-expand-md .offcanvas{position:static;z-index:auto;flex-grow:1;-webkit-flex-grow:1;width:auto !important;height:auto !important;visibility:visible !important;background-color:rgba(0,0,0,0) !important;border:0 !important;transform:none !important;transition:none}.navbar-expand-md .offcanvas .offcanvas-header{display:none}.navbar-expand-md .offcanvas .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}}@media(min-width: 992px){.navbar-expand-lg{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand-lg .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-lg .navbar-nav-scroll{overflow:visible}.navbar-expand-lg .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}.navbar-expand-lg .offcanvas{position:static;z-index:auto;flex-grow:1;-webkit-flex-grow:1;width:auto !important;height:auto !important;visibility:visible !important;background-color:rgba(0,0,0,0) !important;border:0 !important;transform:none !important;transition:none}.navbar-expand-lg .offcanvas .offcanvas-header{display:none}.navbar-expand-lg .offcanvas .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}}@media(min-width: 1200px){.navbar-expand-xl{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand-xl .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-xl .navbar-nav-scroll{overflow:visible}.navbar-expand-xl .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}.navbar-expand-xl .offcanvas{position:static;z-index:auto;flex-grow:1;-webkit-flex-grow:1;width:auto !important;height:auto !important;visibility:visible !important;background-color:rgba(0,0,0,0) !important;border:0 !important;transform:none !important;transition:none}.navbar-expand-xl .offcanvas .offcanvas-header{display:none}.navbar-expand-xl .offcanvas .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}}@media(min-width: 1400px){.navbar-expand-xxl{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand-xxl .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand-xxl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xxl .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-xxl .navbar-nav-scroll{overflow:visible}.navbar-expand-xxl .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand-xxl .navbar-toggler{display:none}.navbar-expand-xxl .offcanvas{position:static;z-index:auto;flex-grow:1;-webkit-flex-grow:1;width:auto !important;height:auto !important;visibility:visible !important;background-color:rgba(0,0,0,0) !important;border:0 !important;transform:none !important;transition:none}.navbar-expand-xxl .offcanvas .offcanvas-header{display:none}.navbar-expand-xxl .offcanvas .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}}.navbar-expand{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand .navbar-nav-scroll{overflow:visible}.navbar-expand .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-expand .offcanvas{position:static;z-index:auto;flex-grow:1;-webkit-flex-grow:1;width:auto !important;height:auto !important;visibility:visible !important;background-color:rgba(0,0,0,0) !important;border:0 !important;transform:none !important;transition:none}.navbar-expand .offcanvas .offcanvas-header{display:none}.navbar-expand .offcanvas .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}.navbar-dark,.navbar[data-bs-theme=dark]{--bs-navbar-color: #fdfefe;--bs-navbar-hover-color: rgba(253, 254, 255, 0.8);--bs-navbar-disabled-color: rgba(253, 254, 254, 0.75);--bs-navbar-active-color: #fdfeff;--bs-navbar-brand-color: #fdfefe;--bs-navbar-brand-hover-color: #fdfeff;--bs-navbar-toggler-border-color: rgba(253, 254, 254, 0);--bs-navbar-toggler-icon-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='%23fdfefe' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}[data-bs-theme=dark] .navbar-toggler-icon{--bs-navbar-toggler-icon-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='%23fdfefe' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.card{--bs-card-spacer-y: 1rem;--bs-card-spacer-x: 1rem;--bs-card-title-spacer-y: 0.5rem;--bs-card-title-color: ;--bs-card-subtitle-color: ;--bs-card-border-width: 1px;--bs-card-border-color: rgba(0, 0, 0, 0.175);--bs-card-border-radius: 0.375rem;--bs-card-box-shadow: ;--bs-card-inner-border-radius: calc(0.375rem - 1px);--bs-card-cap-padding-y: 0.5rem;--bs-card-cap-padding-x: 1rem;--bs-card-cap-bg: rgba(33, 37, 41, 0.03);--bs-card-cap-color: ;--bs-card-height: ;--bs-card-color: ;--bs-card-bg: #ffffff;--bs-card-img-overlay-padding: 1rem;--bs-card-group-margin: 0.75rem;position:relative;display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;min-width:0;height:var(--bs-card-height);color:var(--bs-body-color);word-wrap:break-word;background-color:var(--bs-card-bg);background-clip:border-box;border:var(--bs-card-border-width) solid var(--bs-card-border-color);border-radius:var(--bs-card-border-radius)}.card>hr{margin-right:0;margin-left:0}.card>.list-group{border-top:inherit;border-bottom:inherit}.card>.list-group:first-child{border-top-width:0;border-top-left-radius:var(--bs-card-inner-border-radius);border-top-right-radius:var(--bs-card-inner-border-radius)}.card>.list-group:last-child{border-bottom-width:0;border-bottom-right-radius:var(--bs-card-inner-border-radius);border-bottom-left-radius:var(--bs-card-inner-border-radius)}.card>.card-header+.list-group,.card>.list-group+.card-footer{border-top:0}.card-body{flex:1 1 auto;-webkit-flex:1 1 auto;padding:var(--bs-card-spacer-y) var(--bs-card-spacer-x);color:var(--bs-card-color)}.card-title{margin-bottom:var(--bs-card-title-spacer-y);color:var(--bs-card-title-color)}.card-subtitle{margin-top:calc(-0.5*var(--bs-card-title-spacer-y));margin-bottom:0;color:var(--bs-card-subtitle-color)}.card-text:last-child{margin-bottom:0}.card-link+.card-link{margin-left:var(--bs-card-spacer-x)}.card-header{padding:var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x);margin-bottom:0;color:var(--bs-card-cap-color);background-color:var(--bs-card-cap-bg);border-bottom:var(--bs-card-border-width) solid var(--bs-card-border-color)}.card-header:first-child{border-radius:var(--bs-card-inner-border-radius) var(--bs-card-inner-border-radius) 0 0}.card-footer{padding:var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x);color:var(--bs-card-cap-color);background-color:var(--bs-card-cap-bg);border-top:var(--bs-card-border-width) solid var(--bs-card-border-color)}.card-footer:last-child{border-radius:0 0 var(--bs-card-inner-border-radius) var(--bs-card-inner-border-radius)}.card-header-tabs{margin-right:calc(-0.5*var(--bs-card-cap-padding-x));margin-bottom:calc(-1*var(--bs-card-cap-padding-y));margin-left:calc(-0.5*var(--bs-card-cap-padding-x));border-bottom:0}.card-header-tabs .nav-link.active{background-color:var(--bs-card-bg);border-bottom-color:var(--bs-card-bg)}.card-header-pills{margin-right:calc(-0.5*var(--bs-card-cap-padding-x));margin-left:calc(-0.5*var(--bs-card-cap-padding-x))}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:var(--bs-card-img-overlay-padding);border-radius:var(--bs-card-inner-border-radius)}.card-img,.card-img-top,.card-img-bottom{width:100%}.card-img,.card-img-top{border-top-left-radius:var(--bs-card-inner-border-radius);border-top-right-radius:var(--bs-card-inner-border-radius)}.card-img,.card-img-bottom{border-bottom-right-radius:var(--bs-card-inner-border-radius);border-bottom-left-radius:var(--bs-card-inner-border-radius)}.card-group>.card{margin-bottom:var(--bs-card-group-margin)}@media(min-width: 576px){.card-group{display:flex;display:-webkit-flex;flex-flow:row wrap;-webkit-flex-flow:row wrap}.card-group>.card{flex:1 0 0%;-webkit-flex:1 0 0%;margin-bottom:0}.card-group>.card+.card{margin-left:0;border-left:0}.card-group>.card:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.card-group>.card:not(:last-child) .card-img-top,.card-group>.card:not(:last-child) .card-header{border-top-right-radius:0}.card-group>.card:not(:last-child) .card-img-bottom,.card-group>.card:not(:last-child) .card-footer{border-bottom-right-radius:0}.card-group>.card:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.card-group>.card:not(:first-child) .card-img-top,.card-group>.card:not(:first-child) .card-header{border-top-left-radius:0}.card-group>.card:not(:first-child) .card-img-bottom,.card-group>.card:not(:first-child) .card-footer{border-bottom-left-radius:0}}.accordion{--bs-accordion-color: #212529;--bs-accordion-bg: #ffffff;--bs-accordion-transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out, border-radius 0.15s ease;--bs-accordion-border-color: #dee2e6;--bs-accordion-border-width: 1px;--bs-accordion-border-radius: 0.375rem;--bs-accordion-inner-border-radius: calc(0.375rem - 1px);--bs-accordion-btn-padding-x: 1.25rem;--bs-accordion-btn-padding-y: 1rem;--bs-accordion-btn-color: #212529;--bs-accordion-btn-bg: #ffffff;--bs-accordion-btn-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23212529'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");--bs-accordion-btn-icon-width: 1.25rem;--bs-accordion-btn-icon-transform: rotate(-180deg);--bs-accordion-btn-icon-transition: transform 0.2s ease-in-out;--bs-accordion-btn-active-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23052c65'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");--bs-accordion-btn-focus-border-color: #86b7fe;--bs-accordion-btn-focus-box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);--bs-accordion-body-padding-x: 1.25rem;--bs-accordion-body-padding-y: 1rem;--bs-accordion-active-color: #052c65;--bs-accordion-active-bg: #cfe2ff}.accordion-button{position:relative;display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;width:100%;padding:var(--bs-accordion-btn-padding-y) var(--bs-accordion-btn-padding-x);font-size:1rem;color:var(--bs-accordion-btn-color);text-align:left;background-color:var(--bs-accordion-btn-bg);border:0;border-radius:0;overflow-anchor:none;transition:var(--bs-accordion-transition)}@media(prefers-reduced-motion: reduce){.accordion-button{transition:none}}.accordion-button:not(.collapsed){color:var(--bs-accordion-active-color);background-color:var(--bs-accordion-active-bg);box-shadow:inset 0 calc(-1*var(--bs-accordion-border-width)) 0 var(--bs-accordion-border-color)}.accordion-button:not(.collapsed)::after{background-image:var(--bs-accordion-btn-active-icon);transform:var(--bs-accordion-btn-icon-transform)}.accordion-button::after{flex-shrink:0;-webkit-flex-shrink:0;width:var(--bs-accordion-btn-icon-width);height:var(--bs-accordion-btn-icon-width);margin-left:auto;content:"";background-image:var(--bs-accordion-btn-icon);background-repeat:no-repeat;background-size:var(--bs-accordion-btn-icon-width);transition:var(--bs-accordion-btn-icon-transition)}@media(prefers-reduced-motion: reduce){.accordion-button::after{transition:none}}.accordion-button:hover{z-index:2}.accordion-button:focus{z-index:3;border-color:var(--bs-accordion-btn-focus-border-color);outline:0;box-shadow:var(--bs-accordion-btn-focus-box-shadow)}.accordion-header{margin-bottom:0}.accordion-item{color:var(--bs-accordion-color);background-color:var(--bs-accordion-bg);border:var(--bs-accordion-border-width) solid var(--bs-accordion-border-color)}.accordion-item:first-of-type{border-top-left-radius:var(--bs-accordion-border-radius);border-top-right-radius:var(--bs-accordion-border-radius)}.accordion-item:first-of-type .accordion-button{border-top-left-radius:var(--bs-accordion-inner-border-radius);border-top-right-radius:var(--bs-accordion-inner-border-radius)}.accordion-item:not(:first-of-type){border-top:0}.accordion-item:last-of-type{border-bottom-right-radius:var(--bs-accordion-border-radius);border-bottom-left-radius:var(--bs-accordion-border-radius)}.accordion-item:last-of-type .accordion-button.collapsed{border-bottom-right-radius:var(--bs-accordion-inner-border-radius);border-bottom-left-radius:var(--bs-accordion-inner-border-radius)}.accordion-item:last-of-type .accordion-collapse{border-bottom-right-radius:var(--bs-accordion-border-radius);border-bottom-left-radius:var(--bs-accordion-border-radius)}.accordion-body{padding:var(--bs-accordion-body-padding-y) var(--bs-accordion-body-padding-x)}.accordion-flush .accordion-collapse{border-width:0}.accordion-flush .accordion-item{border-right:0;border-left:0;border-radius:0}.accordion-flush .accordion-item:first-child{border-top:0}.accordion-flush .accordion-item:last-child{border-bottom:0}.accordion-flush .accordion-item .accordion-button,.accordion-flush .accordion-item .accordion-button.collapsed{border-radius:0}[data-bs-theme=dark] .accordion-button::after{--bs-accordion-btn-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%236ea8fe'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");--bs-accordion-btn-active-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%236ea8fe'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e")}.breadcrumb{--bs-breadcrumb-padding-x: 0;--bs-breadcrumb-padding-y: 0;--bs-breadcrumb-margin-bottom: 1rem;--bs-breadcrumb-bg: ;--bs-breadcrumb-border-radius: ;--bs-breadcrumb-divider-color: rgba(33, 37, 41, 0.75);--bs-breadcrumb-item-padding-x: 0.5rem;--bs-breadcrumb-item-active-color: rgba(33, 37, 41, 0.75);display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;padding:var(--bs-breadcrumb-padding-y) var(--bs-breadcrumb-padding-x);margin-bottom:var(--bs-breadcrumb-margin-bottom);font-size:var(--bs-breadcrumb-font-size);list-style:none;background-color:var(--bs-breadcrumb-bg);border-radius:var(--bs-breadcrumb-border-radius)}.breadcrumb-item+.breadcrumb-item{padding-left:var(--bs-breadcrumb-item-padding-x)}.breadcrumb-item+.breadcrumb-item::before{float:left;padding-right:var(--bs-breadcrumb-item-padding-x);color:var(--bs-breadcrumb-divider-color);content:var(--bs-breadcrumb-divider, ">") /* rtl: var(--bs-breadcrumb-divider, ">") */}.breadcrumb-item.active{color:var(--bs-breadcrumb-item-active-color)}.pagination{--bs-pagination-padding-x: 0.75rem;--bs-pagination-padding-y: 0.375rem;--bs-pagination-font-size:1rem;--bs-pagination-color: #0d6efd;--bs-pagination-bg: #ffffff;--bs-pagination-border-width: 1px;--bs-pagination-border-color: #dee2e6;--bs-pagination-border-radius: 0.375rem;--bs-pagination-hover-color: #0a58ca;--bs-pagination-hover-bg: #f8f9fa;--bs-pagination-hover-border-color: #dee2e6;--bs-pagination-focus-color: #0a58ca;--bs-pagination-focus-bg: #e9ecef;--bs-pagination-focus-box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);--bs-pagination-active-color: #ffffff;--bs-pagination-active-bg: #0d6efd;--bs-pagination-active-border-color: #0d6efd;--bs-pagination-disabled-color: rgba(33, 37, 41, 0.75);--bs-pagination-disabled-bg: #e9ecef;--bs-pagination-disabled-border-color: #dee2e6;display:flex;display:-webkit-flex;padding-left:0;list-style:none}.page-link{position:relative;display:block;padding:var(--bs-pagination-padding-y) var(--bs-pagination-padding-x);font-size:var(--bs-pagination-font-size);color:var(--bs-pagination-color);text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;background-color:var(--bs-pagination-bg);border:var(--bs-pagination-border-width) solid var(--bs-pagination-border-color);transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.page-link{transition:none}}.page-link:hover{z-index:2;color:var(--bs-pagination-hover-color);background-color:var(--bs-pagination-hover-bg);border-color:var(--bs-pagination-hover-border-color)}.page-link:focus{z-index:3;color:var(--bs-pagination-focus-color);background-color:var(--bs-pagination-focus-bg);outline:0;box-shadow:var(--bs-pagination-focus-box-shadow)}.page-link.active,.active>.page-link{z-index:3;color:var(--bs-pagination-active-color);background-color:var(--bs-pagination-active-bg);border-color:var(--bs-pagination-active-border-color)}.page-link.disabled,.disabled>.page-link{color:var(--bs-pagination-disabled-color);pointer-events:none;background-color:var(--bs-pagination-disabled-bg);border-color:var(--bs-pagination-disabled-border-color)}.page-item:not(:first-child) .page-link{margin-left:calc(1px*-1)}.page-item:first-child .page-link{border-top-left-radius:var(--bs-pagination-border-radius);border-bottom-left-radius:var(--bs-pagination-border-radius)}.page-item:last-child .page-link{border-top-right-radius:var(--bs-pagination-border-radius);border-bottom-right-radius:var(--bs-pagination-border-radius)}.pagination-lg{--bs-pagination-padding-x: 1.5rem;--bs-pagination-padding-y: 0.75rem;--bs-pagination-font-size:1.25rem;--bs-pagination-border-radius: 0.5rem}.pagination-sm{--bs-pagination-padding-x: 0.5rem;--bs-pagination-padding-y: 0.25rem;--bs-pagination-font-size:0.875rem;--bs-pagination-border-radius: 0.25rem}.badge{--bs-badge-padding-x: 0.65em;--bs-badge-padding-y: 0.35em;--bs-badge-font-size:0.75em;--bs-badge-font-weight: 700;--bs-badge-color: #ffffff;--bs-badge-border-radius: 0.375rem;display:inline-block;padding:var(--bs-badge-padding-y) var(--bs-badge-padding-x);font-size:var(--bs-badge-font-size);font-weight:var(--bs-badge-font-weight);line-height:1;color:var(--bs-badge-color);text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:var(--bs-badge-border-radius)}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.alert{--bs-alert-bg: transparent;--bs-alert-padding-x: 1rem;--bs-alert-padding-y: 1rem;--bs-alert-margin-bottom: 1rem;--bs-alert-color: inherit;--bs-alert-border-color: transparent;--bs-alert-border: 1px solid var(--bs-alert-border-color);--bs-alert-border-radius: 0.375rem;--bs-alert-link-color: inherit;position:relative;padding:var(--bs-alert-padding-y) var(--bs-alert-padding-x);margin-bottom:var(--bs-alert-margin-bottom);color:var(--bs-alert-color);background-color:var(--bs-alert-bg);border:var(--bs-alert-border);border-radius:var(--bs-alert-border-radius)}.alert-heading{color:inherit}.alert-link{font-weight:700;color:var(--bs-alert-link-color)}.alert-dismissible{padding-right:3rem}.alert-dismissible .btn-close{position:absolute;top:0;right:0;z-index:2;padding:1.25rem 1rem}.alert-default{--bs-alert-color: var(--bs-default-text-emphasis);--bs-alert-bg: var(--bs-default-bg-subtle);--bs-alert-border-color: var(--bs-default-border-subtle);--bs-alert-link-color: var(--bs-default-text-emphasis)}.alert-primary{--bs-alert-color: var(--bs-primary-text-emphasis);--bs-alert-bg: var(--bs-primary-bg-subtle);--bs-alert-border-color: var(--bs-primary-border-subtle);--bs-alert-link-color: var(--bs-primary-text-emphasis)}.alert-secondary{--bs-alert-color: var(--bs-secondary-text-emphasis);--bs-alert-bg: var(--bs-secondary-bg-subtle);--bs-alert-border-color: var(--bs-secondary-border-subtle);--bs-alert-link-color: var(--bs-secondary-text-emphasis)}.alert-success{--bs-alert-color: var(--bs-success-text-emphasis);--bs-alert-bg: var(--bs-success-bg-subtle);--bs-alert-border-color: var(--bs-success-border-subtle);--bs-alert-link-color: var(--bs-success-text-emphasis)}.alert-info{--bs-alert-color: var(--bs-info-text-emphasis);--bs-alert-bg: var(--bs-info-bg-subtle);--bs-alert-border-color: var(--bs-info-border-subtle);--bs-alert-link-color: var(--bs-info-text-emphasis)}.alert-warning{--bs-alert-color: var(--bs-warning-text-emphasis);--bs-alert-bg: var(--bs-warning-bg-subtle);--bs-alert-border-color: var(--bs-warning-border-subtle);--bs-alert-link-color: var(--bs-warning-text-emphasis)}.alert-danger{--bs-alert-color: var(--bs-danger-text-emphasis);--bs-alert-bg: var(--bs-danger-bg-subtle);--bs-alert-border-color: var(--bs-danger-border-subtle);--bs-alert-link-color: var(--bs-danger-text-emphasis)}.alert-light{--bs-alert-color: var(--bs-light-text-emphasis);--bs-alert-bg: var(--bs-light-bg-subtle);--bs-alert-border-color: var(--bs-light-border-subtle);--bs-alert-link-color: var(--bs-light-text-emphasis)}.alert-dark{--bs-alert-color: var(--bs-dark-text-emphasis);--bs-alert-bg: var(--bs-dark-bg-subtle);--bs-alert-border-color: var(--bs-dark-border-subtle);--bs-alert-link-color: var(--bs-dark-text-emphasis)}@keyframes progress-bar-stripes{0%{background-position-x:1rem}}.progress,.progress-stacked{--bs-progress-height: 1rem;--bs-progress-font-size:0.75rem;--bs-progress-bg: #e9ecef;--bs-progress-border-radius: 0.375rem;--bs-progress-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.075);--bs-progress-bar-color: #ffffff;--bs-progress-bar-bg: #0d6efd;--bs-progress-bar-transition: width 0.6s ease;display:flex;display:-webkit-flex;height:var(--bs-progress-height);overflow:hidden;font-size:var(--bs-progress-font-size);background-color:var(--bs-progress-bg);border-radius:var(--bs-progress-border-radius)}.progress-bar{display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;justify-content:center;-webkit-justify-content:center;overflow:hidden;color:var(--bs-progress-bar-color);text-align:center;white-space:nowrap;background-color:var(--bs-progress-bar-bg);transition:var(--bs-progress-bar-transition)}@media(prefers-reduced-motion: reduce){.progress-bar{transition:none}}.progress-bar-striped{background-image:linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-size:var(--bs-progress-height) var(--bs-progress-height)}.progress-stacked>.progress{overflow:visible}.progress-stacked>.progress>.progress-bar{width:100%}.progress-bar-animated{animation:1s linear infinite progress-bar-stripes}@media(prefers-reduced-motion: reduce){.progress-bar-animated{animation:none}}.list-group{--bs-list-group-color: #212529;--bs-list-group-bg: #ffffff;--bs-list-group-border-color: #dee2e6;--bs-list-group-border-width: 1px;--bs-list-group-border-radius: 0.375rem;--bs-list-group-item-padding-x: 1rem;--bs-list-group-item-padding-y: 0.5rem;--bs-list-group-action-color: rgba(33, 37, 41, 0.75);--bs-list-group-action-hover-color: #000;--bs-list-group-action-hover-bg: #f8f9fa;--bs-list-group-action-active-color: #212529;--bs-list-group-action-active-bg: #e9ecef;--bs-list-group-disabled-color: rgba(33, 37, 41, 0.75);--bs-list-group-disabled-bg: #ffffff;--bs-list-group-active-color: #ffffff;--bs-list-group-active-bg: #0d6efd;--bs-list-group-active-border-color: #0d6efd;display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;padding-left:0;margin-bottom:0;border-radius:var(--bs-list-group-border-radius)}.list-group-numbered{list-style-type:none;counter-reset:section}.list-group-numbered>.list-group-item::before{content:counters(section, ".") ". ";counter-increment:section}.list-group-item-action{width:100%;color:var(--bs-list-group-action-color);text-align:inherit}.list-group-item-action:hover,.list-group-item-action:focus{z-index:1;color:var(--bs-list-group-action-hover-color);text-decoration:none;background-color:var(--bs-list-group-action-hover-bg)}.list-group-item-action:active{color:var(--bs-list-group-action-active-color);background-color:var(--bs-list-group-action-active-bg)}.list-group-item{position:relative;display:block;padding:var(--bs-list-group-item-padding-y) var(--bs-list-group-item-padding-x);color:var(--bs-list-group-color);text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;background-color:var(--bs-list-group-bg);border:var(--bs-list-group-border-width) solid var(--bs-list-group-border-color)}.list-group-item:first-child{border-top-left-radius:inherit;border-top-right-radius:inherit}.list-group-item:last-child{border-bottom-right-radius:inherit;border-bottom-left-radius:inherit}.list-group-item.disabled,.list-group-item:disabled{color:var(--bs-list-group-disabled-color);pointer-events:none;background-color:var(--bs-list-group-disabled-bg)}.list-group-item.active{z-index:2;color:var(--bs-list-group-active-color);background-color:var(--bs-list-group-active-bg);border-color:var(--bs-list-group-active-border-color)}.list-group-item+.list-group-item{border-top-width:0}.list-group-item+.list-group-item.active{margin-top:calc(-1*var(--bs-list-group-border-width));border-top-width:var(--bs-list-group-border-width)}.list-group-horizontal{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal>.list-group-item.active{margin-top:0}.list-group-horizontal>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal>.list-group-item+.list-group-item.active{margin-left:calc(-1*var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}@media(min-width: 576px){.list-group-horizontal-sm{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal-sm>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-sm>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-sm>.list-group-item.active{margin-top:0}.list-group-horizontal-sm>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-sm>.list-group-item+.list-group-item.active{margin-left:calc(-1*var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media(min-width: 768px){.list-group-horizontal-md{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal-md>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-md>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-md>.list-group-item.active{margin-top:0}.list-group-horizontal-md>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-md>.list-group-item+.list-group-item.active{margin-left:calc(-1*var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media(min-width: 992px){.list-group-horizontal-lg{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal-lg>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-lg>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-lg>.list-group-item.active{margin-top:0}.list-group-horizontal-lg>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-lg>.list-group-item+.list-group-item.active{margin-left:calc(-1*var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media(min-width: 1200px){.list-group-horizontal-xl{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal-xl>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-xl>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-xl>.list-group-item.active{margin-top:0}.list-group-horizontal-xl>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-xl>.list-group-item+.list-group-item.active{margin-left:calc(-1*var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media(min-width: 1400px){.list-group-horizontal-xxl{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal-xxl>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-xxl>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-xxl>.list-group-item.active{margin-top:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item.active{margin-left:calc(-1*var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}.list-group-flush{border-radius:0}.list-group-flush>.list-group-item{border-width:0 0 var(--bs-list-group-border-width)}.list-group-flush>.list-group-item:last-child{border-bottom-width:0}.list-group-item-default{--bs-list-group-color: var(--bs-default-text-emphasis);--bs-list-group-bg: var(--bs-default-bg-subtle);--bs-list-group-border-color: var(--bs-default-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-default-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-default-border-subtle);--bs-list-group-active-color: var(--bs-default-bg-subtle);--bs-list-group-active-bg: var(--bs-default-text-emphasis);--bs-list-group-active-border-color: var(--bs-default-text-emphasis)}.list-group-item-primary{--bs-list-group-color: var(--bs-primary-text-emphasis);--bs-list-group-bg: var(--bs-primary-bg-subtle);--bs-list-group-border-color: var(--bs-primary-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-primary-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-primary-border-subtle);--bs-list-group-active-color: var(--bs-primary-bg-subtle);--bs-list-group-active-bg: var(--bs-primary-text-emphasis);--bs-list-group-active-border-color: var(--bs-primary-text-emphasis)}.list-group-item-secondary{--bs-list-group-color: var(--bs-secondary-text-emphasis);--bs-list-group-bg: var(--bs-secondary-bg-subtle);--bs-list-group-border-color: var(--bs-secondary-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-secondary-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-secondary-border-subtle);--bs-list-group-active-color: var(--bs-secondary-bg-subtle);--bs-list-group-active-bg: var(--bs-secondary-text-emphasis);--bs-list-group-active-border-color: var(--bs-secondary-text-emphasis)}.list-group-item-success{--bs-list-group-color: var(--bs-success-text-emphasis);--bs-list-group-bg: var(--bs-success-bg-subtle);--bs-list-group-border-color: var(--bs-success-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-success-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-success-border-subtle);--bs-list-group-active-color: var(--bs-success-bg-subtle);--bs-list-group-active-bg: var(--bs-success-text-emphasis);--bs-list-group-active-border-color: var(--bs-success-text-emphasis)}.list-group-item-info{--bs-list-group-color: var(--bs-info-text-emphasis);--bs-list-group-bg: var(--bs-info-bg-subtle);--bs-list-group-border-color: var(--bs-info-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-info-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-info-border-subtle);--bs-list-group-active-color: var(--bs-info-bg-subtle);--bs-list-group-active-bg: var(--bs-info-text-emphasis);--bs-list-group-active-border-color: var(--bs-info-text-emphasis)}.list-group-item-warning{--bs-list-group-color: var(--bs-warning-text-emphasis);--bs-list-group-bg: var(--bs-warning-bg-subtle);--bs-list-group-border-color: var(--bs-warning-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-warning-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-warning-border-subtle);--bs-list-group-active-color: var(--bs-warning-bg-subtle);--bs-list-group-active-bg: var(--bs-warning-text-emphasis);--bs-list-group-active-border-color: var(--bs-warning-text-emphasis)}.list-group-item-danger{--bs-list-group-color: var(--bs-danger-text-emphasis);--bs-list-group-bg: var(--bs-danger-bg-subtle);--bs-list-group-border-color: var(--bs-danger-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-danger-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-danger-border-subtle);--bs-list-group-active-color: var(--bs-danger-bg-subtle);--bs-list-group-active-bg: var(--bs-danger-text-emphasis);--bs-list-group-active-border-color: var(--bs-danger-text-emphasis)}.list-group-item-light{--bs-list-group-color: var(--bs-light-text-emphasis);--bs-list-group-bg: var(--bs-light-bg-subtle);--bs-list-group-border-color: var(--bs-light-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-light-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-light-border-subtle);--bs-list-group-active-color: var(--bs-light-bg-subtle);--bs-list-group-active-bg: var(--bs-light-text-emphasis);--bs-list-group-active-border-color: var(--bs-light-text-emphasis)}.list-group-item-dark{--bs-list-group-color: var(--bs-dark-text-emphasis);--bs-list-group-bg: var(--bs-dark-bg-subtle);--bs-list-group-border-color: var(--bs-dark-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-dark-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-dark-border-subtle);--bs-list-group-active-color: var(--bs-dark-bg-subtle);--bs-list-group-active-bg: var(--bs-dark-text-emphasis);--bs-list-group-active-border-color: var(--bs-dark-text-emphasis)}.btn-close{--bs-btn-close-color: #000;--bs-btn-close-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath d='M.293.293a1 1 0 0 1 1.414 0L8 6.586 14.293.293a1 1 0 1 1 1.414 1.414L9.414 8l6.293 6.293a1 1 0 0 1-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 0 1-1.414-1.414L6.586 8 .293 1.707a1 1 0 0 1 0-1.414z'/%3e%3c/svg%3e");--bs-btn-close-opacity: 0.5;--bs-btn-close-hover-opacity: 0.75;--bs-btn-close-focus-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);--bs-btn-close-focus-opacity: 1;--bs-btn-close-disabled-opacity: 0.25;--bs-btn-close-white-filter: invert(1) grayscale(100%) brightness(200%);box-sizing:content-box;width:1em;height:1em;padding:.25em .25em;color:var(--bs-btn-close-color);background:rgba(0,0,0,0) var(--bs-btn-close-bg) center/1em auto no-repeat;border:0;border-radius:.375rem;opacity:var(--bs-btn-close-opacity)}.btn-close:hover{color:var(--bs-btn-close-color);text-decoration:none;opacity:var(--bs-btn-close-hover-opacity)}.btn-close:focus{outline:0;box-shadow:var(--bs-btn-close-focus-shadow);opacity:var(--bs-btn-close-focus-opacity)}.btn-close:disabled,.btn-close.disabled{pointer-events:none;user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;opacity:var(--bs-btn-close-disabled-opacity)}.btn-close-white{filter:var(--bs-btn-close-white-filter)}[data-bs-theme=dark] .btn-close{filter:var(--bs-btn-close-white-filter)}.toast{--bs-toast-zindex: 1090;--bs-toast-padding-x: 0.75rem;--bs-toast-padding-y: 0.5rem;--bs-toast-spacing: 1.5rem;--bs-toast-max-width: 350px;--bs-toast-font-size:0.875rem;--bs-toast-color: ;--bs-toast-bg: rgba(255, 255, 255, 0.85);--bs-toast-border-width: 1px;--bs-toast-border-color: rgba(0, 0, 0, 0.175);--bs-toast-border-radius: 0.375rem;--bs-toast-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);--bs-toast-header-color: rgba(33, 37, 41, 0.75);--bs-toast-header-bg: rgba(255, 255, 255, 0.85);--bs-toast-header-border-color: rgba(0, 0, 0, 0.175);width:var(--bs-toast-max-width);max-width:100%;font-size:var(--bs-toast-font-size);color:var(--bs-toast-color);pointer-events:auto;background-color:var(--bs-toast-bg);background-clip:padding-box;border:var(--bs-toast-border-width) solid var(--bs-toast-border-color);box-shadow:var(--bs-toast-box-shadow);border-radius:var(--bs-toast-border-radius)}.toast.showing{opacity:0}.toast:not(.show){display:none}.toast-container{--bs-toast-zindex: 1090;position:absolute;z-index:var(--bs-toast-zindex);width:max-content;width:-webkit-max-content;width:-moz-max-content;width:-ms-max-content;width:-o-max-content;max-width:100%;pointer-events:none}.toast-container>:not(:last-child){margin-bottom:var(--bs-toast-spacing)}.toast-header{display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;padding:var(--bs-toast-padding-y) var(--bs-toast-padding-x);color:var(--bs-toast-header-color);background-color:var(--bs-toast-header-bg);background-clip:padding-box;border-bottom:var(--bs-toast-border-width) solid var(--bs-toast-header-border-color);border-top-left-radius:calc(var(--bs-toast-border-radius) - var(--bs-toast-border-width));border-top-right-radius:calc(var(--bs-toast-border-radius) - var(--bs-toast-border-width))}.toast-header .btn-close{margin-right:calc(-0.5*var(--bs-toast-padding-x));margin-left:var(--bs-toast-padding-x)}.toast-body{padding:var(--bs-toast-padding-x);word-wrap:break-word}.modal{--bs-modal-zindex: 1055;--bs-modal-width: 500px;--bs-modal-padding: 1rem;--bs-modal-margin: 0.5rem;--bs-modal-color: ;--bs-modal-bg: #ffffff;--bs-modal-border-color: rgba(0, 0, 0, 0.175);--bs-modal-border-width: 1px;--bs-modal-border-radius: 0.5rem;--bs-modal-box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);--bs-modal-inner-border-radius: calc(0.5rem - 1px);--bs-modal-header-padding-x: 1rem;--bs-modal-header-padding-y: 1rem;--bs-modal-header-padding: 1rem 1rem;--bs-modal-header-border-color: #dee2e6;--bs-modal-header-border-width: 1px;--bs-modal-title-line-height: 1.5;--bs-modal-footer-gap: 0.5rem;--bs-modal-footer-bg: ;--bs-modal-footer-border-color: #dee2e6;--bs-modal-footer-border-width: 1px;position:fixed;top:0;left:0;z-index:var(--bs-modal-zindex);display:none;width:100%;height:100%;overflow-x:hidden;overflow-y:auto;outline:0}.modal-dialog{position:relative;width:auto;margin:var(--bs-modal-margin);pointer-events:none}.modal.fade .modal-dialog{transition:transform .3s ease-out;transform:translate(0, -50px)}@media(prefers-reduced-motion: reduce){.modal.fade .modal-dialog{transition:none}}.modal.show .modal-dialog{transform:none}.modal.modal-static .modal-dialog{transform:scale(1.02)}.modal-dialog-scrollable{height:calc(100% - var(--bs-modal-margin)*2)}.modal-dialog-scrollable .modal-content{max-height:100%;overflow:hidden}.modal-dialog-scrollable .modal-body{overflow-y:auto}.modal-dialog-centered{display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;min-height:calc(100% - var(--bs-modal-margin)*2)}.modal-content{position:relative;display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;width:100%;color:var(--bs-modal-color);pointer-events:auto;background-color:var(--bs-modal-bg);background-clip:padding-box;border:var(--bs-modal-border-width) solid var(--bs-modal-border-color);border-radius:var(--bs-modal-border-radius);outline:0}.modal-backdrop{--bs-backdrop-zindex: 1050;--bs-backdrop-bg: #000;--bs-backdrop-opacity: 0.5;position:fixed;top:0;left:0;z-index:var(--bs-backdrop-zindex);width:100vw;height:100vh;background-color:var(--bs-backdrop-bg)}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:var(--bs-backdrop-opacity)}.modal-header{display:flex;display:-webkit-flex;flex-shrink:0;-webkit-flex-shrink:0;align-items:center;-webkit-align-items:center;justify-content:space-between;-webkit-justify-content:space-between;padding:var(--bs-modal-header-padding);border-bottom:var(--bs-modal-header-border-width) solid var(--bs-modal-header-border-color);border-top-left-radius:var(--bs-modal-inner-border-radius);border-top-right-radius:var(--bs-modal-inner-border-radius)}.modal-header .btn-close{padding:calc(var(--bs-modal-header-padding-y)*.5) calc(var(--bs-modal-header-padding-x)*.5);margin:calc(-0.5*var(--bs-modal-header-padding-y)) calc(-0.5*var(--bs-modal-header-padding-x)) calc(-0.5*var(--bs-modal-header-padding-y)) auto}.modal-title{margin-bottom:0;line-height:var(--bs-modal-title-line-height)}.modal-body{position:relative;flex:1 1 auto;-webkit-flex:1 1 auto;padding:var(--bs-modal-padding)}.modal-footer{display:flex;display:-webkit-flex;flex-shrink:0;-webkit-flex-shrink:0;flex-wrap:wrap;-webkit-flex-wrap:wrap;align-items:center;-webkit-align-items:center;justify-content:flex-end;-webkit-justify-content:flex-end;padding:calc(var(--bs-modal-padding) - var(--bs-modal-footer-gap)*.5);background-color:var(--bs-modal-footer-bg);border-top:var(--bs-modal-footer-border-width) solid var(--bs-modal-footer-border-color);border-bottom-right-radius:var(--bs-modal-inner-border-radius);border-bottom-left-radius:var(--bs-modal-inner-border-radius)}.modal-footer>*{margin:calc(var(--bs-modal-footer-gap)*.5)}@media(min-width: 576px){.modal{--bs-modal-margin: 1.75rem;--bs-modal-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15)}.modal-dialog{max-width:var(--bs-modal-width);margin-right:auto;margin-left:auto}.modal-sm{--bs-modal-width: 300px}}@media(min-width: 992px){.modal-lg,.modal-xl{--bs-modal-width: 800px}}@media(min-width: 1200px){.modal-xl{--bs-modal-width: 1140px}}.modal-fullscreen{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen .modal-header,.modal-fullscreen .modal-footer{border-radius:0}.modal-fullscreen .modal-body{overflow-y:auto}@media(max-width: 575.98px){.modal-fullscreen-sm-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-sm-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-sm-down .modal-header,.modal-fullscreen-sm-down .modal-footer{border-radius:0}.modal-fullscreen-sm-down .modal-body{overflow-y:auto}}@media(max-width: 767.98px){.modal-fullscreen-md-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-md-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-md-down .modal-header,.modal-fullscreen-md-down .modal-footer{border-radius:0}.modal-fullscreen-md-down .modal-body{overflow-y:auto}}@media(max-width: 991.98px){.modal-fullscreen-lg-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-lg-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-lg-down .modal-header,.modal-fullscreen-lg-down .modal-footer{border-radius:0}.modal-fullscreen-lg-down .modal-body{overflow-y:auto}}@media(max-width: 1199.98px){.modal-fullscreen-xl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xl-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-xl-down .modal-header,.modal-fullscreen-xl-down .modal-footer{border-radius:0}.modal-fullscreen-xl-down .modal-body{overflow-y:auto}}@media(max-width: 1399.98px){.modal-fullscreen-xxl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xxl-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-xxl-down .modal-header,.modal-fullscreen-xxl-down .modal-footer{border-radius:0}.modal-fullscreen-xxl-down .modal-body{overflow-y:auto}}.tooltip{--bs-tooltip-zindex: 1080;--bs-tooltip-max-width: 200px;--bs-tooltip-padding-x: 0.5rem;--bs-tooltip-padding-y: 0.25rem;--bs-tooltip-margin: ;--bs-tooltip-font-size:0.875rem;--bs-tooltip-color: #ffffff;--bs-tooltip-bg: #000;--bs-tooltip-border-radius: 0.375rem;--bs-tooltip-opacity: 0.9;--bs-tooltip-arrow-width: 0.8rem;--bs-tooltip-arrow-height: 0.4rem;z-index:var(--bs-tooltip-zindex);display:block;margin:var(--bs-tooltip-margin);font-family:system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue","Noto Sans","Liberation Sans",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;white-space:normal;word-spacing:normal;line-break:auto;font-size:var(--bs-tooltip-font-size);word-wrap:break-word;opacity:0}.tooltip.show{opacity:var(--bs-tooltip-opacity)}.tooltip .tooltip-arrow{display:block;width:var(--bs-tooltip-arrow-width);height:var(--bs-tooltip-arrow-height)}.tooltip .tooltip-arrow::before{position:absolute;content:"";border-color:rgba(0,0,0,0);border-style:solid}.bs-tooltip-top .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow{bottom:calc(-1*var(--bs-tooltip-arrow-height))}.bs-tooltip-top .tooltip-arrow::before,.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow::before{top:-1px;border-width:var(--bs-tooltip-arrow-height) calc(var(--bs-tooltip-arrow-width)*.5) 0;border-top-color:var(--bs-tooltip-bg)}.bs-tooltip-end .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow{left:calc(-1*var(--bs-tooltip-arrow-height));width:var(--bs-tooltip-arrow-height);height:var(--bs-tooltip-arrow-width)}.bs-tooltip-end .tooltip-arrow::before,.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow::before{right:-1px;border-width:calc(var(--bs-tooltip-arrow-width)*.5) var(--bs-tooltip-arrow-height) calc(var(--bs-tooltip-arrow-width)*.5) 0;border-right-color:var(--bs-tooltip-bg)}.bs-tooltip-bottom .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow{top:calc(-1*var(--bs-tooltip-arrow-height))}.bs-tooltip-bottom .tooltip-arrow::before,.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow::before{bottom:-1px;border-width:0 calc(var(--bs-tooltip-arrow-width)*.5) var(--bs-tooltip-arrow-height);border-bottom-color:var(--bs-tooltip-bg)}.bs-tooltip-start .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow{right:calc(-1*var(--bs-tooltip-arrow-height));width:var(--bs-tooltip-arrow-height);height:var(--bs-tooltip-arrow-width)}.bs-tooltip-start .tooltip-arrow::before,.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow::before{left:-1px;border-width:calc(var(--bs-tooltip-arrow-width)*.5) 0 calc(var(--bs-tooltip-arrow-width)*.5) var(--bs-tooltip-arrow-height);border-left-color:var(--bs-tooltip-bg)}.tooltip-inner{max-width:var(--bs-tooltip-max-width);padding:var(--bs-tooltip-padding-y) var(--bs-tooltip-padding-x);color:var(--bs-tooltip-color);text-align:center;background-color:var(--bs-tooltip-bg);border-radius:var(--bs-tooltip-border-radius)}.popover{--bs-popover-zindex: 1070;--bs-popover-max-width: 276px;--bs-popover-font-size:0.875rem;--bs-popover-bg: #ffffff;--bs-popover-border-width: 1px;--bs-popover-border-color: rgba(0, 0, 0, 0.175);--bs-popover-border-radius: 0.5rem;--bs-popover-inner-border-radius: calc(0.5rem - 1px);--bs-popover-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);--bs-popover-header-padding-x: 1rem;--bs-popover-header-padding-y: 0.5rem;--bs-popover-header-font-size:1rem;--bs-popover-header-color: inherit;--bs-popover-header-bg: #e9ecef;--bs-popover-body-padding-x: 1rem;--bs-popover-body-padding-y: 1rem;--bs-popover-body-color: #212529;--bs-popover-arrow-width: 1rem;--bs-popover-arrow-height: 0.5rem;--bs-popover-arrow-border: var(--bs-popover-border-color);z-index:var(--bs-popover-zindex);display:block;max-width:var(--bs-popover-max-width);font-family:system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue","Noto Sans","Liberation Sans",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;white-space:normal;word-spacing:normal;line-break:auto;font-size:var(--bs-popover-font-size);word-wrap:break-word;background-color:var(--bs-popover-bg);background-clip:padding-box;border:var(--bs-popover-border-width) solid var(--bs-popover-border-color);border-radius:var(--bs-popover-border-radius)}.popover .popover-arrow{display:block;width:var(--bs-popover-arrow-width);height:var(--bs-popover-arrow-height)}.popover .popover-arrow::before,.popover .popover-arrow::after{position:absolute;display:block;content:"";border-color:rgba(0,0,0,0);border-style:solid;border-width:0}.bs-popover-top>.popover-arrow,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow{bottom:calc(-1*(var(--bs-popover-arrow-height)) - var(--bs-popover-border-width))}.bs-popover-top>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::before,.bs-popover-top>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::after{border-width:var(--bs-popover-arrow-height) calc(var(--bs-popover-arrow-width)*.5) 0}.bs-popover-top>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::before{bottom:0;border-top-color:var(--bs-popover-arrow-border)}.bs-popover-top>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::after{bottom:var(--bs-popover-border-width);border-top-color:var(--bs-popover-bg)}.bs-popover-end>.popover-arrow,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow{left:calc(-1*(var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));width:var(--bs-popover-arrow-height);height:var(--bs-popover-arrow-width)}.bs-popover-end>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::before,.bs-popover-end>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::after{border-width:calc(var(--bs-popover-arrow-width)*.5) var(--bs-popover-arrow-height) calc(var(--bs-popover-arrow-width)*.5) 0}.bs-popover-end>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::before{left:0;border-right-color:var(--bs-popover-arrow-border)}.bs-popover-end>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::after{left:var(--bs-popover-border-width);border-right-color:var(--bs-popover-bg)}.bs-popover-bottom>.popover-arrow,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow{top:calc(-1*(var(--bs-popover-arrow-height)) - var(--bs-popover-border-width))}.bs-popover-bottom>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::before,.bs-popover-bottom>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::after{border-width:0 calc(var(--bs-popover-arrow-width)*.5) var(--bs-popover-arrow-height)}.bs-popover-bottom>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::before{top:0;border-bottom-color:var(--bs-popover-arrow-border)}.bs-popover-bottom>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::after{top:var(--bs-popover-border-width);border-bottom-color:var(--bs-popover-bg)}.bs-popover-bottom .popover-header::before,.bs-popover-auto[data-popper-placement^=bottom] .popover-header::before{position:absolute;top:0;left:50%;display:block;width:var(--bs-popover-arrow-width);margin-left:calc(-0.5*var(--bs-popover-arrow-width));content:"";border-bottom:var(--bs-popover-border-width) solid var(--bs-popover-header-bg)}.bs-popover-start>.popover-arrow,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow{right:calc(-1*(var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));width:var(--bs-popover-arrow-height);height:var(--bs-popover-arrow-width)}.bs-popover-start>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::before,.bs-popover-start>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::after{border-width:calc(var(--bs-popover-arrow-width)*.5) 0 calc(var(--bs-popover-arrow-width)*.5) var(--bs-popover-arrow-height)}.bs-popover-start>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::before{right:0;border-left-color:var(--bs-popover-arrow-border)}.bs-popover-start>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::after{right:var(--bs-popover-border-width);border-left-color:var(--bs-popover-bg)}.popover-header{padding:var(--bs-popover-header-padding-y) var(--bs-popover-header-padding-x);margin-bottom:0;font-size:var(--bs-popover-header-font-size);color:var(--bs-popover-header-color);background-color:var(--bs-popover-header-bg);border-bottom:var(--bs-popover-border-width) solid var(--bs-popover-border-color);border-top-left-radius:var(--bs-popover-inner-border-radius);border-top-right-radius:var(--bs-popover-inner-border-radius)}.popover-header:empty{display:none}.popover-body{padding:var(--bs-popover-body-padding-y) var(--bs-popover-body-padding-x);color:var(--bs-popover-body-color)}.carousel{position:relative}.carousel.pointer-event{touch-action:pan-y;-webkit-touch-action:pan-y;-moz-touch-action:pan-y;-ms-touch-action:pan-y;-o-touch-action:pan-y}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner::after{display:block;clear:both;content:""}.carousel-item{position:relative;display:none;float:left;width:100%;margin-right:-100%;backface-visibility:hidden;-webkit-backface-visibility:hidden;-moz-backface-visibility:hidden;-ms-backface-visibility:hidden;-o-backface-visibility:hidden;transition:transform .6s ease-in-out}@media(prefers-reduced-motion: reduce){.carousel-item{transition:none}}.carousel-item.active,.carousel-item-next,.carousel-item-prev{display:block}.carousel-item-next:not(.carousel-item-start),.active.carousel-item-end{transform:translateX(100%)}.carousel-item-prev:not(.carousel-item-end),.active.carousel-item-start{transform:translateX(-100%)}.carousel-fade .carousel-item{opacity:0;transition-property:opacity;transform:none}.carousel-fade .carousel-item.active,.carousel-fade .carousel-item-next.carousel-item-start,.carousel-fade .carousel-item-prev.carousel-item-end{z-index:1;opacity:1}.carousel-fade .active.carousel-item-start,.carousel-fade .active.carousel-item-end{z-index:0;opacity:0;transition:opacity 0s .6s}@media(prefers-reduced-motion: reduce){.carousel-fade .active.carousel-item-start,.carousel-fade .active.carousel-item-end{transition:none}}.carousel-control-prev,.carousel-control-next{position:absolute;top:0;bottom:0;z-index:1;display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;justify-content:center;-webkit-justify-content:center;width:15%;padding:0;color:#fff;text-align:center;background:none;border:0;opacity:.5;transition:opacity .15s ease}@media(prefers-reduced-motion: reduce){.carousel-control-prev,.carousel-control-next{transition:none}}.carousel-control-prev:hover,.carousel-control-prev:focus,.carousel-control-next:hover,.carousel-control-next:focus{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-prev-icon,.carousel-control-next-icon{display:inline-block;width:2rem;height:2rem;background-repeat:no-repeat;background-position:50%;background-size:100% 100%}.carousel-control-prev-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23ffffff'%3e%3cpath d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z'/%3e%3c/svg%3e")}.carousel-control-next-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23ffffff'%3e%3cpath d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e")}.carousel-indicators{position:absolute;right:0;bottom:0;left:0;z-index:2;display:flex;display:-webkit-flex;justify-content:center;-webkit-justify-content:center;padding:0;margin-right:15%;margin-bottom:1rem;margin-left:15%}.carousel-indicators [data-bs-target]{box-sizing:content-box;flex:0 1 auto;-webkit-flex:0 1 auto;width:30px;height:3px;padding:0;margin-right:3px;margin-left:3px;text-indent:-999px;cursor:pointer;background-color:#fff;background-clip:padding-box;border:0;border-top:10px solid rgba(0,0,0,0);border-bottom:10px solid rgba(0,0,0,0);opacity:.5;transition:opacity .6s ease}@media(prefers-reduced-motion: reduce){.carousel-indicators [data-bs-target]{transition:none}}.carousel-indicators .active{opacity:1}.carousel-caption{position:absolute;right:15%;bottom:1.25rem;left:15%;padding-top:1.25rem;padding-bottom:1.25rem;color:#fff;text-align:center}.carousel-dark .carousel-control-prev-icon,.carousel-dark .carousel-control-next-icon{filter:invert(1) grayscale(100)}.carousel-dark .carousel-indicators [data-bs-target]{background-color:#000}.carousel-dark .carousel-caption{color:#000}[data-bs-theme=dark] .carousel .carousel-control-prev-icon,[data-bs-theme=dark] .carousel .carousel-control-next-icon,[data-bs-theme=dark].carousel .carousel-control-prev-icon,[data-bs-theme=dark].carousel .carousel-control-next-icon{filter:invert(1) grayscale(100)}[data-bs-theme=dark] .carousel .carousel-indicators [data-bs-target],[data-bs-theme=dark].carousel .carousel-indicators [data-bs-target]{background-color:#000}[data-bs-theme=dark] .carousel .carousel-caption,[data-bs-theme=dark].carousel .carousel-caption{color:#000}.spinner-grow,.spinner-border{display:inline-block;width:var(--bs-spinner-width);height:var(--bs-spinner-height);vertical-align:var(--bs-spinner-vertical-align);border-radius:50%;animation:var(--bs-spinner-animation-speed) linear infinite var(--bs-spinner-animation-name)}@keyframes spinner-border{to{transform:rotate(360deg) /* rtl:ignore */}}.spinner-border{--bs-spinner-width: 2rem;--bs-spinner-height: 2rem;--bs-spinner-vertical-align: -0.125em;--bs-spinner-border-width: 0.25em;--bs-spinner-animation-speed: 0.75s;--bs-spinner-animation-name: spinner-border;border:var(--bs-spinner-border-width) solid currentcolor;border-right-color:rgba(0,0,0,0)}.spinner-border-sm{--bs-spinner-width: 1rem;--bs-spinner-height: 1rem;--bs-spinner-border-width: 0.2em}@keyframes spinner-grow{0%{transform:scale(0)}50%{opacity:1;transform:none}}.spinner-grow{--bs-spinner-width: 2rem;--bs-spinner-height: 2rem;--bs-spinner-vertical-align: -0.125em;--bs-spinner-animation-speed: 0.75s;--bs-spinner-animation-name: spinner-grow;background-color:currentcolor;opacity:0}.spinner-grow-sm{--bs-spinner-width: 1rem;--bs-spinner-height: 1rem}@media(prefers-reduced-motion: reduce){.spinner-border,.spinner-grow{--bs-spinner-animation-speed: 1.5s}}.offcanvas,.offcanvas-xxl,.offcanvas-xl,.offcanvas-lg,.offcanvas-md,.offcanvas-sm{--bs-offcanvas-zindex: 1045;--bs-offcanvas-width: 400px;--bs-offcanvas-height: 30vh;--bs-offcanvas-padding-x: 1rem;--bs-offcanvas-padding-y: 1rem;--bs-offcanvas-color: #212529;--bs-offcanvas-bg: #ffffff;--bs-offcanvas-border-width: 1px;--bs-offcanvas-border-color: rgba(0, 0, 0, 0.175);--bs-offcanvas-box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);--bs-offcanvas-transition: transform 0.3s ease-in-out;--bs-offcanvas-title-line-height: 1.5}@media(max-width: 575.98px){.offcanvas-sm{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media(max-width: 575.98px)and (prefers-reduced-motion: reduce){.offcanvas-sm{transition:none}}@media(max-width: 575.98px){.offcanvas-sm.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-sm.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-sm.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-sm.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-sm.showing,.offcanvas-sm.show:not(.hiding){transform:none}.offcanvas-sm.showing,.offcanvas-sm.hiding,.offcanvas-sm.show{visibility:visible}}@media(min-width: 576px){.offcanvas-sm{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:rgba(0,0,0,0) !important}.offcanvas-sm .offcanvas-header{display:none}.offcanvas-sm .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible;background-color:rgba(0,0,0,0) !important}}@media(max-width: 767.98px){.offcanvas-md{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media(max-width: 767.98px)and (prefers-reduced-motion: reduce){.offcanvas-md{transition:none}}@media(max-width: 767.98px){.offcanvas-md.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-md.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-md.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-md.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-md.showing,.offcanvas-md.show:not(.hiding){transform:none}.offcanvas-md.showing,.offcanvas-md.hiding,.offcanvas-md.show{visibility:visible}}@media(min-width: 768px){.offcanvas-md{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:rgba(0,0,0,0) !important}.offcanvas-md .offcanvas-header{display:none}.offcanvas-md .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible;background-color:rgba(0,0,0,0) !important}}@media(max-width: 991.98px){.offcanvas-lg{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media(max-width: 991.98px)and (prefers-reduced-motion: reduce){.offcanvas-lg{transition:none}}@media(max-width: 991.98px){.offcanvas-lg.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-lg.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-lg.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-lg.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-lg.showing,.offcanvas-lg.show:not(.hiding){transform:none}.offcanvas-lg.showing,.offcanvas-lg.hiding,.offcanvas-lg.show{visibility:visible}}@media(min-width: 992px){.offcanvas-lg{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:rgba(0,0,0,0) !important}.offcanvas-lg .offcanvas-header{display:none}.offcanvas-lg .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible;background-color:rgba(0,0,0,0) !important}}@media(max-width: 1199.98px){.offcanvas-xl{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media(max-width: 1199.98px)and (prefers-reduced-motion: reduce){.offcanvas-xl{transition:none}}@media(max-width: 1199.98px){.offcanvas-xl.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-xl.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-xl.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-xl.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-xl.showing,.offcanvas-xl.show:not(.hiding){transform:none}.offcanvas-xl.showing,.offcanvas-xl.hiding,.offcanvas-xl.show{visibility:visible}}@media(min-width: 1200px){.offcanvas-xl{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:rgba(0,0,0,0) !important}.offcanvas-xl .offcanvas-header{display:none}.offcanvas-xl .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible;background-color:rgba(0,0,0,0) !important}}@media(max-width: 1399.98px){.offcanvas-xxl{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media(max-width: 1399.98px)and (prefers-reduced-motion: reduce){.offcanvas-xxl{transition:none}}@media(max-width: 1399.98px){.offcanvas-xxl.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-xxl.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-xxl.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-xxl.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-xxl.showing,.offcanvas-xxl.show:not(.hiding){transform:none}.offcanvas-xxl.showing,.offcanvas-xxl.hiding,.offcanvas-xxl.show{visibility:visible}}@media(min-width: 1400px){.offcanvas-xxl{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:rgba(0,0,0,0) !important}.offcanvas-xxl .offcanvas-header{display:none}.offcanvas-xxl .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible;background-color:rgba(0,0,0,0) !important}}.offcanvas{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}@media(prefers-reduced-motion: reduce){.offcanvas{transition:none}}.offcanvas.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas.showing,.offcanvas.show:not(.hiding){transform:none}.offcanvas.showing,.offcanvas.hiding,.offcanvas.show{visibility:visible}.offcanvas-backdrop{position:fixed;top:0;left:0;z-index:1040;width:100vw;height:100vh;background-color:#000}.offcanvas-backdrop.fade{opacity:0}.offcanvas-backdrop.show{opacity:.5}.offcanvas-header{display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;justify-content:space-between;-webkit-justify-content:space-between;padding:var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x)}.offcanvas-header .btn-close{padding:calc(var(--bs-offcanvas-padding-y)*.5) calc(var(--bs-offcanvas-padding-x)*.5);margin-top:calc(-0.5*var(--bs-offcanvas-padding-y));margin-right:calc(-0.5*var(--bs-offcanvas-padding-x));margin-bottom:calc(-0.5*var(--bs-offcanvas-padding-y))}.offcanvas-title{margin-bottom:0;line-height:var(--bs-offcanvas-title-line-height)}.offcanvas-body{flex-grow:1;-webkit-flex-grow:1;padding:var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x);overflow-y:auto}.placeholder{display:inline-block;min-height:1em;vertical-align:middle;cursor:wait;background-color:currentcolor;opacity:.5}.placeholder.btn::before{display:inline-block;content:""}.placeholder-xs{min-height:.6em}.placeholder-sm{min-height:.8em}.placeholder-lg{min-height:1.2em}.placeholder-glow .placeholder{animation:placeholder-glow 2s ease-in-out infinite}@keyframes placeholder-glow{50%{opacity:.2}}.placeholder-wave{mask-image:linear-gradient(130deg, #000 55%, rgba(0, 0, 0, 0.8) 75%, #000 95%);-webkit-mask-image:linear-gradient(130deg, #000 55%, rgba(0, 0, 0, 0.8) 75%, #000 95%);mask-size:200% 100%;-webkit-mask-size:200% 100%;animation:placeholder-wave 2s linear infinite}@keyframes placeholder-wave{100%{mask-position:-200% 0%;-webkit-mask-position:-200% 0%}}.clearfix::after{display:block;clear:both;content:""}.text-bg-default{color:#000 !important;background-color:RGBA(var(--bs-default-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-primary{color:#fff !important;background-color:RGBA(var(--bs-primary-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-secondary{color:#fff !important;background-color:RGBA(var(--bs-secondary-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-success{color:#fff !important;background-color:RGBA(var(--bs-success-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-info{color:#000 !important;background-color:RGBA(var(--bs-info-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-warning{color:#000 !important;background-color:RGBA(var(--bs-warning-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-danger{color:#fff !important;background-color:RGBA(var(--bs-danger-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-light{color:#000 !important;background-color:RGBA(var(--bs-light-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-dark{color:#fff !important;background-color:RGBA(var(--bs-dark-rgb), var(--bs-bg-opacity, 1)) !important}.link-default{color:RGBA(var(--bs-default-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-default-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-default:hover,.link-default:focus{color:RGBA(229, 232, 235, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(229, 232, 235, var(--bs-link-underline-opacity, 1)) !important}.link-primary{color:RGBA(var(--bs-primary-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-primary-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-primary:hover,.link-primary:focus{color:RGBA(10, 88, 202, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(10, 88, 202, var(--bs-link-underline-opacity, 1)) !important}.link-secondary{color:RGBA(var(--bs-secondary-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-secondary-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-secondary:hover,.link-secondary:focus{color:RGBA(86, 94, 100, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(86, 94, 100, var(--bs-link-underline-opacity, 1)) !important}.link-success{color:RGBA(var(--bs-success-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-success-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-success:hover,.link-success:focus{color:RGBA(20, 108, 67, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(20, 108, 67, var(--bs-link-underline-opacity, 1)) !important}.link-info{color:RGBA(var(--bs-info-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-info-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-info:hover,.link-info:focus{color:RGBA(61, 213, 243, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(61, 213, 243, var(--bs-link-underline-opacity, 1)) !important}.link-warning{color:RGBA(var(--bs-warning-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-warning-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-warning:hover,.link-warning:focus{color:RGBA(255, 205, 57, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(255, 205, 57, var(--bs-link-underline-opacity, 1)) !important}.link-danger{color:RGBA(var(--bs-danger-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-danger-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-danger:hover,.link-danger:focus{color:RGBA(176, 42, 55, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(176, 42, 55, var(--bs-link-underline-opacity, 1)) !important}.link-light{color:RGBA(var(--bs-light-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-light-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-light:hover,.link-light:focus{color:RGBA(249, 250, 251, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(249, 250, 251, var(--bs-link-underline-opacity, 1)) !important}.link-dark{color:RGBA(var(--bs-dark-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-dark-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-dark:hover,.link-dark:focus{color:RGBA(26, 30, 33, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(26, 30, 33, var(--bs-link-underline-opacity, 1)) !important}.link-body-emphasis{color:RGBA(var(--bs-emphasis-color-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-emphasis-color-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-body-emphasis:hover,.link-body-emphasis:focus{color:RGBA(var(--bs-emphasis-color-rgb), var(--bs-link-opacity, 0.75)) !important;text-decoration-color:RGBA(var(--bs-emphasis-color-rgb), var(--bs-link-underline-opacity, 0.75)) !important}.focus-ring:focus{outline:0;box-shadow:var(--bs-focus-ring-x, 0) var(--bs-focus-ring-y, 0) var(--bs-focus-ring-blur, 0) var(--bs-focus-ring-width) var(--bs-focus-ring-color)}.icon-link{display:inline-flex;gap:.375rem;align-items:center;-webkit-align-items:center;text-decoration-color:rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 0.5));text-underline-offset:.25em;backface-visibility:hidden;-webkit-backface-visibility:hidden;-moz-backface-visibility:hidden;-ms-backface-visibility:hidden;-o-backface-visibility:hidden}.icon-link>.bi{flex-shrink:0;-webkit-flex-shrink:0;width:1em;height:1em;fill:currentcolor;transition:.2s ease-in-out transform}@media(prefers-reduced-motion: reduce){.icon-link>.bi{transition:none}}.icon-link-hover:hover>.bi,.icon-link-hover:focus-visible>.bi{transform:var(--bs-icon-link-transform, translate3d(0.25em, 0, 0))}.ratio{position:relative;width:100%}.ratio::before{display:block;padding-top:var(--bs-aspect-ratio);content:""}.ratio>*{position:absolute;top:0;left:0;width:100%;height:100%}.ratio-1x1{--bs-aspect-ratio: 100%}.ratio-4x3{--bs-aspect-ratio: 75%}.ratio-16x9{--bs-aspect-ratio: 56.25%}.ratio-21x9{--bs-aspect-ratio: 42.8571428571%}.fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030}.fixed-bottom{position:fixed;right:0;bottom:0;left:0;z-index:1030}.sticky-top{position:sticky;top:0;z-index:1020}.sticky-bottom{position:sticky;bottom:0;z-index:1020}@media(min-width: 576px){.sticky-sm-top{position:sticky;top:0;z-index:1020}.sticky-sm-bottom{position:sticky;bottom:0;z-index:1020}}@media(min-width: 768px){.sticky-md-top{position:sticky;top:0;z-index:1020}.sticky-md-bottom{position:sticky;bottom:0;z-index:1020}}@media(min-width: 992px){.sticky-lg-top{position:sticky;top:0;z-index:1020}.sticky-lg-bottom{position:sticky;bottom:0;z-index:1020}}@media(min-width: 1200px){.sticky-xl-top{position:sticky;top:0;z-index:1020}.sticky-xl-bottom{position:sticky;bottom:0;z-index:1020}}@media(min-width: 1400px){.sticky-xxl-top{position:sticky;top:0;z-index:1020}.sticky-xxl-bottom{position:sticky;bottom:0;z-index:1020}}.hstack{display:flex;display:-webkit-flex;flex-direction:row;-webkit-flex-direction:row;align-items:center;-webkit-align-items:center;align-self:stretch;-webkit-align-self:stretch}.vstack{display:flex;display:-webkit-flex;flex:1 1 auto;-webkit-flex:1 1 auto;flex-direction:column;-webkit-flex-direction:column;align-self:stretch;-webkit-align-self:stretch}.visually-hidden,.visually-hidden-focusable:not(:focus):not(:focus-within){width:1px !important;height:1px !important;padding:0 !important;margin:-1px !important;overflow:hidden !important;clip:rect(0, 0, 0, 0) !important;white-space:nowrap !important;border:0 !important}.visually-hidden:not(caption),.visually-hidden-focusable:not(:focus):not(:focus-within):not(caption){position:absolute !important}.stretched-link::after{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;content:""}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vr{display:inline-block;align-self:stretch;-webkit-align-self:stretch;width:1px;min-height:1em;background-color:currentcolor;opacity:.25}.align-baseline{vertical-align:baseline !important}.align-top{vertical-align:top !important}.align-middle{vertical-align:middle !important}.align-bottom{vertical-align:bottom !important}.align-text-bottom{vertical-align:text-bottom !important}.align-text-top{vertical-align:text-top !important}.float-start{float:left !important}.float-end{float:right !important}.float-none{float:none !important}.object-fit-contain{object-fit:contain !important}.object-fit-cover{object-fit:cover !important}.object-fit-fill{object-fit:fill !important}.object-fit-scale{object-fit:scale-down !important}.object-fit-none{object-fit:none !important}.opacity-0{opacity:0 !important}.opacity-25{opacity:.25 !important}.opacity-50{opacity:.5 !important}.opacity-75{opacity:.75 !important}.opacity-100{opacity:1 !important}.overflow-auto{overflow:auto !important}.overflow-hidden{overflow:hidden !important}.overflow-visible{overflow:visible !important}.overflow-scroll{overflow:scroll !important}.overflow-x-auto{overflow-x:auto !important}.overflow-x-hidden{overflow-x:hidden !important}.overflow-x-visible{overflow-x:visible !important}.overflow-x-scroll{overflow-x:scroll !important}.overflow-y-auto{overflow-y:auto !important}.overflow-y-hidden{overflow-y:hidden !important}.overflow-y-visible{overflow-y:visible !important}.overflow-y-scroll{overflow-y:scroll !important}.d-inline{display:inline !important}.d-inline-block{display:inline-block !important}.d-block{display:block !important}.d-grid{display:grid !important}.d-inline-grid{display:inline-grid !important}.d-table{display:table !important}.d-table-row{display:table-row !important}.d-table-cell{display:table-cell !important}.d-flex{display:flex !important}.d-inline-flex{display:inline-flex !important}.d-none{display:none !important}.shadow{box-shadow:0 .5rem 1rem rgba(0,0,0,.15) !important}.shadow-sm{box-shadow:0 .125rem .25rem rgba(0,0,0,.075) !important}.shadow-lg{box-shadow:0 1rem 3rem rgba(0,0,0,.175) !important}.shadow-none{box-shadow:none !important}.focus-ring-default{--bs-focus-ring-color: rgba(var(--bs-default-rgb), var(--bs-focus-ring-opacity))}.focus-ring-primary{--bs-focus-ring-color: rgba(var(--bs-primary-rgb), var(--bs-focus-ring-opacity))}.focus-ring-secondary{--bs-focus-ring-color: rgba(var(--bs-secondary-rgb), var(--bs-focus-ring-opacity))}.focus-ring-success{--bs-focus-ring-color: rgba(var(--bs-success-rgb), var(--bs-focus-ring-opacity))}.focus-ring-info{--bs-focus-ring-color: rgba(var(--bs-info-rgb), var(--bs-focus-ring-opacity))}.focus-ring-warning{--bs-focus-ring-color: rgba(var(--bs-warning-rgb), var(--bs-focus-ring-opacity))}.focus-ring-danger{--bs-focus-ring-color: rgba(var(--bs-danger-rgb), var(--bs-focus-ring-opacity))}.focus-ring-light{--bs-focus-ring-color: rgba(var(--bs-light-rgb), var(--bs-focus-ring-opacity))}.focus-ring-dark{--bs-focus-ring-color: rgba(var(--bs-dark-rgb), var(--bs-focus-ring-opacity))}.position-static{position:static !important}.position-relative{position:relative !important}.position-absolute{position:absolute !important}.position-fixed{position:fixed !important}.position-sticky{position:sticky !important}.top-0{top:0 !important}.top-50{top:50% !important}.top-100{top:100% !important}.bottom-0{bottom:0 !important}.bottom-50{bottom:50% !important}.bottom-100{bottom:100% !important}.start-0{left:0 !important}.start-50{left:50% !important}.start-100{left:100% !important}.end-0{right:0 !important}.end-50{right:50% !important}.end-100{right:100% !important}.translate-middle{transform:translate(-50%, -50%) !important}.translate-middle-x{transform:translateX(-50%) !important}.translate-middle-y{transform:translateY(-50%) !important}.border{border:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important}.border-0{border:0 !important}.border-top{border-top:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important}.border-top-0{border-top:0 !important}.border-end{border-right:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important}.border-end-0{border-right:0 !important}.border-bottom{border-bottom:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important}.border-bottom-0{border-bottom:0 !important}.border-start{border-left:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important}.border-start-0{border-left:0 !important}.border-default{--bs-border-opacity: 1;border-color:rgba(var(--bs-default-rgb), var(--bs-border-opacity)) !important}.border-primary{--bs-border-opacity: 1;border-color:rgba(var(--bs-primary-rgb), var(--bs-border-opacity)) !important}.border-secondary{--bs-border-opacity: 1;border-color:rgba(var(--bs-secondary-rgb), var(--bs-border-opacity)) !important}.border-success{--bs-border-opacity: 1;border-color:rgba(var(--bs-success-rgb), var(--bs-border-opacity)) !important}.border-info{--bs-border-opacity: 1;border-color:rgba(var(--bs-info-rgb), var(--bs-border-opacity)) !important}.border-warning{--bs-border-opacity: 1;border-color:rgba(var(--bs-warning-rgb), var(--bs-border-opacity)) !important}.border-danger{--bs-border-opacity: 1;border-color:rgba(var(--bs-danger-rgb), var(--bs-border-opacity)) !important}.border-light{--bs-border-opacity: 1;border-color:rgba(var(--bs-light-rgb), var(--bs-border-opacity)) !important}.border-dark{--bs-border-opacity: 1;border-color:rgba(var(--bs-dark-rgb), var(--bs-border-opacity)) !important}.border-black{--bs-border-opacity: 1;border-color:rgba(var(--bs-black-rgb), var(--bs-border-opacity)) !important}.border-white{--bs-border-opacity: 1;border-color:rgba(var(--bs-white-rgb), var(--bs-border-opacity)) !important}.border-primary-subtle{border-color:var(--bs-primary-border-subtle) !important}.border-secondary-subtle{border-color:var(--bs-secondary-border-subtle) !important}.border-success-subtle{border-color:var(--bs-success-border-subtle) !important}.border-info-subtle{border-color:var(--bs-info-border-subtle) !important}.border-warning-subtle{border-color:var(--bs-warning-border-subtle) !important}.border-danger-subtle{border-color:var(--bs-danger-border-subtle) !important}.border-light-subtle{border-color:var(--bs-light-border-subtle) !important}.border-dark-subtle{border-color:var(--bs-dark-border-subtle) !important}.border-1{border-width:1px !important}.border-2{border-width:2px !important}.border-3{border-width:3px !important}.border-4{border-width:4px !important}.border-5{border-width:5px !important}.border-opacity-10{--bs-border-opacity: 0.1}.border-opacity-25{--bs-border-opacity: 0.25}.border-opacity-50{--bs-border-opacity: 0.5}.border-opacity-75{--bs-border-opacity: 0.75}.border-opacity-100{--bs-border-opacity: 1}.w-25{width:25% !important}.w-50{width:50% !important}.w-75{width:75% !important}.w-100{width:100% !important}.w-auto{width:auto !important}.mw-100{max-width:100% !important}.vw-100{width:100vw !important}.min-vw-100{min-width:100vw !important}.h-25{height:25% !important}.h-50{height:50% !important}.h-75{height:75% !important}.h-100{height:100% !important}.h-auto{height:auto !important}.mh-100{max-height:100% !important}.vh-100{height:100vh !important}.min-vh-100{min-height:100vh !important}.flex-fill{flex:1 1 auto !important}.flex-row{flex-direction:row !important}.flex-column{flex-direction:column !important}.flex-row-reverse{flex-direction:row-reverse !important}.flex-column-reverse{flex-direction:column-reverse !important}.flex-grow-0{flex-grow:0 !important}.flex-grow-1{flex-grow:1 !important}.flex-shrink-0{flex-shrink:0 !important}.flex-shrink-1{flex-shrink:1 !important}.flex-wrap{flex-wrap:wrap !important}.flex-nowrap{flex-wrap:nowrap !important}.flex-wrap-reverse{flex-wrap:wrap-reverse !important}.justify-content-start{justify-content:flex-start !important}.justify-content-end{justify-content:flex-end !important}.justify-content-center{justify-content:center !important}.justify-content-between{justify-content:space-between !important}.justify-content-around{justify-content:space-around !important}.justify-content-evenly{justify-content:space-evenly !important}.align-items-start{align-items:flex-start !important}.align-items-end{align-items:flex-end !important}.align-items-center{align-items:center !important}.align-items-baseline{align-items:baseline !important}.align-items-stretch{align-items:stretch !important}.align-content-start{align-content:flex-start !important}.align-content-end{align-content:flex-end !important}.align-content-center{align-content:center !important}.align-content-between{align-content:space-between !important}.align-content-around{align-content:space-around !important}.align-content-stretch{align-content:stretch !important}.align-self-auto{align-self:auto !important}.align-self-start{align-self:flex-start !important}.align-self-end{align-self:flex-end !important}.align-self-center{align-self:center !important}.align-self-baseline{align-self:baseline !important}.align-self-stretch{align-self:stretch !important}.order-first{order:-1 !important}.order-0{order:0 !important}.order-1{order:1 !important}.order-2{order:2 !important}.order-3{order:3 !important}.order-4{order:4 !important}.order-5{order:5 !important}.order-last{order:6 !important}.m-0{margin:0 !important}.m-1{margin:.25rem !important}.m-2{margin:.5rem !important}.m-3{margin:1rem !important}.m-4{margin:1.5rem !important}.m-5{margin:3rem !important}.m-auto{margin:auto !important}.mx-0{margin-right:0 !important;margin-left:0 !important}.mx-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-3{margin-right:1rem !important;margin-left:1rem !important}.mx-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-5{margin-right:3rem !important;margin-left:3rem !important}.mx-auto{margin-right:auto !important;margin-left:auto !important}.my-0{margin-top:0 !important;margin-bottom:0 !important}.my-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-0{margin-top:0 !important}.mt-1{margin-top:.25rem !important}.mt-2{margin-top:.5rem !important}.mt-3{margin-top:1rem !important}.mt-4{margin-top:1.5rem !important}.mt-5{margin-top:3rem !important}.mt-auto{margin-top:auto !important}.me-0{margin-right:0 !important}.me-1{margin-right:.25rem !important}.me-2{margin-right:.5rem !important}.me-3{margin-right:1rem !important}.me-4{margin-right:1.5rem !important}.me-5{margin-right:3rem !important}.me-auto{margin-right:auto !important}.mb-0{margin-bottom:0 !important}.mb-1{margin-bottom:.25rem !important}.mb-2{margin-bottom:.5rem !important}.mb-3{margin-bottom:1rem !important}.mb-4{margin-bottom:1.5rem !important}.mb-5{margin-bottom:3rem !important}.mb-auto{margin-bottom:auto !important}.ms-0{margin-left:0 !important}.ms-1{margin-left:.25rem !important}.ms-2{margin-left:.5rem !important}.ms-3{margin-left:1rem !important}.ms-4{margin-left:1.5rem !important}.ms-5{margin-left:3rem !important}.ms-auto{margin-left:auto !important}.p-0{padding:0 !important}.p-1{padding:.25rem !important}.p-2{padding:.5rem !important}.p-3{padding:1rem !important}.p-4{padding:1.5rem !important}.p-5{padding:3rem !important}.px-0{padding-right:0 !important;padding-left:0 !important}.px-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-3{padding-right:1rem !important;padding-left:1rem !important}.px-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-5{padding-right:3rem !important;padding-left:3rem !important}.py-0{padding-top:0 !important;padding-bottom:0 !important}.py-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-0{padding-top:0 !important}.pt-1{padding-top:.25rem !important}.pt-2{padding-top:.5rem !important}.pt-3{padding-top:1rem !important}.pt-4{padding-top:1.5rem !important}.pt-5{padding-top:3rem !important}.pe-0{padding-right:0 !important}.pe-1{padding-right:.25rem !important}.pe-2{padding-right:.5rem !important}.pe-3{padding-right:1rem !important}.pe-4{padding-right:1.5rem !important}.pe-5{padding-right:3rem !important}.pb-0{padding-bottom:0 !important}.pb-1{padding-bottom:.25rem !important}.pb-2{padding-bottom:.5rem !important}.pb-3{padding-bottom:1rem !important}.pb-4{padding-bottom:1.5rem !important}.pb-5{padding-bottom:3rem !important}.ps-0{padding-left:0 !important}.ps-1{padding-left:.25rem !important}.ps-2{padding-left:.5rem !important}.ps-3{padding-left:1rem !important}.ps-4{padding-left:1.5rem !important}.ps-5{padding-left:3rem !important}.gap-0{gap:0 !important}.gap-1{gap:.25rem !important}.gap-2{gap:.5rem !important}.gap-3{gap:1rem !important}.gap-4{gap:1.5rem !important}.gap-5{gap:3rem !important}.row-gap-0{row-gap:0 !important}.row-gap-1{row-gap:.25rem !important}.row-gap-2{row-gap:.5rem !important}.row-gap-3{row-gap:1rem !important}.row-gap-4{row-gap:1.5rem !important}.row-gap-5{row-gap:3rem !important}.column-gap-0{column-gap:0 !important}.column-gap-1{column-gap:.25rem !important}.column-gap-2{column-gap:.5rem !important}.column-gap-3{column-gap:1rem !important}.column-gap-4{column-gap:1.5rem !important}.column-gap-5{column-gap:3rem !important}.font-monospace{font-family:var(--bs-font-monospace) !important}.fs-1{font-size:calc(1.325rem + 0.9vw) !important}.fs-2{font-size:calc(1.29rem + 0.48vw) !important}.fs-3{font-size:calc(1.27rem + 0.24vw) !important}.fs-4{font-size:1.25rem !important}.fs-5{font-size:1.1rem !important}.fs-6{font-size:1rem !important}.fst-italic{font-style:italic !important}.fst-normal{font-style:normal !important}.fw-lighter{font-weight:lighter !important}.fw-light{font-weight:300 !important}.fw-normal{font-weight:400 !important}.fw-medium{font-weight:500 !important}.fw-semibold{font-weight:600 !important}.fw-bold{font-weight:700 !important}.fw-bolder{font-weight:bolder !important}.lh-1{line-height:1 !important}.lh-sm{line-height:1.25 !important}.lh-base{line-height:1.5 !important}.lh-lg{line-height:2 !important}.text-start{text-align:left !important}.text-end{text-align:right !important}.text-center{text-align:center !important}.text-decoration-none{text-decoration:none !important}.text-decoration-underline{text-decoration:underline !important}.text-decoration-line-through{text-decoration:line-through !important}.text-lowercase{text-transform:lowercase !important}.text-uppercase{text-transform:uppercase !important}.text-capitalize{text-transform:capitalize !important}.text-wrap{white-space:normal !important}.text-nowrap{white-space:nowrap !important}.text-break{word-wrap:break-word !important;word-break:break-word !important}.text-default{--bs-text-opacity: 1;color:rgba(var(--bs-default-rgb), var(--bs-text-opacity)) !important}.text-primary{--bs-text-opacity: 1;color:rgba(var(--bs-primary-rgb), var(--bs-text-opacity)) !important}.text-secondary{--bs-text-opacity: 1;color:rgba(var(--bs-secondary-rgb), var(--bs-text-opacity)) !important}.text-success{--bs-text-opacity: 1;color:rgba(var(--bs-success-rgb), var(--bs-text-opacity)) !important}.text-info{--bs-text-opacity: 1;color:rgba(var(--bs-info-rgb), var(--bs-text-opacity)) !important}.text-warning{--bs-text-opacity: 1;color:rgba(var(--bs-warning-rgb), var(--bs-text-opacity)) !important}.text-danger{--bs-text-opacity: 1;color:rgba(var(--bs-danger-rgb), var(--bs-text-opacity)) !important}.text-light{--bs-text-opacity: 1;color:rgba(var(--bs-light-rgb), var(--bs-text-opacity)) !important}.text-dark{--bs-text-opacity: 1;color:rgba(var(--bs-dark-rgb), var(--bs-text-opacity)) !important}.text-black{--bs-text-opacity: 1;color:rgba(var(--bs-black-rgb), var(--bs-text-opacity)) !important}.text-white{--bs-text-opacity: 1;color:rgba(var(--bs-white-rgb), var(--bs-text-opacity)) !important}.text-body{--bs-text-opacity: 1;color:rgba(var(--bs-body-color-rgb), var(--bs-text-opacity)) !important}.text-muted{--bs-text-opacity: 1;color:var(--bs-secondary-color) !important}.text-black-50{--bs-text-opacity: 1;color:rgba(0,0,0,.5) !important}.text-white-50{--bs-text-opacity: 1;color:rgba(255,255,255,.5) !important}.text-body-secondary{--bs-text-opacity: 1;color:var(--bs-secondary-color) !important}.text-body-tertiary{--bs-text-opacity: 1;color:var(--bs-tertiary-color) !important}.text-body-emphasis{--bs-text-opacity: 1;color:var(--bs-emphasis-color) !important}.text-reset{--bs-text-opacity: 1;color:inherit !important}.text-opacity-25{--bs-text-opacity: 0.25}.text-opacity-50{--bs-text-opacity: 0.5}.text-opacity-75{--bs-text-opacity: 0.75}.text-opacity-100{--bs-text-opacity: 1}.text-primary-emphasis{color:var(--bs-primary-text-emphasis) !important}.text-secondary-emphasis{color:var(--bs-secondary-text-emphasis) !important}.text-success-emphasis{color:var(--bs-success-text-emphasis) !important}.text-info-emphasis{color:var(--bs-info-text-emphasis) !important}.text-warning-emphasis{color:var(--bs-warning-text-emphasis) !important}.text-danger-emphasis{color:var(--bs-danger-text-emphasis) !important}.text-light-emphasis{color:var(--bs-light-text-emphasis) !important}.text-dark-emphasis{color:var(--bs-dark-text-emphasis) !important}.link-opacity-10{--bs-link-opacity: 0.1}.link-opacity-10-hover:hover{--bs-link-opacity: 0.1}.link-opacity-25{--bs-link-opacity: 0.25}.link-opacity-25-hover:hover{--bs-link-opacity: 0.25}.link-opacity-50{--bs-link-opacity: 0.5}.link-opacity-50-hover:hover{--bs-link-opacity: 0.5}.link-opacity-75{--bs-link-opacity: 0.75}.link-opacity-75-hover:hover{--bs-link-opacity: 0.75}.link-opacity-100{--bs-link-opacity: 1}.link-opacity-100-hover:hover{--bs-link-opacity: 1}.link-offset-1{text-underline-offset:.125em !important}.link-offset-1-hover:hover{text-underline-offset:.125em !important}.link-offset-2{text-underline-offset:.25em !important}.link-offset-2-hover:hover{text-underline-offset:.25em !important}.link-offset-3{text-underline-offset:.375em !important}.link-offset-3-hover:hover{text-underline-offset:.375em !important}.link-underline-default{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-default-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-primary{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-primary-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-secondary{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-secondary-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-success{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-success-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-info{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-info-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-warning{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-warning-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-danger{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-danger-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-light{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-light-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-dark{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-dark-rgb), var(--bs-link-underline-opacity)) !important}.link-underline{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-link-color-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-underline-opacity-0{--bs-link-underline-opacity: 0}.link-underline-opacity-0-hover:hover{--bs-link-underline-opacity: 0}.link-underline-opacity-10{--bs-link-underline-opacity: 0.1}.link-underline-opacity-10-hover:hover{--bs-link-underline-opacity: 0.1}.link-underline-opacity-25{--bs-link-underline-opacity: 0.25}.link-underline-opacity-25-hover:hover{--bs-link-underline-opacity: 0.25}.link-underline-opacity-50{--bs-link-underline-opacity: 0.5}.link-underline-opacity-50-hover:hover{--bs-link-underline-opacity: 0.5}.link-underline-opacity-75{--bs-link-underline-opacity: 0.75}.link-underline-opacity-75-hover:hover{--bs-link-underline-opacity: 0.75}.link-underline-opacity-100{--bs-link-underline-opacity: 1}.link-underline-opacity-100-hover:hover{--bs-link-underline-opacity: 1}.bg-default{--bs-bg-opacity: 1;background-color:rgba(var(--bs-default-rgb), var(--bs-bg-opacity)) !important}.bg-primary{--bs-bg-opacity: 1;background-color:rgba(var(--bs-primary-rgb), var(--bs-bg-opacity)) !important}.bg-secondary{--bs-bg-opacity: 1;background-color:rgba(var(--bs-secondary-rgb), var(--bs-bg-opacity)) !important}.bg-success{--bs-bg-opacity: 1;background-color:rgba(var(--bs-success-rgb), var(--bs-bg-opacity)) !important}.bg-info{--bs-bg-opacity: 1;background-color:rgba(var(--bs-info-rgb), var(--bs-bg-opacity)) !important}.bg-warning{--bs-bg-opacity: 1;background-color:rgba(var(--bs-warning-rgb), var(--bs-bg-opacity)) !important}.bg-danger{--bs-bg-opacity: 1;background-color:rgba(var(--bs-danger-rgb), var(--bs-bg-opacity)) !important}.bg-light{--bs-bg-opacity: 1;background-color:rgba(var(--bs-light-rgb), var(--bs-bg-opacity)) !important}.bg-dark{--bs-bg-opacity: 1;background-color:rgba(var(--bs-dark-rgb), var(--bs-bg-opacity)) !important}.bg-black{--bs-bg-opacity: 1;background-color:rgba(var(--bs-black-rgb), var(--bs-bg-opacity)) !important}.bg-white{--bs-bg-opacity: 1;background-color:rgba(var(--bs-white-rgb), var(--bs-bg-opacity)) !important}.bg-body{--bs-bg-opacity: 1;background-color:rgba(var(--bs-body-bg-rgb), var(--bs-bg-opacity)) !important}.bg-transparent{--bs-bg-opacity: 1;background-color:rgba(0,0,0,0) !important}.bg-body-secondary{--bs-bg-opacity: 1;background-color:rgba(var(--bs-secondary-bg-rgb), var(--bs-bg-opacity)) !important}.bg-body-tertiary{--bs-bg-opacity: 1;background-color:rgba(var(--bs-tertiary-bg-rgb), var(--bs-bg-opacity)) !important}.bg-opacity-10{--bs-bg-opacity: 0.1}.bg-opacity-25{--bs-bg-opacity: 0.25}.bg-opacity-50{--bs-bg-opacity: 0.5}.bg-opacity-75{--bs-bg-opacity: 0.75}.bg-opacity-100{--bs-bg-opacity: 1}.bg-primary-subtle{background-color:var(--bs-primary-bg-subtle) !important}.bg-secondary-subtle{background-color:var(--bs-secondary-bg-subtle) !important}.bg-success-subtle{background-color:var(--bs-success-bg-subtle) !important}.bg-info-subtle{background-color:var(--bs-info-bg-subtle) !important}.bg-warning-subtle{background-color:var(--bs-warning-bg-subtle) !important}.bg-danger-subtle{background-color:var(--bs-danger-bg-subtle) !important}.bg-light-subtle{background-color:var(--bs-light-bg-subtle) !important}.bg-dark-subtle{background-color:var(--bs-dark-bg-subtle) !important}.bg-gradient{background-image:var(--bs-gradient) !important}.user-select-all{user-select:all !important}.user-select-auto{user-select:auto !important}.user-select-none{user-select:none !important}.pe-none{pointer-events:none !important}.pe-auto{pointer-events:auto !important}.rounded{border-radius:var(--bs-border-radius) !important}.rounded-0{border-radius:0 !important}.rounded-1{border-radius:var(--bs-border-radius-sm) !important}.rounded-2{border-radius:var(--bs-border-radius) !important}.rounded-3{border-radius:var(--bs-border-radius-lg) !important}.rounded-4{border-radius:var(--bs-border-radius-xl) !important}.rounded-5{border-radius:var(--bs-border-radius-xxl) !important}.rounded-circle{border-radius:50% !important}.rounded-pill{border-radius:var(--bs-border-radius-pill) !important}.rounded-top{border-top-left-radius:var(--bs-border-radius) !important;border-top-right-radius:var(--bs-border-radius) !important}.rounded-top-0{border-top-left-radius:0 !important;border-top-right-radius:0 !important}.rounded-top-1{border-top-left-radius:var(--bs-border-radius-sm) !important;border-top-right-radius:var(--bs-border-radius-sm) !important}.rounded-top-2{border-top-left-radius:var(--bs-border-radius) !important;border-top-right-radius:var(--bs-border-radius) !important}.rounded-top-3{border-top-left-radius:var(--bs-border-radius-lg) !important;border-top-right-radius:var(--bs-border-radius-lg) !important}.rounded-top-4{border-top-left-radius:var(--bs-border-radius-xl) !important;border-top-right-radius:var(--bs-border-radius-xl) !important}.rounded-top-5{border-top-left-radius:var(--bs-border-radius-xxl) !important;border-top-right-radius:var(--bs-border-radius-xxl) !important}.rounded-top-circle{border-top-left-radius:50% !important;border-top-right-radius:50% !important}.rounded-top-pill{border-top-left-radius:var(--bs-border-radius-pill) !important;border-top-right-radius:var(--bs-border-radius-pill) !important}.rounded-end{border-top-right-radius:var(--bs-border-radius) !important;border-bottom-right-radius:var(--bs-border-radius) !important}.rounded-end-0{border-top-right-radius:0 !important;border-bottom-right-radius:0 !important}.rounded-end-1{border-top-right-radius:var(--bs-border-radius-sm) !important;border-bottom-right-radius:var(--bs-border-radius-sm) !important}.rounded-end-2{border-top-right-radius:var(--bs-border-radius) !important;border-bottom-right-radius:var(--bs-border-radius) !important}.rounded-end-3{border-top-right-radius:var(--bs-border-radius-lg) !important;border-bottom-right-radius:var(--bs-border-radius-lg) !important}.rounded-end-4{border-top-right-radius:var(--bs-border-radius-xl) !important;border-bottom-right-radius:var(--bs-border-radius-xl) !important}.rounded-end-5{border-top-right-radius:var(--bs-border-radius-xxl) !important;border-bottom-right-radius:var(--bs-border-radius-xxl) !important}.rounded-end-circle{border-top-right-radius:50% !important;border-bottom-right-radius:50% !important}.rounded-end-pill{border-top-right-radius:var(--bs-border-radius-pill) !important;border-bottom-right-radius:var(--bs-border-radius-pill) !important}.rounded-bottom{border-bottom-right-radius:var(--bs-border-radius) !important;border-bottom-left-radius:var(--bs-border-radius) !important}.rounded-bottom-0{border-bottom-right-radius:0 !important;border-bottom-left-radius:0 !important}.rounded-bottom-1{border-bottom-right-radius:var(--bs-border-radius-sm) !important;border-bottom-left-radius:var(--bs-border-radius-sm) !important}.rounded-bottom-2{border-bottom-right-radius:var(--bs-border-radius) !important;border-bottom-left-radius:var(--bs-border-radius) !important}.rounded-bottom-3{border-bottom-right-radius:var(--bs-border-radius-lg) !important;border-bottom-left-radius:var(--bs-border-radius-lg) !important}.rounded-bottom-4{border-bottom-right-radius:var(--bs-border-radius-xl) !important;border-bottom-left-radius:var(--bs-border-radius-xl) !important}.rounded-bottom-5{border-bottom-right-radius:var(--bs-border-radius-xxl) !important;border-bottom-left-radius:var(--bs-border-radius-xxl) !important}.rounded-bottom-circle{border-bottom-right-radius:50% !important;border-bottom-left-radius:50% !important}.rounded-bottom-pill{border-bottom-right-radius:var(--bs-border-radius-pill) !important;border-bottom-left-radius:var(--bs-border-radius-pill) !important}.rounded-start{border-bottom-left-radius:var(--bs-border-radius) !important;border-top-left-radius:var(--bs-border-radius) !important}.rounded-start-0{border-bottom-left-radius:0 !important;border-top-left-radius:0 !important}.rounded-start-1{border-bottom-left-radius:var(--bs-border-radius-sm) !important;border-top-left-radius:var(--bs-border-radius-sm) !important}.rounded-start-2{border-bottom-left-radius:var(--bs-border-radius) !important;border-top-left-radius:var(--bs-border-radius) !important}.rounded-start-3{border-bottom-left-radius:var(--bs-border-radius-lg) !important;border-top-left-radius:var(--bs-border-radius-lg) !important}.rounded-start-4{border-bottom-left-radius:var(--bs-border-radius-xl) !important;border-top-left-radius:var(--bs-border-radius-xl) !important}.rounded-start-5{border-bottom-left-radius:var(--bs-border-radius-xxl) !important;border-top-left-radius:var(--bs-border-radius-xxl) !important}.rounded-start-circle{border-bottom-left-radius:50% !important;border-top-left-radius:50% !important}.rounded-start-pill{border-bottom-left-radius:var(--bs-border-radius-pill) !important;border-top-left-radius:var(--bs-border-radius-pill) !important}.visible{visibility:visible !important}.invisible{visibility:hidden !important}.z-n1{z-index:-1 !important}.z-0{z-index:0 !important}.z-1{z-index:1 !important}.z-2{z-index:2 !important}.z-3{z-index:3 !important}@media(min-width: 576px){.float-sm-start{float:left !important}.float-sm-end{float:right !important}.float-sm-none{float:none !important}.object-fit-sm-contain{object-fit:contain !important}.object-fit-sm-cover{object-fit:cover !important}.object-fit-sm-fill{object-fit:fill !important}.object-fit-sm-scale{object-fit:scale-down !important}.object-fit-sm-none{object-fit:none !important}.d-sm-inline{display:inline !important}.d-sm-inline-block{display:inline-block !important}.d-sm-block{display:block !important}.d-sm-grid{display:grid !important}.d-sm-inline-grid{display:inline-grid !important}.d-sm-table{display:table !important}.d-sm-table-row{display:table-row !important}.d-sm-table-cell{display:table-cell !important}.d-sm-flex{display:flex !important}.d-sm-inline-flex{display:inline-flex !important}.d-sm-none{display:none !important}.flex-sm-fill{flex:1 1 auto !important}.flex-sm-row{flex-direction:row !important}.flex-sm-column{flex-direction:column !important}.flex-sm-row-reverse{flex-direction:row-reverse !important}.flex-sm-column-reverse{flex-direction:column-reverse !important}.flex-sm-grow-0{flex-grow:0 !important}.flex-sm-grow-1{flex-grow:1 !important}.flex-sm-shrink-0{flex-shrink:0 !important}.flex-sm-shrink-1{flex-shrink:1 !important}.flex-sm-wrap{flex-wrap:wrap !important}.flex-sm-nowrap{flex-wrap:nowrap !important}.flex-sm-wrap-reverse{flex-wrap:wrap-reverse !important}.justify-content-sm-start{justify-content:flex-start !important}.justify-content-sm-end{justify-content:flex-end !important}.justify-content-sm-center{justify-content:center !important}.justify-content-sm-between{justify-content:space-between !important}.justify-content-sm-around{justify-content:space-around !important}.justify-content-sm-evenly{justify-content:space-evenly !important}.align-items-sm-start{align-items:flex-start !important}.align-items-sm-end{align-items:flex-end !important}.align-items-sm-center{align-items:center !important}.align-items-sm-baseline{align-items:baseline !important}.align-items-sm-stretch{align-items:stretch !important}.align-content-sm-start{align-content:flex-start !important}.align-content-sm-end{align-content:flex-end !important}.align-content-sm-center{align-content:center !important}.align-content-sm-between{align-content:space-between !important}.align-content-sm-around{align-content:space-around !important}.align-content-sm-stretch{align-content:stretch !important}.align-self-sm-auto{align-self:auto !important}.align-self-sm-start{align-self:flex-start !important}.align-self-sm-end{align-self:flex-end !important}.align-self-sm-center{align-self:center !important}.align-self-sm-baseline{align-self:baseline !important}.align-self-sm-stretch{align-self:stretch !important}.order-sm-first{order:-1 !important}.order-sm-0{order:0 !important}.order-sm-1{order:1 !important}.order-sm-2{order:2 !important}.order-sm-3{order:3 !important}.order-sm-4{order:4 !important}.order-sm-5{order:5 !important}.order-sm-last{order:6 !important}.m-sm-0{margin:0 !important}.m-sm-1{margin:.25rem !important}.m-sm-2{margin:.5rem !important}.m-sm-3{margin:1rem !important}.m-sm-4{margin:1.5rem !important}.m-sm-5{margin:3rem !important}.m-sm-auto{margin:auto !important}.mx-sm-0{margin-right:0 !important;margin-left:0 !important}.mx-sm-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-sm-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-sm-3{margin-right:1rem !important;margin-left:1rem !important}.mx-sm-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-sm-5{margin-right:3rem !important;margin-left:3rem !important}.mx-sm-auto{margin-right:auto !important;margin-left:auto !important}.my-sm-0{margin-top:0 !important;margin-bottom:0 !important}.my-sm-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-sm-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-sm-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-sm-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-sm-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-sm-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-sm-0{margin-top:0 !important}.mt-sm-1{margin-top:.25rem !important}.mt-sm-2{margin-top:.5rem !important}.mt-sm-3{margin-top:1rem !important}.mt-sm-4{margin-top:1.5rem !important}.mt-sm-5{margin-top:3rem !important}.mt-sm-auto{margin-top:auto !important}.me-sm-0{margin-right:0 !important}.me-sm-1{margin-right:.25rem !important}.me-sm-2{margin-right:.5rem !important}.me-sm-3{margin-right:1rem !important}.me-sm-4{margin-right:1.5rem !important}.me-sm-5{margin-right:3rem !important}.me-sm-auto{margin-right:auto !important}.mb-sm-0{margin-bottom:0 !important}.mb-sm-1{margin-bottom:.25rem !important}.mb-sm-2{margin-bottom:.5rem !important}.mb-sm-3{margin-bottom:1rem !important}.mb-sm-4{margin-bottom:1.5rem !important}.mb-sm-5{margin-bottom:3rem !important}.mb-sm-auto{margin-bottom:auto !important}.ms-sm-0{margin-left:0 !important}.ms-sm-1{margin-left:.25rem !important}.ms-sm-2{margin-left:.5rem !important}.ms-sm-3{margin-left:1rem !important}.ms-sm-4{margin-left:1.5rem !important}.ms-sm-5{margin-left:3rem !important}.ms-sm-auto{margin-left:auto !important}.p-sm-0{padding:0 !important}.p-sm-1{padding:.25rem !important}.p-sm-2{padding:.5rem !important}.p-sm-3{padding:1rem !important}.p-sm-4{padding:1.5rem !important}.p-sm-5{padding:3rem !important}.px-sm-0{padding-right:0 !important;padding-left:0 !important}.px-sm-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-sm-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-sm-3{padding-right:1rem !important;padding-left:1rem !important}.px-sm-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-sm-5{padding-right:3rem !important;padding-left:3rem !important}.py-sm-0{padding-top:0 !important;padding-bottom:0 !important}.py-sm-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-sm-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-sm-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-sm-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-sm-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-sm-0{padding-top:0 !important}.pt-sm-1{padding-top:.25rem !important}.pt-sm-2{padding-top:.5rem !important}.pt-sm-3{padding-top:1rem !important}.pt-sm-4{padding-top:1.5rem !important}.pt-sm-5{padding-top:3rem !important}.pe-sm-0{padding-right:0 !important}.pe-sm-1{padding-right:.25rem !important}.pe-sm-2{padding-right:.5rem !important}.pe-sm-3{padding-right:1rem !important}.pe-sm-4{padding-right:1.5rem !important}.pe-sm-5{padding-right:3rem !important}.pb-sm-0{padding-bottom:0 !important}.pb-sm-1{padding-bottom:.25rem !important}.pb-sm-2{padding-bottom:.5rem !important}.pb-sm-3{padding-bottom:1rem !important}.pb-sm-4{padding-bottom:1.5rem !important}.pb-sm-5{padding-bottom:3rem !important}.ps-sm-0{padding-left:0 !important}.ps-sm-1{padding-left:.25rem !important}.ps-sm-2{padding-left:.5rem !important}.ps-sm-3{padding-left:1rem !important}.ps-sm-4{padding-left:1.5rem !important}.ps-sm-5{padding-left:3rem !important}.gap-sm-0{gap:0 !important}.gap-sm-1{gap:.25rem !important}.gap-sm-2{gap:.5rem !important}.gap-sm-3{gap:1rem !important}.gap-sm-4{gap:1.5rem !important}.gap-sm-5{gap:3rem !important}.row-gap-sm-0{row-gap:0 !important}.row-gap-sm-1{row-gap:.25rem !important}.row-gap-sm-2{row-gap:.5rem !important}.row-gap-sm-3{row-gap:1rem !important}.row-gap-sm-4{row-gap:1.5rem !important}.row-gap-sm-5{row-gap:3rem !important}.column-gap-sm-0{column-gap:0 !important}.column-gap-sm-1{column-gap:.25rem !important}.column-gap-sm-2{column-gap:.5rem !important}.column-gap-sm-3{column-gap:1rem !important}.column-gap-sm-4{column-gap:1.5rem !important}.column-gap-sm-5{column-gap:3rem !important}.text-sm-start{text-align:left !important}.text-sm-end{text-align:right !important}.text-sm-center{text-align:center !important}}@media(min-width: 768px){.float-md-start{float:left !important}.float-md-end{float:right !important}.float-md-none{float:none !important}.object-fit-md-contain{object-fit:contain !important}.object-fit-md-cover{object-fit:cover !important}.object-fit-md-fill{object-fit:fill !important}.object-fit-md-scale{object-fit:scale-down !important}.object-fit-md-none{object-fit:none !important}.d-md-inline{display:inline !important}.d-md-inline-block{display:inline-block !important}.d-md-block{display:block !important}.d-md-grid{display:grid !important}.d-md-inline-grid{display:inline-grid !important}.d-md-table{display:table !important}.d-md-table-row{display:table-row !important}.d-md-table-cell{display:table-cell !important}.d-md-flex{display:flex !important}.d-md-inline-flex{display:inline-flex !important}.d-md-none{display:none !important}.flex-md-fill{flex:1 1 auto !important}.flex-md-row{flex-direction:row !important}.flex-md-column{flex-direction:column !important}.flex-md-row-reverse{flex-direction:row-reverse !important}.flex-md-column-reverse{flex-direction:column-reverse !important}.flex-md-grow-0{flex-grow:0 !important}.flex-md-grow-1{flex-grow:1 !important}.flex-md-shrink-0{flex-shrink:0 !important}.flex-md-shrink-1{flex-shrink:1 !important}.flex-md-wrap{flex-wrap:wrap !important}.flex-md-nowrap{flex-wrap:nowrap !important}.flex-md-wrap-reverse{flex-wrap:wrap-reverse !important}.justify-content-md-start{justify-content:flex-start !important}.justify-content-md-end{justify-content:flex-end !important}.justify-content-md-center{justify-content:center !important}.justify-content-md-between{justify-content:space-between !important}.justify-content-md-around{justify-content:space-around !important}.justify-content-md-evenly{justify-content:space-evenly !important}.align-items-md-start{align-items:flex-start !important}.align-items-md-end{align-items:flex-end !important}.align-items-md-center{align-items:center !important}.align-items-md-baseline{align-items:baseline !important}.align-items-md-stretch{align-items:stretch !important}.align-content-md-start{align-content:flex-start !important}.align-content-md-end{align-content:flex-end !important}.align-content-md-center{align-content:center !important}.align-content-md-between{align-content:space-between !important}.align-content-md-around{align-content:space-around !important}.align-content-md-stretch{align-content:stretch !important}.align-self-md-auto{align-self:auto !important}.align-self-md-start{align-self:flex-start !important}.align-self-md-end{align-self:flex-end !important}.align-self-md-center{align-self:center !important}.align-self-md-baseline{align-self:baseline !important}.align-self-md-stretch{align-self:stretch !important}.order-md-first{order:-1 !important}.order-md-0{order:0 !important}.order-md-1{order:1 !important}.order-md-2{order:2 !important}.order-md-3{order:3 !important}.order-md-4{order:4 !important}.order-md-5{order:5 !important}.order-md-last{order:6 !important}.m-md-0{margin:0 !important}.m-md-1{margin:.25rem !important}.m-md-2{margin:.5rem !important}.m-md-3{margin:1rem !important}.m-md-4{margin:1.5rem !important}.m-md-5{margin:3rem !important}.m-md-auto{margin:auto !important}.mx-md-0{margin-right:0 !important;margin-left:0 !important}.mx-md-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-md-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-md-3{margin-right:1rem !important;margin-left:1rem !important}.mx-md-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-md-5{margin-right:3rem !important;margin-left:3rem !important}.mx-md-auto{margin-right:auto !important;margin-left:auto !important}.my-md-0{margin-top:0 !important;margin-bottom:0 !important}.my-md-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-md-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-md-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-md-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-md-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-md-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-md-0{margin-top:0 !important}.mt-md-1{margin-top:.25rem !important}.mt-md-2{margin-top:.5rem !important}.mt-md-3{margin-top:1rem !important}.mt-md-4{margin-top:1.5rem !important}.mt-md-5{margin-top:3rem !important}.mt-md-auto{margin-top:auto !important}.me-md-0{margin-right:0 !important}.me-md-1{margin-right:.25rem !important}.me-md-2{margin-right:.5rem !important}.me-md-3{margin-right:1rem !important}.me-md-4{margin-right:1.5rem !important}.me-md-5{margin-right:3rem !important}.me-md-auto{margin-right:auto !important}.mb-md-0{margin-bottom:0 !important}.mb-md-1{margin-bottom:.25rem !important}.mb-md-2{margin-bottom:.5rem !important}.mb-md-3{margin-bottom:1rem !important}.mb-md-4{margin-bottom:1.5rem !important}.mb-md-5{margin-bottom:3rem !important}.mb-md-auto{margin-bottom:auto !important}.ms-md-0{margin-left:0 !important}.ms-md-1{margin-left:.25rem !important}.ms-md-2{margin-left:.5rem !important}.ms-md-3{margin-left:1rem !important}.ms-md-4{margin-left:1.5rem !important}.ms-md-5{margin-left:3rem !important}.ms-md-auto{margin-left:auto !important}.p-md-0{padding:0 !important}.p-md-1{padding:.25rem !important}.p-md-2{padding:.5rem !important}.p-md-3{padding:1rem !important}.p-md-4{padding:1.5rem !important}.p-md-5{padding:3rem !important}.px-md-0{padding-right:0 !important;padding-left:0 !important}.px-md-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-md-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-md-3{padding-right:1rem !important;padding-left:1rem !important}.px-md-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-md-5{padding-right:3rem !important;padding-left:3rem !important}.py-md-0{padding-top:0 !important;padding-bottom:0 !important}.py-md-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-md-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-md-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-md-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-md-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-md-0{padding-top:0 !important}.pt-md-1{padding-top:.25rem !important}.pt-md-2{padding-top:.5rem !important}.pt-md-3{padding-top:1rem !important}.pt-md-4{padding-top:1.5rem !important}.pt-md-5{padding-top:3rem !important}.pe-md-0{padding-right:0 !important}.pe-md-1{padding-right:.25rem !important}.pe-md-2{padding-right:.5rem !important}.pe-md-3{padding-right:1rem !important}.pe-md-4{padding-right:1.5rem !important}.pe-md-5{padding-right:3rem !important}.pb-md-0{padding-bottom:0 !important}.pb-md-1{padding-bottom:.25rem !important}.pb-md-2{padding-bottom:.5rem !important}.pb-md-3{padding-bottom:1rem !important}.pb-md-4{padding-bottom:1.5rem !important}.pb-md-5{padding-bottom:3rem !important}.ps-md-0{padding-left:0 !important}.ps-md-1{padding-left:.25rem !important}.ps-md-2{padding-left:.5rem !important}.ps-md-3{padding-left:1rem !important}.ps-md-4{padding-left:1.5rem !important}.ps-md-5{padding-left:3rem !important}.gap-md-0{gap:0 !important}.gap-md-1{gap:.25rem !important}.gap-md-2{gap:.5rem !important}.gap-md-3{gap:1rem !important}.gap-md-4{gap:1.5rem !important}.gap-md-5{gap:3rem !important}.row-gap-md-0{row-gap:0 !important}.row-gap-md-1{row-gap:.25rem !important}.row-gap-md-2{row-gap:.5rem !important}.row-gap-md-3{row-gap:1rem !important}.row-gap-md-4{row-gap:1.5rem !important}.row-gap-md-5{row-gap:3rem !important}.column-gap-md-0{column-gap:0 !important}.column-gap-md-1{column-gap:.25rem !important}.column-gap-md-2{column-gap:.5rem !important}.column-gap-md-3{column-gap:1rem !important}.column-gap-md-4{column-gap:1.5rem !important}.column-gap-md-5{column-gap:3rem !important}.text-md-start{text-align:left !important}.text-md-end{text-align:right !important}.text-md-center{text-align:center !important}}@media(min-width: 992px){.float-lg-start{float:left !important}.float-lg-end{float:right !important}.float-lg-none{float:none !important}.object-fit-lg-contain{object-fit:contain !important}.object-fit-lg-cover{object-fit:cover !important}.object-fit-lg-fill{object-fit:fill !important}.object-fit-lg-scale{object-fit:scale-down !important}.object-fit-lg-none{object-fit:none !important}.d-lg-inline{display:inline !important}.d-lg-inline-block{display:inline-block !important}.d-lg-block{display:block !important}.d-lg-grid{display:grid !important}.d-lg-inline-grid{display:inline-grid !important}.d-lg-table{display:table !important}.d-lg-table-row{display:table-row !important}.d-lg-table-cell{display:table-cell !important}.d-lg-flex{display:flex !important}.d-lg-inline-flex{display:inline-flex !important}.d-lg-none{display:none !important}.flex-lg-fill{flex:1 1 auto !important}.flex-lg-row{flex-direction:row !important}.flex-lg-column{flex-direction:column !important}.flex-lg-row-reverse{flex-direction:row-reverse !important}.flex-lg-column-reverse{flex-direction:column-reverse !important}.flex-lg-grow-0{flex-grow:0 !important}.flex-lg-grow-1{flex-grow:1 !important}.flex-lg-shrink-0{flex-shrink:0 !important}.flex-lg-shrink-1{flex-shrink:1 !important}.flex-lg-wrap{flex-wrap:wrap !important}.flex-lg-nowrap{flex-wrap:nowrap !important}.flex-lg-wrap-reverse{flex-wrap:wrap-reverse !important}.justify-content-lg-start{justify-content:flex-start !important}.justify-content-lg-end{justify-content:flex-end !important}.justify-content-lg-center{justify-content:center !important}.justify-content-lg-between{justify-content:space-between !important}.justify-content-lg-around{justify-content:space-around !important}.justify-content-lg-evenly{justify-content:space-evenly !important}.align-items-lg-start{align-items:flex-start !important}.align-items-lg-end{align-items:flex-end !important}.align-items-lg-center{align-items:center !important}.align-items-lg-baseline{align-items:baseline !important}.align-items-lg-stretch{align-items:stretch !important}.align-content-lg-start{align-content:flex-start !important}.align-content-lg-end{align-content:flex-end !important}.align-content-lg-center{align-content:center !important}.align-content-lg-between{align-content:space-between !important}.align-content-lg-around{align-content:space-around !important}.align-content-lg-stretch{align-content:stretch !important}.align-self-lg-auto{align-self:auto !important}.align-self-lg-start{align-self:flex-start !important}.align-self-lg-end{align-self:flex-end !important}.align-self-lg-center{align-self:center !important}.align-self-lg-baseline{align-self:baseline !important}.align-self-lg-stretch{align-self:stretch !important}.order-lg-first{order:-1 !important}.order-lg-0{order:0 !important}.order-lg-1{order:1 !important}.order-lg-2{order:2 !important}.order-lg-3{order:3 !important}.order-lg-4{order:4 !important}.order-lg-5{order:5 !important}.order-lg-last{order:6 !important}.m-lg-0{margin:0 !important}.m-lg-1{margin:.25rem !important}.m-lg-2{margin:.5rem !important}.m-lg-3{margin:1rem !important}.m-lg-4{margin:1.5rem !important}.m-lg-5{margin:3rem !important}.m-lg-auto{margin:auto !important}.mx-lg-0{margin-right:0 !important;margin-left:0 !important}.mx-lg-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-lg-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-lg-3{margin-right:1rem !important;margin-left:1rem !important}.mx-lg-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-lg-5{margin-right:3rem !important;margin-left:3rem !important}.mx-lg-auto{margin-right:auto !important;margin-left:auto !important}.my-lg-0{margin-top:0 !important;margin-bottom:0 !important}.my-lg-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-lg-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-lg-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-lg-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-lg-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-lg-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-lg-0{margin-top:0 !important}.mt-lg-1{margin-top:.25rem !important}.mt-lg-2{margin-top:.5rem !important}.mt-lg-3{margin-top:1rem !important}.mt-lg-4{margin-top:1.5rem !important}.mt-lg-5{margin-top:3rem !important}.mt-lg-auto{margin-top:auto !important}.me-lg-0{margin-right:0 !important}.me-lg-1{margin-right:.25rem !important}.me-lg-2{margin-right:.5rem !important}.me-lg-3{margin-right:1rem !important}.me-lg-4{margin-right:1.5rem !important}.me-lg-5{margin-right:3rem !important}.me-lg-auto{margin-right:auto !important}.mb-lg-0{margin-bottom:0 !important}.mb-lg-1{margin-bottom:.25rem !important}.mb-lg-2{margin-bottom:.5rem !important}.mb-lg-3{margin-bottom:1rem !important}.mb-lg-4{margin-bottom:1.5rem !important}.mb-lg-5{margin-bottom:3rem !important}.mb-lg-auto{margin-bottom:auto !important}.ms-lg-0{margin-left:0 !important}.ms-lg-1{margin-left:.25rem !important}.ms-lg-2{margin-left:.5rem !important}.ms-lg-3{margin-left:1rem !important}.ms-lg-4{margin-left:1.5rem !important}.ms-lg-5{margin-left:3rem !important}.ms-lg-auto{margin-left:auto !important}.p-lg-0{padding:0 !important}.p-lg-1{padding:.25rem !important}.p-lg-2{padding:.5rem !important}.p-lg-3{padding:1rem !important}.p-lg-4{padding:1.5rem !important}.p-lg-5{padding:3rem !important}.px-lg-0{padding-right:0 !important;padding-left:0 !important}.px-lg-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-lg-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-lg-3{padding-right:1rem !important;padding-left:1rem !important}.px-lg-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-lg-5{padding-right:3rem !important;padding-left:3rem !important}.py-lg-0{padding-top:0 !important;padding-bottom:0 !important}.py-lg-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-lg-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-lg-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-lg-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-lg-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-lg-0{padding-top:0 !important}.pt-lg-1{padding-top:.25rem !important}.pt-lg-2{padding-top:.5rem !important}.pt-lg-3{padding-top:1rem !important}.pt-lg-4{padding-top:1.5rem !important}.pt-lg-5{padding-top:3rem !important}.pe-lg-0{padding-right:0 !important}.pe-lg-1{padding-right:.25rem !important}.pe-lg-2{padding-right:.5rem !important}.pe-lg-3{padding-right:1rem !important}.pe-lg-4{padding-right:1.5rem !important}.pe-lg-5{padding-right:3rem !important}.pb-lg-0{padding-bottom:0 !important}.pb-lg-1{padding-bottom:.25rem !important}.pb-lg-2{padding-bottom:.5rem !important}.pb-lg-3{padding-bottom:1rem !important}.pb-lg-4{padding-bottom:1.5rem !important}.pb-lg-5{padding-bottom:3rem !important}.ps-lg-0{padding-left:0 !important}.ps-lg-1{padding-left:.25rem !important}.ps-lg-2{padding-left:.5rem !important}.ps-lg-3{padding-left:1rem !important}.ps-lg-4{padding-left:1.5rem !important}.ps-lg-5{padding-left:3rem !important}.gap-lg-0{gap:0 !important}.gap-lg-1{gap:.25rem !important}.gap-lg-2{gap:.5rem !important}.gap-lg-3{gap:1rem !important}.gap-lg-4{gap:1.5rem !important}.gap-lg-5{gap:3rem !important}.row-gap-lg-0{row-gap:0 !important}.row-gap-lg-1{row-gap:.25rem !important}.row-gap-lg-2{row-gap:.5rem !important}.row-gap-lg-3{row-gap:1rem !important}.row-gap-lg-4{row-gap:1.5rem !important}.row-gap-lg-5{row-gap:3rem !important}.column-gap-lg-0{column-gap:0 !important}.column-gap-lg-1{column-gap:.25rem !important}.column-gap-lg-2{column-gap:.5rem !important}.column-gap-lg-3{column-gap:1rem !important}.column-gap-lg-4{column-gap:1.5rem !important}.column-gap-lg-5{column-gap:3rem !important}.text-lg-start{text-align:left !important}.text-lg-end{text-align:right !important}.text-lg-center{text-align:center !important}}@media(min-width: 1200px){.float-xl-start{float:left !important}.float-xl-end{float:right !important}.float-xl-none{float:none !important}.object-fit-xl-contain{object-fit:contain !important}.object-fit-xl-cover{object-fit:cover !important}.object-fit-xl-fill{object-fit:fill !important}.object-fit-xl-scale{object-fit:scale-down !important}.object-fit-xl-none{object-fit:none !important}.d-xl-inline{display:inline !important}.d-xl-inline-block{display:inline-block !important}.d-xl-block{display:block !important}.d-xl-grid{display:grid !important}.d-xl-inline-grid{display:inline-grid !important}.d-xl-table{display:table !important}.d-xl-table-row{display:table-row !important}.d-xl-table-cell{display:table-cell !important}.d-xl-flex{display:flex !important}.d-xl-inline-flex{display:inline-flex !important}.d-xl-none{display:none !important}.flex-xl-fill{flex:1 1 auto !important}.flex-xl-row{flex-direction:row !important}.flex-xl-column{flex-direction:column !important}.flex-xl-row-reverse{flex-direction:row-reverse !important}.flex-xl-column-reverse{flex-direction:column-reverse !important}.flex-xl-grow-0{flex-grow:0 !important}.flex-xl-grow-1{flex-grow:1 !important}.flex-xl-shrink-0{flex-shrink:0 !important}.flex-xl-shrink-1{flex-shrink:1 !important}.flex-xl-wrap{flex-wrap:wrap !important}.flex-xl-nowrap{flex-wrap:nowrap !important}.flex-xl-wrap-reverse{flex-wrap:wrap-reverse !important}.justify-content-xl-start{justify-content:flex-start !important}.justify-content-xl-end{justify-content:flex-end !important}.justify-content-xl-center{justify-content:center !important}.justify-content-xl-between{justify-content:space-between !important}.justify-content-xl-around{justify-content:space-around !important}.justify-content-xl-evenly{justify-content:space-evenly !important}.align-items-xl-start{align-items:flex-start !important}.align-items-xl-end{align-items:flex-end !important}.align-items-xl-center{align-items:center !important}.align-items-xl-baseline{align-items:baseline !important}.align-items-xl-stretch{align-items:stretch !important}.align-content-xl-start{align-content:flex-start !important}.align-content-xl-end{align-content:flex-end !important}.align-content-xl-center{align-content:center !important}.align-content-xl-between{align-content:space-between !important}.align-content-xl-around{align-content:space-around !important}.align-content-xl-stretch{align-content:stretch !important}.align-self-xl-auto{align-self:auto !important}.align-self-xl-start{align-self:flex-start !important}.align-self-xl-end{align-self:flex-end !important}.align-self-xl-center{align-self:center !important}.align-self-xl-baseline{align-self:baseline !important}.align-self-xl-stretch{align-self:stretch !important}.order-xl-first{order:-1 !important}.order-xl-0{order:0 !important}.order-xl-1{order:1 !important}.order-xl-2{order:2 !important}.order-xl-3{order:3 !important}.order-xl-4{order:4 !important}.order-xl-5{order:5 !important}.order-xl-last{order:6 !important}.m-xl-0{margin:0 !important}.m-xl-1{margin:.25rem !important}.m-xl-2{margin:.5rem !important}.m-xl-3{margin:1rem !important}.m-xl-4{margin:1.5rem !important}.m-xl-5{margin:3rem !important}.m-xl-auto{margin:auto !important}.mx-xl-0{margin-right:0 !important;margin-left:0 !important}.mx-xl-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-xl-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-xl-3{margin-right:1rem !important;margin-left:1rem !important}.mx-xl-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-xl-5{margin-right:3rem !important;margin-left:3rem !important}.mx-xl-auto{margin-right:auto !important;margin-left:auto !important}.my-xl-0{margin-top:0 !important;margin-bottom:0 !important}.my-xl-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-xl-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-xl-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-xl-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-xl-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-xl-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-xl-0{margin-top:0 !important}.mt-xl-1{margin-top:.25rem !important}.mt-xl-2{margin-top:.5rem !important}.mt-xl-3{margin-top:1rem !important}.mt-xl-4{margin-top:1.5rem !important}.mt-xl-5{margin-top:3rem !important}.mt-xl-auto{margin-top:auto !important}.me-xl-0{margin-right:0 !important}.me-xl-1{margin-right:.25rem !important}.me-xl-2{margin-right:.5rem !important}.me-xl-3{margin-right:1rem !important}.me-xl-4{margin-right:1.5rem !important}.me-xl-5{margin-right:3rem !important}.me-xl-auto{margin-right:auto !important}.mb-xl-0{margin-bottom:0 !important}.mb-xl-1{margin-bottom:.25rem !important}.mb-xl-2{margin-bottom:.5rem !important}.mb-xl-3{margin-bottom:1rem !important}.mb-xl-4{margin-bottom:1.5rem !important}.mb-xl-5{margin-bottom:3rem !important}.mb-xl-auto{margin-bottom:auto !important}.ms-xl-0{margin-left:0 !important}.ms-xl-1{margin-left:.25rem !important}.ms-xl-2{margin-left:.5rem !important}.ms-xl-3{margin-left:1rem !important}.ms-xl-4{margin-left:1.5rem !important}.ms-xl-5{margin-left:3rem !important}.ms-xl-auto{margin-left:auto !important}.p-xl-0{padding:0 !important}.p-xl-1{padding:.25rem !important}.p-xl-2{padding:.5rem !important}.p-xl-3{padding:1rem !important}.p-xl-4{padding:1.5rem !important}.p-xl-5{padding:3rem !important}.px-xl-0{padding-right:0 !important;padding-left:0 !important}.px-xl-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-xl-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-xl-3{padding-right:1rem !important;padding-left:1rem !important}.px-xl-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-xl-5{padding-right:3rem !important;padding-left:3rem !important}.py-xl-0{padding-top:0 !important;padding-bottom:0 !important}.py-xl-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-xl-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-xl-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-xl-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-xl-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-xl-0{padding-top:0 !important}.pt-xl-1{padding-top:.25rem !important}.pt-xl-2{padding-top:.5rem !important}.pt-xl-3{padding-top:1rem !important}.pt-xl-4{padding-top:1.5rem !important}.pt-xl-5{padding-top:3rem !important}.pe-xl-0{padding-right:0 !important}.pe-xl-1{padding-right:.25rem !important}.pe-xl-2{padding-right:.5rem !important}.pe-xl-3{padding-right:1rem !important}.pe-xl-4{padding-right:1.5rem !important}.pe-xl-5{padding-right:3rem !important}.pb-xl-0{padding-bottom:0 !important}.pb-xl-1{padding-bottom:.25rem !important}.pb-xl-2{padding-bottom:.5rem !important}.pb-xl-3{padding-bottom:1rem !important}.pb-xl-4{padding-bottom:1.5rem !important}.pb-xl-5{padding-bottom:3rem !important}.ps-xl-0{padding-left:0 !important}.ps-xl-1{padding-left:.25rem !important}.ps-xl-2{padding-left:.5rem !important}.ps-xl-3{padding-left:1rem !important}.ps-xl-4{padding-left:1.5rem !important}.ps-xl-5{padding-left:3rem !important}.gap-xl-0{gap:0 !important}.gap-xl-1{gap:.25rem !important}.gap-xl-2{gap:.5rem !important}.gap-xl-3{gap:1rem !important}.gap-xl-4{gap:1.5rem !important}.gap-xl-5{gap:3rem !important}.row-gap-xl-0{row-gap:0 !important}.row-gap-xl-1{row-gap:.25rem !important}.row-gap-xl-2{row-gap:.5rem !important}.row-gap-xl-3{row-gap:1rem !important}.row-gap-xl-4{row-gap:1.5rem !important}.row-gap-xl-5{row-gap:3rem !important}.column-gap-xl-0{column-gap:0 !important}.column-gap-xl-1{column-gap:.25rem !important}.column-gap-xl-2{column-gap:.5rem !important}.column-gap-xl-3{column-gap:1rem !important}.column-gap-xl-4{column-gap:1.5rem !important}.column-gap-xl-5{column-gap:3rem !important}.text-xl-start{text-align:left !important}.text-xl-end{text-align:right !important}.text-xl-center{text-align:center !important}}@media(min-width: 1400px){.float-xxl-start{float:left !important}.float-xxl-end{float:right !important}.float-xxl-none{float:none !important}.object-fit-xxl-contain{object-fit:contain !important}.object-fit-xxl-cover{object-fit:cover !important}.object-fit-xxl-fill{object-fit:fill !important}.object-fit-xxl-scale{object-fit:scale-down !important}.object-fit-xxl-none{object-fit:none !important}.d-xxl-inline{display:inline !important}.d-xxl-inline-block{display:inline-block !important}.d-xxl-block{display:block !important}.d-xxl-grid{display:grid !important}.d-xxl-inline-grid{display:inline-grid !important}.d-xxl-table{display:table !important}.d-xxl-table-row{display:table-row !important}.d-xxl-table-cell{display:table-cell !important}.d-xxl-flex{display:flex !important}.d-xxl-inline-flex{display:inline-flex !important}.d-xxl-none{display:none !important}.flex-xxl-fill{flex:1 1 auto !important}.flex-xxl-row{flex-direction:row !important}.flex-xxl-column{flex-direction:column !important}.flex-xxl-row-reverse{flex-direction:row-reverse !important}.flex-xxl-column-reverse{flex-direction:column-reverse !important}.flex-xxl-grow-0{flex-grow:0 !important}.flex-xxl-grow-1{flex-grow:1 !important}.flex-xxl-shrink-0{flex-shrink:0 !important}.flex-xxl-shrink-1{flex-shrink:1 !important}.flex-xxl-wrap{flex-wrap:wrap !important}.flex-xxl-nowrap{flex-wrap:nowrap !important}.flex-xxl-wrap-reverse{flex-wrap:wrap-reverse !important}.justify-content-xxl-start{justify-content:flex-start !important}.justify-content-xxl-end{justify-content:flex-end !important}.justify-content-xxl-center{justify-content:center !important}.justify-content-xxl-between{justify-content:space-between !important}.justify-content-xxl-around{justify-content:space-around !important}.justify-content-xxl-evenly{justify-content:space-evenly !important}.align-items-xxl-start{align-items:flex-start !important}.align-items-xxl-end{align-items:flex-end !important}.align-items-xxl-center{align-items:center !important}.align-items-xxl-baseline{align-items:baseline !important}.align-items-xxl-stretch{align-items:stretch !important}.align-content-xxl-start{align-content:flex-start !important}.align-content-xxl-end{align-content:flex-end !important}.align-content-xxl-center{align-content:center !important}.align-content-xxl-between{align-content:space-between !important}.align-content-xxl-around{align-content:space-around !important}.align-content-xxl-stretch{align-content:stretch !important}.align-self-xxl-auto{align-self:auto !important}.align-self-xxl-start{align-self:flex-start !important}.align-self-xxl-end{align-self:flex-end !important}.align-self-xxl-center{align-self:center !important}.align-self-xxl-baseline{align-self:baseline !important}.align-self-xxl-stretch{align-self:stretch !important}.order-xxl-first{order:-1 !important}.order-xxl-0{order:0 !important}.order-xxl-1{order:1 !important}.order-xxl-2{order:2 !important}.order-xxl-3{order:3 !important}.order-xxl-4{order:4 !important}.order-xxl-5{order:5 !important}.order-xxl-last{order:6 !important}.m-xxl-0{margin:0 !important}.m-xxl-1{margin:.25rem !important}.m-xxl-2{margin:.5rem !important}.m-xxl-3{margin:1rem !important}.m-xxl-4{margin:1.5rem !important}.m-xxl-5{margin:3rem !important}.m-xxl-auto{margin:auto !important}.mx-xxl-0{margin-right:0 !important;margin-left:0 !important}.mx-xxl-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-xxl-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-xxl-3{margin-right:1rem !important;margin-left:1rem !important}.mx-xxl-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-xxl-5{margin-right:3rem !important;margin-left:3rem !important}.mx-xxl-auto{margin-right:auto !important;margin-left:auto !important}.my-xxl-0{margin-top:0 !important;margin-bottom:0 !important}.my-xxl-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-xxl-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-xxl-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-xxl-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-xxl-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-xxl-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-xxl-0{margin-top:0 !important}.mt-xxl-1{margin-top:.25rem !important}.mt-xxl-2{margin-top:.5rem !important}.mt-xxl-3{margin-top:1rem !important}.mt-xxl-4{margin-top:1.5rem !important}.mt-xxl-5{margin-top:3rem !important}.mt-xxl-auto{margin-top:auto !important}.me-xxl-0{margin-right:0 !important}.me-xxl-1{margin-right:.25rem !important}.me-xxl-2{margin-right:.5rem !important}.me-xxl-3{margin-right:1rem !important}.me-xxl-4{margin-right:1.5rem !important}.me-xxl-5{margin-right:3rem !important}.me-xxl-auto{margin-right:auto !important}.mb-xxl-0{margin-bottom:0 !important}.mb-xxl-1{margin-bottom:.25rem !important}.mb-xxl-2{margin-bottom:.5rem !important}.mb-xxl-3{margin-bottom:1rem !important}.mb-xxl-4{margin-bottom:1.5rem !important}.mb-xxl-5{margin-bottom:3rem !important}.mb-xxl-auto{margin-bottom:auto !important}.ms-xxl-0{margin-left:0 !important}.ms-xxl-1{margin-left:.25rem !important}.ms-xxl-2{margin-left:.5rem !important}.ms-xxl-3{margin-left:1rem !important}.ms-xxl-4{margin-left:1.5rem !important}.ms-xxl-5{margin-left:3rem !important}.ms-xxl-auto{margin-left:auto !important}.p-xxl-0{padding:0 !important}.p-xxl-1{padding:.25rem !important}.p-xxl-2{padding:.5rem !important}.p-xxl-3{padding:1rem !important}.p-xxl-4{padding:1.5rem !important}.p-xxl-5{padding:3rem !important}.px-xxl-0{padding-right:0 !important;padding-left:0 !important}.px-xxl-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-xxl-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-xxl-3{padding-right:1rem !important;padding-left:1rem !important}.px-xxl-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-xxl-5{padding-right:3rem !important;padding-left:3rem !important}.py-xxl-0{padding-top:0 !important;padding-bottom:0 !important}.py-xxl-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-xxl-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-xxl-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-xxl-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-xxl-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-xxl-0{padding-top:0 !important}.pt-xxl-1{padding-top:.25rem !important}.pt-xxl-2{padding-top:.5rem !important}.pt-xxl-3{padding-top:1rem !important}.pt-xxl-4{padding-top:1.5rem !important}.pt-xxl-5{padding-top:3rem !important}.pe-xxl-0{padding-right:0 !important}.pe-xxl-1{padding-right:.25rem !important}.pe-xxl-2{padding-right:.5rem !important}.pe-xxl-3{padding-right:1rem !important}.pe-xxl-4{padding-right:1.5rem !important}.pe-xxl-5{padding-right:3rem !important}.pb-xxl-0{padding-bottom:0 !important}.pb-xxl-1{padding-bottom:.25rem !important}.pb-xxl-2{padding-bottom:.5rem !important}.pb-xxl-3{padding-bottom:1rem !important}.pb-xxl-4{padding-bottom:1.5rem !important}.pb-xxl-5{padding-bottom:3rem !important}.ps-xxl-0{padding-left:0 !important}.ps-xxl-1{padding-left:.25rem !important}.ps-xxl-2{padding-left:.5rem !important}.ps-xxl-3{padding-left:1rem !important}.ps-xxl-4{padding-left:1.5rem !important}.ps-xxl-5{padding-left:3rem !important}.gap-xxl-0{gap:0 !important}.gap-xxl-1{gap:.25rem !important}.gap-xxl-2{gap:.5rem !important}.gap-xxl-3{gap:1rem !important}.gap-xxl-4{gap:1.5rem !important}.gap-xxl-5{gap:3rem !important}.row-gap-xxl-0{row-gap:0 !important}.row-gap-xxl-1{row-gap:.25rem !important}.row-gap-xxl-2{row-gap:.5rem !important}.row-gap-xxl-3{row-gap:1rem !important}.row-gap-xxl-4{row-gap:1.5rem !important}.row-gap-xxl-5{row-gap:3rem !important}.column-gap-xxl-0{column-gap:0 !important}.column-gap-xxl-1{column-gap:.25rem !important}.column-gap-xxl-2{column-gap:.5rem !important}.column-gap-xxl-3{column-gap:1rem !important}.column-gap-xxl-4{column-gap:1.5rem !important}.column-gap-xxl-5{column-gap:3rem !important}.text-xxl-start{text-align:left !important}.text-xxl-end{text-align:right !important}.text-xxl-center{text-align:center !important}}.bg-default{color:#000}.bg-primary{color:#fff}.bg-secondary{color:#fff}.bg-success{color:#fff}.bg-info{color:#000}.bg-warning{color:#000}.bg-danger{color:#fff}.bg-light{color:#000}.bg-dark{color:#fff}@media(min-width: 1200px){.fs-1{font-size:2rem !important}.fs-2{font-size:1.65rem !important}.fs-3{font-size:1.45rem !important}}@media print{.d-print-inline{display:inline !important}.d-print-inline-block{display:inline-block !important}.d-print-block{display:block !important}.d-print-grid{display:grid !important}.d-print-inline-grid{display:inline-grid !important}.d-print-table{display:table !important}.d-print-table-row{display:table-row !important}.d-print-table-cell{display:table-cell !important}.d-print-flex{display:flex !important}.d-print-inline-flex{display:inline-flex !important}.d-print-none{display:none !important}}.tab-content>.tab-pane.html-fill-container{display:none}.tab-content>.active.html-fill-container{display:flex}.tab-content.html-fill-container{padding:0}:root{--bslib-spacer: 1rem;--bslib-mb-spacer: var(--bslib-spacer, 1rem)}.bslib-mb-spacing{margin-bottom:var(--bslib-mb-spacer)}.bslib-gap-spacing{gap:var(--bslib-mb-spacer)}.bslib-gap-spacing>.bslib-mb-spacing,.bslib-gap-spacing>.form-group,.bslib-gap-spacing>p,.bslib-gap-spacing>pre{margin-bottom:0}.html-fill-container>.html-fill-item.bslib-mb-spacing{margin-bottom:0}.tab-content>.tab-pane.html-fill-container{display:none}.tab-content>.active.html-fill-container{display:flex}.tab-content.html-fill-container{padding:0}.bg-blue{--bslib-color-bg: #0d6efd;--bslib-color-fg: #ffffff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-blue{--bslib-color-fg: #0d6efd;color:var(--bslib-color-fg)}.bg-indigo{--bslib-color-bg: #6610f2;--bslib-color-fg: #ffffff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-indigo{--bslib-color-fg: #6610f2;color:var(--bslib-color-fg)}.bg-purple{--bslib-color-bg: #6f42c1;--bslib-color-fg: #ffffff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-purple{--bslib-color-fg: #6f42c1;color:var(--bslib-color-fg)}.bg-pink{--bslib-color-bg: #d63384;--bslib-color-fg: #ffffff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-pink{--bslib-color-fg: #d63384;color:var(--bslib-color-fg)}.bg-red{--bslib-color-bg: #dc3545;--bslib-color-fg: #ffffff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-red{--bslib-color-fg: #dc3545;color:var(--bslib-color-fg)}.bg-orange{--bslib-color-bg: #fd7e14;--bslib-color-fg: #000;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-orange{--bslib-color-fg: #fd7e14;color:var(--bslib-color-fg)}.bg-yellow{--bslib-color-bg: #ffc107;--bslib-color-fg: #000;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-yellow{--bslib-color-fg: #ffc107;color:var(--bslib-color-fg)}.bg-green{--bslib-color-bg: #198754;--bslib-color-fg: #ffffff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-green{--bslib-color-fg: #198754;color:var(--bslib-color-fg)}.bg-teal{--bslib-color-bg: #20c997;--bslib-color-fg: #000;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-teal{--bslib-color-fg: #20c997;color:var(--bslib-color-fg)}.bg-cyan{--bslib-color-bg: #0dcaf0;--bslib-color-fg: #000;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-cyan{--bslib-color-fg: #0dcaf0;color:var(--bslib-color-fg)}.text-default{--bslib-color-fg: #dee2e6}.bg-default{--bslib-color-bg: #dee2e6;--bslib-color-fg: #000}.text-primary{--bslib-color-fg: #0d6efd}.bg-primary{--bslib-color-bg: #0d6efd;--bslib-color-fg: #ffffff}.text-secondary{--bslib-color-fg: #6c757d}.bg-secondary{--bslib-color-bg: #6c757d;--bslib-color-fg: #ffffff}.text-success{--bslib-color-fg: #198754}.bg-success{--bslib-color-bg: #198754;--bslib-color-fg: #ffffff}.text-info{--bslib-color-fg: #0dcaf0}.bg-info{--bslib-color-bg: #0dcaf0;--bslib-color-fg: #000}.text-warning{--bslib-color-fg: #ffc107}.bg-warning{--bslib-color-bg: #ffc107;--bslib-color-fg: #000}.text-danger{--bslib-color-fg: #dc3545}.bg-danger{--bslib-color-bg: #dc3545;--bslib-color-fg: #ffffff}.text-light{--bslib-color-fg: #f8f9fa}.bg-light{--bslib-color-bg: #f8f9fa;--bslib-color-fg: #000}.text-dark{--bslib-color-fg: #212529}.bg-dark{--bslib-color-bg: #212529;--bslib-color-fg: #ffffff}.bg-gradient-blue-indigo{--bslib-color-fg: #ffffff;--bslib-color-bg: #3148f9;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #3148f9;color:#fff}.bg-gradient-blue-purple{--bslib-color-fg: #ffffff;--bslib-color-bg: #345ce5;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #345ce5;color:#fff}.bg-gradient-blue-pink{--bslib-color-fg: #ffffff;--bslib-color-bg: #5d56cd;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #5d56cd;color:#fff}.bg-gradient-blue-red{--bslib-color-fg: #ffffff;--bslib-color-bg: #6057b3;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #6057b3;color:#fff}.bg-gradient-blue-orange{--bslib-color-fg: #ffffff;--bslib-color-bg: #6d74a0;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #6d74a0;color:#fff}.bg-gradient-blue-yellow{--bslib-color-fg: #000;--bslib-color-bg: #6e8f9b;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #6e8f9b;color:#000}.bg-gradient-blue-green{--bslib-color-fg: #ffffff;--bslib-color-bg: #1278b9;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #1278b9;color:#fff}.bg-gradient-blue-teal{--bslib-color-fg: #000;--bslib-color-bg: #1592d4;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #1592d4;color:#000}.bg-gradient-blue-cyan{--bslib-color-fg: #000;--bslib-color-bg: #0d93f8;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #0d93f8;color:#000}.bg-gradient-indigo-blue{--bslib-color-fg: #ffffff;--bslib-color-bg: #4236f6;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #4236f6;color:#fff}.bg-gradient-indigo-purple{--bslib-color-fg: #ffffff;--bslib-color-bg: #6a24de;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #6a24de;color:#fff}.bg-gradient-indigo-pink{--bslib-color-fg: #ffffff;--bslib-color-bg: #931ec6;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #931ec6;color:#fff}.bg-gradient-indigo-red{--bslib-color-fg: #ffffff;--bslib-color-bg: #951fad;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #951fad;color:#fff}.bg-gradient-indigo-orange{--bslib-color-fg: #ffffff;--bslib-color-bg: #a23c99;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #a23c99;color:#fff}.bg-gradient-indigo-yellow{--bslib-color-fg: #ffffff;--bslib-color-bg: #a35794;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #a35794;color:#fff}.bg-gradient-indigo-green{--bslib-color-fg: #ffffff;--bslib-color-bg: #4740b3;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #4740b3;color:#fff}.bg-gradient-indigo-teal{--bslib-color-fg: #ffffff;--bslib-color-bg: #4a5ace;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #4a5ace;color:#fff}.bg-gradient-indigo-cyan{--bslib-color-fg: #ffffff;--bslib-color-bg: #425af1;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #425af1;color:#fff}.bg-gradient-purple-blue{--bslib-color-fg: #ffffff;--bslib-color-bg: #4854d9;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #4854d9;color:#fff}.bg-gradient-purple-indigo{--bslib-color-fg: #ffffff;--bslib-color-bg: #6b2ed5;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #6b2ed5;color:#fff}.bg-gradient-purple-pink{--bslib-color-fg: #ffffff;--bslib-color-bg: #983ca9;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #983ca9;color:#fff}.bg-gradient-purple-red{--bslib-color-fg: #ffffff;--bslib-color-bg: #9b3d8f;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #9b3d8f;color:#fff}.bg-gradient-purple-orange{--bslib-color-fg: #ffffff;--bslib-color-bg: #a85a7c;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #a85a7c;color:#fff}.bg-gradient-purple-yellow{--bslib-color-fg: #000;--bslib-color-bg: #a97577;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #a97577;color:#000}.bg-gradient-purple-green{--bslib-color-fg: #ffffff;--bslib-color-bg: #4d5e95;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #4d5e95;color:#fff}.bg-gradient-purple-teal{--bslib-color-fg: #ffffff;--bslib-color-bg: #4f78b0;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #4f78b0;color:#fff}.bg-gradient-purple-cyan{--bslib-color-fg: #000;--bslib-color-bg: #4878d4;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #4878d4;color:#000}.bg-gradient-pink-blue{--bslib-color-fg: #ffffff;--bslib-color-bg: #864bb4;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #864bb4;color:#fff}.bg-gradient-pink-indigo{--bslib-color-fg: #ffffff;--bslib-color-bg: #a925b0;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #a925b0;color:#fff}.bg-gradient-pink-purple{--bslib-color-fg: #ffffff;--bslib-color-bg: #ad399c;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #ad399c;color:#fff}.bg-gradient-pink-red{--bslib-color-fg: #ffffff;--bslib-color-bg: #d8346b;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #d8346b;color:#fff}.bg-gradient-pink-orange{--bslib-color-fg: #000;--bslib-color-bg: #e65157;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #e65157;color:#000}.bg-gradient-pink-yellow{--bslib-color-fg: #000;--bslib-color-bg: #e66c52;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #e66c52;color:#000}.bg-gradient-pink-green{--bslib-color-fg: #ffffff;--bslib-color-bg: #8a5571;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #8a5571;color:#fff}.bg-gradient-pink-teal{--bslib-color-fg: #000;--bslib-color-bg: #8d6f8c;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #8d6f8c;color:#000}.bg-gradient-pink-cyan{--bslib-color-fg: #000;--bslib-color-bg: #866faf;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #866faf;color:#000}.bg-gradient-red-blue{--bslib-color-fg: #ffffff;--bslib-color-bg: #894c8f;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #894c8f;color:#fff}.bg-gradient-red-indigo{--bslib-color-fg: #ffffff;--bslib-color-bg: #ad268a;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #ad268a;color:#fff}.bg-gradient-red-purple{--bslib-color-fg: #ffffff;--bslib-color-bg: #b03a77;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #b03a77;color:#fff}.bg-gradient-red-pink{--bslib-color-fg: #ffffff;--bslib-color-bg: #da345e;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #da345e;color:#fff}.bg-gradient-red-orange{--bslib-color-fg: #000;--bslib-color-bg: #e95231;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #e95231;color:#000}.bg-gradient-red-yellow{--bslib-color-fg: #000;--bslib-color-bg: #ea6d2c;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #ea6d2c;color:#000}.bg-gradient-red-green{--bslib-color-fg: #ffffff;--bslib-color-bg: #8e564b;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #8e564b;color:#fff}.bg-gradient-red-teal{--bslib-color-fg: #000;--bslib-color-bg: #917066;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #917066;color:#000}.bg-gradient-red-cyan{--bslib-color-fg: #000;--bslib-color-bg: #897189;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #897189;color:#000}.bg-gradient-orange-blue{--bslib-color-fg: #000;--bslib-color-bg: #9d7871;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #9d7871;color:#000}.bg-gradient-orange-indigo{--bslib-color-fg: #000;--bslib-color-bg: #c1526d;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #c1526d;color:#000}.bg-gradient-orange-purple{--bslib-color-fg: #000;--bslib-color-bg: #c46659;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #c46659;color:#000}.bg-gradient-orange-pink{--bslib-color-fg: #000;--bslib-color-bg: #ed6041;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #ed6041;color:#000}.bg-gradient-orange-red{--bslib-color-fg: #000;--bslib-color-bg: #f06128;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #f06128;color:#000}.bg-gradient-orange-yellow{--bslib-color-fg: #000;--bslib-color-bg: #fe990f;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #fe990f;color:#000}.bg-gradient-orange-green{--bslib-color-fg: #000;--bslib-color-bg: #a2822e;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #a2822e;color:#000}.bg-gradient-orange-teal{--bslib-color-fg: #000;--bslib-color-bg: #a59c48;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #a59c48;color:#000}.bg-gradient-orange-cyan{--bslib-color-fg: #000;--bslib-color-bg: #9d9c6c;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #9d9c6c;color:#000}.bg-gradient-yellow-blue{--bslib-color-fg: #000;--bslib-color-bg: #9ea069;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #9ea069;color:#000}.bg-gradient-yellow-indigo{--bslib-color-fg: #000;--bslib-color-bg: #c27a65;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #c27a65;color:#000}.bg-gradient-yellow-purple{--bslib-color-fg: #000;--bslib-color-bg: #c58e51;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #c58e51;color:#000}.bg-gradient-yellow-pink{--bslib-color-fg: #000;--bslib-color-bg: #ef8839;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #ef8839;color:#000}.bg-gradient-yellow-red{--bslib-color-fg: #000;--bslib-color-bg: #f18920;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #f18920;color:#000}.bg-gradient-yellow-orange{--bslib-color-fg: #000;--bslib-color-bg: #fea60c;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #fea60c;color:#000}.bg-gradient-yellow-green{--bslib-color-fg: #000;--bslib-color-bg: #a3aa26;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #a3aa26;color:#000}.bg-gradient-yellow-teal{--bslib-color-fg: #000;--bslib-color-bg: #a6c441;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #a6c441;color:#000}.bg-gradient-yellow-cyan{--bslib-color-fg: #000;--bslib-color-bg: #9ec564;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #9ec564;color:#000}.bg-gradient-green-blue{--bslib-color-fg: #ffffff;--bslib-color-bg: #147d98;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #147d98;color:#fff}.bg-gradient-green-indigo{--bslib-color-fg: #ffffff;--bslib-color-bg: #385793;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #385793;color:#fff}.bg-gradient-green-purple{--bslib-color-fg: #ffffff;--bslib-color-bg: #3b6b80;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #3b6b80;color:#fff}.bg-gradient-green-pink{--bslib-color-fg: #ffffff;--bslib-color-bg: #656567;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #656567;color:#fff}.bg-gradient-green-red{--bslib-color-fg: #ffffff;--bslib-color-bg: #67664e;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #67664e;color:#fff}.bg-gradient-green-orange{--bslib-color-fg: #000;--bslib-color-bg: #74833a;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #74833a;color:#000}.bg-gradient-green-yellow{--bslib-color-fg: #000;--bslib-color-bg: #759e35;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #759e35;color:#000}.bg-gradient-green-teal{--bslib-color-fg: #000;--bslib-color-bg: #1ca16f;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #1ca16f;color:#000}.bg-gradient-green-cyan{--bslib-color-fg: #000;--bslib-color-bg: #14a292;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #14a292;color:#000}.bg-gradient-teal-blue{--bslib-color-fg: #000;--bslib-color-bg: #18a5c0;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #18a5c0;color:#000}.bg-gradient-teal-indigo{--bslib-color-fg: #000;--bslib-color-bg: #3c7fbb;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #3c7fbb;color:#000}.bg-gradient-teal-purple{--bslib-color-fg: #000;--bslib-color-bg: #4093a8;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #4093a8;color:#000}.bg-gradient-teal-pink{--bslib-color-fg: #000;--bslib-color-bg: #698d8f;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #698d8f;color:#000}.bg-gradient-teal-red{--bslib-color-fg: #000;--bslib-color-bg: #6b8e76;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #6b8e76;color:#000}.bg-gradient-teal-orange{--bslib-color-fg: #000;--bslib-color-bg: #78ab63;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #78ab63;color:#000}.bg-gradient-teal-yellow{--bslib-color-fg: #000;--bslib-color-bg: #79c65d;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #79c65d;color:#000}.bg-gradient-teal-green{--bslib-color-fg: #000;--bslib-color-bg: #1daf7c;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #1daf7c;color:#000}.bg-gradient-teal-cyan{--bslib-color-fg: #000;--bslib-color-bg: #18c9bb;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #18c9bb;color:#000}.bg-gradient-cyan-blue{--bslib-color-fg: #000;--bslib-color-bg: #0da5f5;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #0da5f5;color:#000}.bg-gradient-cyan-indigo{--bslib-color-fg: #000;--bslib-color-bg: #3180f1;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #3180f1;color:#000}.bg-gradient-cyan-purple{--bslib-color-fg: #000;--bslib-color-bg: #3494dd;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #3494dd;color:#000}.bg-gradient-cyan-pink{--bslib-color-fg: #000;--bslib-color-bg: #5d8ec5;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #5d8ec5;color:#000}.bg-gradient-cyan-red{--bslib-color-fg: #000;--bslib-color-bg: #608eac;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #608eac;color:#000}.bg-gradient-cyan-orange{--bslib-color-fg: #000;--bslib-color-bg: #6dac98;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #6dac98;color:#000}.bg-gradient-cyan-yellow{--bslib-color-fg: #000;--bslib-color-bg: #6ec693;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #6ec693;color:#000}.bg-gradient-cyan-green{--bslib-color-fg: #000;--bslib-color-bg: #12afb2;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #12afb2;color:#000}.bg-gradient-cyan-teal{--bslib-color-fg: #000;--bslib-color-bg: #15cacc;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #15cacc;color:#000}.bg-blue{--bslib-color-bg: #0d6efd;--bslib-color-fg: #ffffff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-blue{--bslib-color-fg: #0d6efd;color:var(--bslib-color-fg)}.bg-indigo{--bslib-color-bg: #6610f2;--bslib-color-fg: #ffffff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-indigo{--bslib-color-fg: #6610f2;color:var(--bslib-color-fg)}.bg-purple{--bslib-color-bg: #6f42c1;--bslib-color-fg: #ffffff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-purple{--bslib-color-fg: #6f42c1;color:var(--bslib-color-fg)}.bg-pink{--bslib-color-bg: #d63384;--bslib-color-fg: #ffffff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-pink{--bslib-color-fg: #d63384;color:var(--bslib-color-fg)}.bg-red{--bslib-color-bg: #dc3545;--bslib-color-fg: #ffffff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-red{--bslib-color-fg: #dc3545;color:var(--bslib-color-fg)}.bg-orange{--bslib-color-bg: #fd7e14;--bslib-color-fg: #000;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-orange{--bslib-color-fg: #fd7e14;color:var(--bslib-color-fg)}.bg-yellow{--bslib-color-bg: #ffc107;--bslib-color-fg: #000;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-yellow{--bslib-color-fg: #ffc107;color:var(--bslib-color-fg)}.bg-green{--bslib-color-bg: #198754;--bslib-color-fg: #ffffff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-green{--bslib-color-fg: #198754;color:var(--bslib-color-fg)}.bg-teal{--bslib-color-bg: #20c997;--bslib-color-fg: #000;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-teal{--bslib-color-fg: #20c997;color:var(--bslib-color-fg)}.bg-cyan{--bslib-color-bg: #0dcaf0;--bslib-color-fg: #000;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-cyan{--bslib-color-fg: #0dcaf0;color:var(--bslib-color-fg)}.text-default{--bslib-color-fg: #dee2e6}.bg-default{--bslib-color-bg: #dee2e6;--bslib-color-fg: #000}.text-primary{--bslib-color-fg: #0d6efd}.bg-primary{--bslib-color-bg: #0d6efd;--bslib-color-fg: #ffffff}.text-secondary{--bslib-color-fg: #6c757d}.bg-secondary{--bslib-color-bg: #6c757d;--bslib-color-fg: #ffffff}.text-success{--bslib-color-fg: #198754}.bg-success{--bslib-color-bg: #198754;--bslib-color-fg: #ffffff}.text-info{--bslib-color-fg: #0dcaf0}.bg-info{--bslib-color-bg: #0dcaf0;--bslib-color-fg: #000}.text-warning{--bslib-color-fg: #ffc107}.bg-warning{--bslib-color-bg: #ffc107;--bslib-color-fg: #000}.text-danger{--bslib-color-fg: #dc3545}.bg-danger{--bslib-color-bg: #dc3545;--bslib-color-fg: #ffffff}.text-light{--bslib-color-fg: #f8f9fa}.bg-light{--bslib-color-bg: #f8f9fa;--bslib-color-fg: #000}.text-dark{--bslib-color-fg: #212529}.bg-dark{--bslib-color-bg: #212529;--bslib-color-fg: #ffffff}.bg-gradient-blue-indigo{--bslib-color-fg: #ffffff;--bslib-color-bg: #3148f9;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #3148f9;color:#fff}.bg-gradient-blue-purple{--bslib-color-fg: #ffffff;--bslib-color-bg: #345ce5;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #345ce5;color:#fff}.bg-gradient-blue-pink{--bslib-color-fg: #ffffff;--bslib-color-bg: #5d56cd;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #5d56cd;color:#fff}.bg-gradient-blue-red{--bslib-color-fg: #ffffff;--bslib-color-bg: #6057b3;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #6057b3;color:#fff}.bg-gradient-blue-orange{--bslib-color-fg: #ffffff;--bslib-color-bg: #6d74a0;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #6d74a0;color:#fff}.bg-gradient-blue-yellow{--bslib-color-fg: #000;--bslib-color-bg: #6e8f9b;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #6e8f9b;color:#000}.bg-gradient-blue-green{--bslib-color-fg: #ffffff;--bslib-color-bg: #1278b9;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #1278b9;color:#fff}.bg-gradient-blue-teal{--bslib-color-fg: #000;--bslib-color-bg: #1592d4;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #1592d4;color:#000}.bg-gradient-blue-cyan{--bslib-color-fg: #000;--bslib-color-bg: #0d93f8;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0d6efd var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #0d93f8;color:#000}.bg-gradient-indigo-blue{--bslib-color-fg: #ffffff;--bslib-color-bg: #4236f6;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #4236f6;color:#fff}.bg-gradient-indigo-purple{--bslib-color-fg: #ffffff;--bslib-color-bg: #6a24de;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #6a24de;color:#fff}.bg-gradient-indigo-pink{--bslib-color-fg: #ffffff;--bslib-color-bg: #931ec6;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #931ec6;color:#fff}.bg-gradient-indigo-red{--bslib-color-fg: #ffffff;--bslib-color-bg: #951fad;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #951fad;color:#fff}.bg-gradient-indigo-orange{--bslib-color-fg: #ffffff;--bslib-color-bg: #a23c99;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #a23c99;color:#fff}.bg-gradient-indigo-yellow{--bslib-color-fg: #ffffff;--bslib-color-bg: #a35794;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #a35794;color:#fff}.bg-gradient-indigo-green{--bslib-color-fg: #ffffff;--bslib-color-bg: #4740b3;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #4740b3;color:#fff}.bg-gradient-indigo-teal{--bslib-color-fg: #ffffff;--bslib-color-bg: #4a5ace;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #4a5ace;color:#fff}.bg-gradient-indigo-cyan{--bslib-color-fg: #ffffff;--bslib-color-bg: #425af1;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #425af1;color:#fff}.bg-gradient-purple-blue{--bslib-color-fg: #ffffff;--bslib-color-bg: #4854d9;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #4854d9;color:#fff}.bg-gradient-purple-indigo{--bslib-color-fg: #ffffff;--bslib-color-bg: #6b2ed5;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #6b2ed5;color:#fff}.bg-gradient-purple-pink{--bslib-color-fg: #ffffff;--bslib-color-bg: #983ca9;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #983ca9;color:#fff}.bg-gradient-purple-red{--bslib-color-fg: #ffffff;--bslib-color-bg: #9b3d8f;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #9b3d8f;color:#fff}.bg-gradient-purple-orange{--bslib-color-fg: #ffffff;--bslib-color-bg: #a85a7c;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #a85a7c;color:#fff}.bg-gradient-purple-yellow{--bslib-color-fg: #000;--bslib-color-bg: #a97577;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #a97577;color:#000}.bg-gradient-purple-green{--bslib-color-fg: #ffffff;--bslib-color-bg: #4d5e95;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #4d5e95;color:#fff}.bg-gradient-purple-teal{--bslib-color-fg: #ffffff;--bslib-color-bg: #4f78b0;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #4f78b0;color:#fff}.bg-gradient-purple-cyan{--bslib-color-fg: #000;--bslib-color-bg: #4878d4;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6f42c1 var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #4878d4;color:#000}.bg-gradient-pink-blue{--bslib-color-fg: #ffffff;--bslib-color-bg: #864bb4;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #864bb4;color:#fff}.bg-gradient-pink-indigo{--bslib-color-fg: #ffffff;--bslib-color-bg: #a925b0;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #a925b0;color:#fff}.bg-gradient-pink-purple{--bslib-color-fg: #ffffff;--bslib-color-bg: #ad399c;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #ad399c;color:#fff}.bg-gradient-pink-red{--bslib-color-fg: #ffffff;--bslib-color-bg: #d8346b;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #d8346b;color:#fff}.bg-gradient-pink-orange{--bslib-color-fg: #000;--bslib-color-bg: #e65157;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #e65157;color:#000}.bg-gradient-pink-yellow{--bslib-color-fg: #000;--bslib-color-bg: #e66c52;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #e66c52;color:#000}.bg-gradient-pink-green{--bslib-color-fg: #ffffff;--bslib-color-bg: #8a5571;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #8a5571;color:#fff}.bg-gradient-pink-teal{--bslib-color-fg: #000;--bslib-color-bg: #8d6f8c;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #8d6f8c;color:#000}.bg-gradient-pink-cyan{--bslib-color-fg: #000;--bslib-color-bg: #866faf;background:linear-gradient(var(--bg-gradient-deg, 140deg), #d63384 var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #866faf;color:#000}.bg-gradient-red-blue{--bslib-color-fg: #ffffff;--bslib-color-bg: #894c8f;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #894c8f;color:#fff}.bg-gradient-red-indigo{--bslib-color-fg: #ffffff;--bslib-color-bg: #ad268a;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #ad268a;color:#fff}.bg-gradient-red-purple{--bslib-color-fg: #ffffff;--bslib-color-bg: #b03a77;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #b03a77;color:#fff}.bg-gradient-red-pink{--bslib-color-fg: #ffffff;--bslib-color-bg: #da345e;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #da345e;color:#fff}.bg-gradient-red-orange{--bslib-color-fg: #000;--bslib-color-bg: #e95231;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #e95231;color:#000}.bg-gradient-red-yellow{--bslib-color-fg: #000;--bslib-color-bg: #ea6d2c;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #ea6d2c;color:#000}.bg-gradient-red-green{--bslib-color-fg: #ffffff;--bslib-color-bg: #8e564b;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #8e564b;color:#fff}.bg-gradient-red-teal{--bslib-color-fg: #000;--bslib-color-bg: #917066;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #917066;color:#000}.bg-gradient-red-cyan{--bslib-color-fg: #000;--bslib-color-bg: #897189;background:linear-gradient(var(--bg-gradient-deg, 140deg), #dc3545 var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #897189;color:#000}.bg-gradient-orange-blue{--bslib-color-fg: #000;--bslib-color-bg: #9d7871;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #9d7871;color:#000}.bg-gradient-orange-indigo{--bslib-color-fg: #000;--bslib-color-bg: #c1526d;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #c1526d;color:#000}.bg-gradient-orange-purple{--bslib-color-fg: #000;--bslib-color-bg: #c46659;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #c46659;color:#000}.bg-gradient-orange-pink{--bslib-color-fg: #000;--bslib-color-bg: #ed6041;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #ed6041;color:#000}.bg-gradient-orange-red{--bslib-color-fg: #000;--bslib-color-bg: #f06128;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #f06128;color:#000}.bg-gradient-orange-yellow{--bslib-color-fg: #000;--bslib-color-bg: #fe990f;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #fe990f;color:#000}.bg-gradient-orange-green{--bslib-color-fg: #000;--bslib-color-bg: #a2822e;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #a2822e;color:#000}.bg-gradient-orange-teal{--bslib-color-fg: #000;--bslib-color-bg: #a59c48;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #a59c48;color:#000}.bg-gradient-orange-cyan{--bslib-color-fg: #000;--bslib-color-bg: #9d9c6c;background:linear-gradient(var(--bg-gradient-deg, 140deg), #fd7e14 var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #9d9c6c;color:#000}.bg-gradient-yellow-blue{--bslib-color-fg: #000;--bslib-color-bg: #9ea069;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #9ea069;color:#000}.bg-gradient-yellow-indigo{--bslib-color-fg: #000;--bslib-color-bg: #c27a65;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #c27a65;color:#000}.bg-gradient-yellow-purple{--bslib-color-fg: #000;--bslib-color-bg: #c58e51;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #c58e51;color:#000}.bg-gradient-yellow-pink{--bslib-color-fg: #000;--bslib-color-bg: #ef8839;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #ef8839;color:#000}.bg-gradient-yellow-red{--bslib-color-fg: #000;--bslib-color-bg: #f18920;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #f18920;color:#000}.bg-gradient-yellow-orange{--bslib-color-fg: #000;--bslib-color-bg: #fea60c;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #fea60c;color:#000}.bg-gradient-yellow-green{--bslib-color-fg: #000;--bslib-color-bg: #a3aa26;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #a3aa26;color:#000}.bg-gradient-yellow-teal{--bslib-color-fg: #000;--bslib-color-bg: #a6c441;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #a6c441;color:#000}.bg-gradient-yellow-cyan{--bslib-color-fg: #000;--bslib-color-bg: #9ec564;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ffc107 var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #9ec564;color:#000}.bg-gradient-green-blue{--bslib-color-fg: #ffffff;--bslib-color-bg: #147d98;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #147d98;color:#fff}.bg-gradient-green-indigo{--bslib-color-fg: #ffffff;--bslib-color-bg: #385793;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #385793;color:#fff}.bg-gradient-green-purple{--bslib-color-fg: #ffffff;--bslib-color-bg: #3b6b80;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #3b6b80;color:#fff}.bg-gradient-green-pink{--bslib-color-fg: #ffffff;--bslib-color-bg: #656567;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #656567;color:#fff}.bg-gradient-green-red{--bslib-color-fg: #ffffff;--bslib-color-bg: #67664e;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #67664e;color:#fff}.bg-gradient-green-orange{--bslib-color-fg: #000;--bslib-color-bg: #74833a;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #74833a;color:#000}.bg-gradient-green-yellow{--bslib-color-fg: #000;--bslib-color-bg: #759e35;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #759e35;color:#000}.bg-gradient-green-teal{--bslib-color-fg: #000;--bslib-color-bg: #1ca16f;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #1ca16f;color:#000}.bg-gradient-green-cyan{--bslib-color-fg: #000;--bslib-color-bg: #14a292;background:linear-gradient(var(--bg-gradient-deg, 140deg), #198754 var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #14a292;color:#000}.bg-gradient-teal-blue{--bslib-color-fg: #000;--bslib-color-bg: #18a5c0;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #18a5c0;color:#000}.bg-gradient-teal-indigo{--bslib-color-fg: #000;--bslib-color-bg: #3c7fbb;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #3c7fbb;color:#000}.bg-gradient-teal-purple{--bslib-color-fg: #000;--bslib-color-bg: #4093a8;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #4093a8;color:#000}.bg-gradient-teal-pink{--bslib-color-fg: #000;--bslib-color-bg: #698d8f;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #698d8f;color:#000}.bg-gradient-teal-red{--bslib-color-fg: #000;--bslib-color-bg: #6b8e76;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #6b8e76;color:#000}.bg-gradient-teal-orange{--bslib-color-fg: #000;--bslib-color-bg: #78ab63;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #78ab63;color:#000}.bg-gradient-teal-yellow{--bslib-color-fg: #000;--bslib-color-bg: #79c65d;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #79c65d;color:#000}.bg-gradient-teal-green{--bslib-color-fg: #000;--bslib-color-bg: #1daf7c;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #1daf7c;color:#000}.bg-gradient-teal-cyan{--bslib-color-fg: #000;--bslib-color-bg: #18c9bb;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #0dcaf0 var(--bg-gradient-end, 180%)) #18c9bb;color:#000}.bg-gradient-cyan-blue{--bslib-color-fg: #000;--bslib-color-bg: #0da5f5;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #0d6efd var(--bg-gradient-end, 180%)) #0da5f5;color:#000}.bg-gradient-cyan-indigo{--bslib-color-fg: #000;--bslib-color-bg: #3180f1;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #3180f1;color:#000}.bg-gradient-cyan-purple{--bslib-color-fg: #000;--bslib-color-bg: #3494dd;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #6f42c1 var(--bg-gradient-end, 180%)) #3494dd;color:#000}.bg-gradient-cyan-pink{--bslib-color-fg: #000;--bslib-color-bg: #5d8ec5;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #d63384 var(--bg-gradient-end, 180%)) #5d8ec5;color:#000}.bg-gradient-cyan-red{--bslib-color-fg: #000;--bslib-color-bg: #608eac;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #dc3545 var(--bg-gradient-end, 180%)) #608eac;color:#000}.bg-gradient-cyan-orange{--bslib-color-fg: #000;--bslib-color-bg: #6dac98;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #fd7e14 var(--bg-gradient-end, 180%)) #6dac98;color:#000}.bg-gradient-cyan-yellow{--bslib-color-fg: #000;--bslib-color-bg: #6ec693;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #ffc107 var(--bg-gradient-end, 180%)) #6ec693;color:#000}.bg-gradient-cyan-green{--bslib-color-fg: #000;--bslib-color-bg: #12afb2;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #198754 var(--bg-gradient-end, 180%)) #12afb2;color:#000}.bg-gradient-cyan-teal{--bslib-color-fg: #000;--bslib-color-bg: #15cacc;background:linear-gradient(var(--bg-gradient-deg, 140deg), #0dcaf0 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #15cacc;color:#000}:root{--bslib-spacer: 1rem;--bslib-mb-spacer: var(--bslib-spacer, 1rem)}.bslib-mb-spacing{margin-bottom:var(--bslib-mb-spacer)}.bslib-gap-spacing{gap:var(--bslib-mb-spacer)}.bslib-gap-spacing>.bslib-mb-spacing,.bslib-gap-spacing>.form-group,.bslib-gap-spacing>p,.bslib-gap-spacing>pre{margin-bottom:0}.html-fill-container>.html-fill-item.bslib-mb-spacing{margin-bottom:0}.bslib-grid{display:grid !important;gap:var(--bslib-spacer, 1rem);height:var(--bslib-grid-height)}.bslib-grid.grid{grid-template-columns:repeat(var(--bs-columns, 12), minmax(0, 1fr));grid-template-rows:unset;grid-auto-rows:var(--bslib-grid--row-heights);--bslib-grid--row-heights--xs: unset;--bslib-grid--row-heights--sm: unset;--bslib-grid--row-heights--md: unset;--bslib-grid--row-heights--lg: unset;--bslib-grid--row-heights--xl: unset;--bslib-grid--row-heights--xxl: unset}.bslib-grid.grid.bslib-grid--row-heights--xs{--bslib-grid--row-heights: var(--bslib-grid--row-heights--xs)}@media(min-width: 576px){.bslib-grid.grid.bslib-grid--row-heights--sm{--bslib-grid--row-heights: var(--bslib-grid--row-heights--sm)}}@media(min-width: 768px){.bslib-grid.grid.bslib-grid--row-heights--md{--bslib-grid--row-heights: var(--bslib-grid--row-heights--md)}}@media(min-width: 992px){.bslib-grid.grid.bslib-grid--row-heights--lg{--bslib-grid--row-heights: var(--bslib-grid--row-heights--lg)}}@media(min-width: 1200px){.bslib-grid.grid.bslib-grid--row-heights--xl{--bslib-grid--row-heights: var(--bslib-grid--row-heights--xl)}}@media(min-width: 1400px){.bslib-grid.grid.bslib-grid--row-heights--xxl{--bslib-grid--row-heights: var(--bslib-grid--row-heights--xxl)}}.bslib-grid>*>.shiny-input-container{width:100%}.bslib-grid-item{grid-column:auto/span 1}@media(max-width: 767.98px){.bslib-grid-item{grid-column:1/-1}}@media(max-width: 575.98px){.bslib-grid{grid-template-columns:1fr !important;height:var(--bslib-grid-height-mobile)}.bslib-grid.grid{height:unset !important;grid-auto-rows:var(--bslib-grid--row-heights--xs, auto)}}@media(min-width: 576px){.nav:not(.nav-hidden){display:flex !important;display:-webkit-flex !important}.nav:not(.nav-hidden):not(.nav-stacked):not(.flex-column){float:none !important}.nav:not(.nav-hidden):not(.nav-stacked):not(.flex-column)>.bslib-nav-spacer{margin-left:auto !important}.nav:not(.nav-hidden):not(.nav-stacked):not(.flex-column)>.form-inline{margin-top:auto;margin-bottom:auto}.nav:not(.nav-hidden).nav-stacked{flex-direction:column;-webkit-flex-direction:column;height:100%}.nav:not(.nav-hidden).nav-stacked>.bslib-nav-spacer{margin-top:auto !important}}.accordion .accordion-header{font-size:calc(1.29rem + 0.48vw);margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2;color:var(--bs-heading-color);margin-bottom:0}@media(min-width: 1200px){.accordion .accordion-header{font-size:1.65rem}}.accordion .accordion-icon:not(:empty){margin-right:.75rem;display:flex}.accordion .accordion-button:not(.collapsed){box-shadow:none}.accordion .accordion-button:not(.collapsed):focus{box-shadow:var(--bs-accordion-btn-focus-box-shadow)}html{height:100%}.bslib-page-fill{width:100%;height:100%;margin:0;padding:var(--bslib-spacer, 1rem);gap:var(--bslib-spacer, 1rem)}@media(max-width: 575.98px){.bslib-page-fill{height:var(--bslib-page-fill-mobile-height, auto)}}.bslib-sidebar-layout{--bslib-sidebar-transition-duration: 500ms;--bslib-sidebar-transition-easing-x: cubic-bezier(0.8, 0.78, 0.22, 1.07);--bslib-sidebar-border: var(--bs-card-border-width, 1px) solid var(--bs-card-border-color, rgba(0, 0, 0, 0.175));--bslib-sidebar-border-radius: var(--bs-border-radius);--bslib-sidebar-vert-border: var(--bs-card-border-width, 1px) solid var(--bs-card-border-color, rgba(0, 0, 0, 0.175));--bslib-sidebar-bg: rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.05);--bslib-sidebar-fg: var(--bs-emphasis-color, black);--bslib-sidebar-main-fg: var(--bs-card-color, var(--bs-body-color));--bslib-sidebar-main-bg: var(--bs-card-bg, var(--bs-body-bg));--bslib-sidebar-toggle-bg: rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.1);--bslib-sidebar-padding: calc(var(--bslib-spacer) * 1.5);--bslib-sidebar-icon-size: var(--bslib-spacer, 1rem);--bslib-sidebar-icon-button-size: calc(var(--bslib-sidebar-icon-size, 1rem) * 2);--bslib-sidebar-padding-icon: calc(var(--bslib-sidebar-icon-button-size, 2rem) * 1.5);--bslib-collapse-toggle-border-radius: var(--bs-border-radius, 0.375rem);--bslib-collapse-toggle-transform: 0deg;--bslib-sidebar-toggle-transition-easing: cubic-bezier(1, 0, 0, 1);--bslib-collapse-toggle-right-transform: 180deg;--bslib-sidebar-column-main: minmax(0, 1fr);display:grid !important;grid-template-columns:min(100% - var(--bslib-sidebar-icon-size),var(--bslib-sidebar-width, 250px)) var(--bslib-sidebar-column-main);position:relative;transition:grid-template-columns ease-in-out var(--bslib-sidebar-transition-duration);border:var(--bslib-sidebar-border);border-radius:var(--bslib-sidebar-border-radius)}@media(prefers-reduced-motion: reduce){.bslib-sidebar-layout{transition:none}}.bslib-sidebar-layout[data-bslib-sidebar-border=false]{border:none}.bslib-sidebar-layout[data-bslib-sidebar-border-radius=false]{border-radius:initial}.bslib-sidebar-layout>.main,.bslib-sidebar-layout>.sidebar{grid-row:1/2;border-radius:inherit;overflow:auto}.bslib-sidebar-layout>.main{grid-column:2/3;border-top-left-radius:0;border-bottom-left-radius:0;padding:var(--bslib-sidebar-padding);transition:padding var(--bslib-sidebar-transition-easing-x) var(--bslib-sidebar-transition-duration);color:var(--bslib-sidebar-main-fg);background-color:var(--bslib-sidebar-main-bg)}.bslib-sidebar-layout>.sidebar{grid-column:1/2;width:100%;height:100%;border-right:var(--bslib-sidebar-vert-border);border-top-right-radius:0;border-bottom-right-radius:0;color:var(--bslib-sidebar-fg);background-color:var(--bslib-sidebar-bg);backdrop-filter:blur(5px)}.bslib-sidebar-layout>.sidebar>.sidebar-content{display:flex;flex-direction:column;gap:var(--bslib-spacer, 1rem);padding:var(--bslib-sidebar-padding);padding-top:var(--bslib-sidebar-padding-icon)}.bslib-sidebar-layout>.sidebar>.sidebar-content>:last-child:not(.sidebar-title){margin-bottom:0}.bslib-sidebar-layout>.sidebar>.sidebar-content>.accordion{margin-left:calc(-1*var(--bslib-sidebar-padding));margin-right:calc(-1*var(--bslib-sidebar-padding))}.bslib-sidebar-layout>.sidebar>.sidebar-content>.accordion:last-child{margin-bottom:calc(-1*var(--bslib-sidebar-padding))}.bslib-sidebar-layout>.sidebar>.sidebar-content>.accordion:not(:last-child){margin-bottom:1rem}.bslib-sidebar-layout>.sidebar>.sidebar-content>.accordion .accordion-body{display:flex;flex-direction:column}.bslib-sidebar-layout>.sidebar>.sidebar-content>.accordion:not(:first-child) .accordion-item:first-child{border-top:var(--bs-accordion-border-width) solid var(--bs-accordion-border-color)}.bslib-sidebar-layout>.sidebar>.sidebar-content>.accordion:not(:last-child) .accordion-item:last-child{border-bottom:var(--bs-accordion-border-width) solid var(--bs-accordion-border-color)}.bslib-sidebar-layout>.sidebar>.sidebar-content.has-accordion>.sidebar-title{border-bottom:none;padding-bottom:0}.bslib-sidebar-layout>.sidebar .shiny-input-container{width:100%}.bslib-sidebar-layout[data-bslib-sidebar-open=always]>.sidebar>.sidebar-content{padding-top:var(--bslib-sidebar-padding)}.bslib-sidebar-layout>.collapse-toggle{grid-row:1/2;grid-column:1/2;display:inline-flex;align-items:center;position:absolute;right:calc(var(--bslib-sidebar-icon-size));top:calc(var(--bslib-sidebar-icon-size, 1rem)/2);border:none;border-radius:var(--bslib-collapse-toggle-border-radius);height:var(--bslib-sidebar-icon-button-size, 2rem);width:var(--bslib-sidebar-icon-button-size, 2rem);display:flex;align-items:center;justify-content:center;padding:0;color:var(--bslib-sidebar-fg);background-color:unset;transition:color var(--bslib-sidebar-transition-easing-x) var(--bslib-sidebar-transition-duration),top var(--bslib-sidebar-transition-easing-x) var(--bslib-sidebar-transition-duration),right var(--bslib-sidebar-transition-easing-x) var(--bslib-sidebar-transition-duration),left var(--bslib-sidebar-transition-easing-x) var(--bslib-sidebar-transition-duration)}.bslib-sidebar-layout>.collapse-toggle:hover{background-color:var(--bslib-sidebar-toggle-bg)}.bslib-sidebar-layout>.collapse-toggle>.collapse-icon{opacity:.8;width:var(--bslib-sidebar-icon-size);height:var(--bslib-sidebar-icon-size);transform:rotateY(var(--bslib-collapse-toggle-transform));transition:transform var(--bslib-sidebar-toggle-transition-easing) var(--bslib-sidebar-transition-duration)}.bslib-sidebar-layout>.collapse-toggle:hover>.collapse-icon{opacity:1}.bslib-sidebar-layout .sidebar-title{font-size:1.25rem;line-height:1.25;margin-top:0;margin-bottom:1rem;padding-bottom:1rem;border-bottom:var(--bslib-sidebar-border)}.bslib-sidebar-layout.sidebar-right{grid-template-columns:var(--bslib-sidebar-column-main) min(100% - var(--bslib-sidebar-icon-size),var(--bslib-sidebar-width, 250px))}.bslib-sidebar-layout.sidebar-right>.main{grid-column:1/2;border-top-right-radius:0;border-bottom-right-radius:0;border-top-left-radius:inherit;border-bottom-left-radius:inherit}.bslib-sidebar-layout.sidebar-right>.sidebar{grid-column:2/3;border-right:none;border-left:var(--bslib-sidebar-vert-border);border-top-left-radius:0;border-bottom-left-radius:0}.bslib-sidebar-layout.sidebar-right>.collapse-toggle{grid-column:2/3;left:var(--bslib-sidebar-icon-size);right:unset;border:var(--bslib-collapse-toggle-border)}.bslib-sidebar-layout.sidebar-right>.collapse-toggle>.collapse-icon{transform:rotateY(var(--bslib-collapse-toggle-right-transform))}.bslib-sidebar-layout.sidebar-collapsed{--bslib-collapse-toggle-transform: 180deg;--bslib-collapse-toggle-right-transform: 0deg;--bslib-sidebar-vert-border: none;grid-template-columns:0 minmax(0, 1fr)}.bslib-sidebar-layout.sidebar-collapsed.sidebar-right{grid-template-columns:minmax(0, 1fr) 0}.bslib-sidebar-layout.sidebar-collapsed:not(.transitioning)>.sidebar>*{display:none}.bslib-sidebar-layout.sidebar-collapsed>.main{border-radius:inherit}.bslib-sidebar-layout.sidebar-collapsed:not(.sidebar-right)>.main{padding-left:var(--bslib-sidebar-padding-icon)}.bslib-sidebar-layout.sidebar-collapsed.sidebar-right>.main{padding-right:var(--bslib-sidebar-padding-icon)}.bslib-sidebar-layout.sidebar-collapsed>.collapse-toggle{color:var(--bslib-sidebar-main-fg);top:calc(var(--bslib-sidebar-overlap-counter, 0)*(var(--bslib-sidebar-icon-size) + var(--bslib-sidebar-padding)) + var(--bslib-sidebar-icon-size, 1rem)/2);right:calc(-2.5*var(--bslib-sidebar-icon-size) - var(--bs-card-border-width, 1px))}.bslib-sidebar-layout.sidebar-collapsed.sidebar-right>.collapse-toggle{left:calc(-2.5*var(--bslib-sidebar-icon-size) - var(--bs-card-border-width, 1px));right:unset}@media(min-width: 576px){.bslib-sidebar-layout.transitioning>.sidebar>.sidebar-content{display:none}}@media(max-width: 575.98px){.bslib-sidebar-layout[data-bslib-sidebar-open=desktop]{--bslib-sidebar-js-init-collapsed: true}.bslib-sidebar-layout>.sidebar,.bslib-sidebar-layout.sidebar-right>.sidebar{border:none}.bslib-sidebar-layout>.main,.bslib-sidebar-layout.sidebar-right>.main{grid-column:1/3}.bslib-sidebar-layout[data-bslib-sidebar-open=always]{display:block !important}.bslib-sidebar-layout[data-bslib-sidebar-open=always]>.sidebar{max-height:var(--bslib-sidebar-max-height-mobile);overflow-y:auto;border-top:var(--bslib-sidebar-vert-border)}.bslib-sidebar-layout:not([data-bslib-sidebar-open=always]){grid-template-columns:100% 0}.bslib-sidebar-layout:not([data-bslib-sidebar-open=always]):not(.sidebar-collapsed)>.sidebar{z-index:1}.bslib-sidebar-layout:not([data-bslib-sidebar-open=always]):not(.sidebar-collapsed)>.collapse-toggle{z-index:1}.bslib-sidebar-layout:not([data-bslib-sidebar-open=always]).sidebar-right{grid-template-columns:0 100%}.bslib-sidebar-layout:not([data-bslib-sidebar-open=always]).sidebar-collapsed{grid-template-columns:0 100%}.bslib-sidebar-layout:not([data-bslib-sidebar-open=always]).sidebar-collapsed.sidebar-right{grid-template-columns:100% 0}.bslib-sidebar-layout:not([data-bslib-sidebar-open=always]):not(.sidebar-right)>.main{padding-left:var(--bslib-sidebar-padding-icon)}.bslib-sidebar-layout:not([data-bslib-sidebar-open=always]).sidebar-right>.main{padding-right:var(--bslib-sidebar-padding-icon)}.bslib-sidebar-layout:not([data-bslib-sidebar-open=always])>.main{opacity:0;transition:opacity var(--bslib-sidebar-transition-easing-x) var(--bslib-sidebar-transition-duration)}.bslib-sidebar-layout:not([data-bslib-sidebar-open=always]).sidebar-collapsed>.main{opacity:1}}:root{--bslib-value-box-shadow: none;--bslib-value-box-border-width-auto-yes: var(--bslib-value-box-border-width-baseline);--bslib-value-box-border-width-auto-no: 0;--bslib-value-box-border-width-baseline: 1px}.bslib-value-box{border-width:var(--bslib-value-box-border-width-auto-no, var(--bslib-value-box-border-width-baseline));container-name:bslib-value-box;container-type:inline-size}.bslib-value-box.card{box-shadow:var(--bslib-value-box-shadow)}.bslib-value-box.border-auto{border-width:var(--bslib-value-box-border-width-auto-yes, var(--bslib-value-box-border-width-baseline))}.bslib-value-box.default{--bslib-value-box-bg-default: var(--bs-card-bg, #ffffff);--bslib-value-box-border-color-default: var(--bs-card-border-color, rgba(0, 0, 0, 0.175));color:var(--bslib-value-box-color);background-color:var(--bslib-value-box-bg, var(--bslib-value-box-bg-default));border-color:var(--bslib-value-box-border-color, var(--bslib-value-box-border-color-default))}.bslib-value-box .value-box-grid{display:grid;grid-template-areas:"left right";align-items:center;overflow:hidden}.bslib-value-box .value-box-showcase{height:100%;max-height:var(---bslib-value-box-showcase-max-h, 100%)}.bslib-value-box .value-box-showcase,.bslib-value-box .value-box-showcase>.html-fill-item{width:100%}.bslib-value-box[data-full-screen=true] .value-box-showcase{max-height:var(---bslib-value-box-showcase-max-h-fs, 100%)}@media screen and (min-width: 575.98px){@container bslib-value-box (max-width: 300px){.bslib-value-box:not(.showcase-bottom) .value-box-grid{grid-template-columns:1fr !important;grid-template-rows:auto auto;grid-template-areas:"top" "bottom"}.bslib-value-box:not(.showcase-bottom) .value-box-grid .value-box-showcase{grid-area:top !important}.bslib-value-box:not(.showcase-bottom) .value-box-grid .value-box-area{grid-area:bottom !important;justify-content:end}}}.bslib-value-box .value-box-area{justify-content:center;padding:1.5rem 1rem;font-size:.9rem;font-weight:500}.bslib-value-box .value-box-area *{margin-bottom:0;margin-top:0}.bslib-value-box .value-box-title{font-size:1rem;margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2}.bslib-value-box .value-box-title:empty::after{content:" "}.bslib-value-box .value-box-value{font-size:calc(1.29rem + 0.48vw);margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2}@media(min-width: 1200px){.bslib-value-box .value-box-value{font-size:1.65rem}}.bslib-value-box .value-box-value:empty::after{content:" "}.bslib-value-box .value-box-showcase{align-items:center;justify-content:center;margin-top:auto;margin-bottom:auto;padding:1rem}.bslib-value-box .value-box-showcase .bi,.bslib-value-box .value-box-showcase .fa,.bslib-value-box .value-box-showcase .fab,.bslib-value-box .value-box-showcase .fas,.bslib-value-box .value-box-showcase .far{opacity:.85;min-width:50px;max-width:125%}.bslib-value-box .value-box-showcase .bi,.bslib-value-box .value-box-showcase .fa,.bslib-value-box .value-box-showcase .fab,.bslib-value-box .value-box-showcase .fas,.bslib-value-box .value-box-showcase .far{font-size:4rem}.bslib-value-box.showcase-top-right .value-box-grid{grid-template-columns:1fr var(---bslib-value-box-showcase-w, 50%)}.bslib-value-box.showcase-top-right .value-box-grid .value-box-showcase{grid-area:right;margin-left:auto;align-self:start;align-items:end;padding-left:0;padding-bottom:0}.bslib-value-box.showcase-top-right .value-box-grid .value-box-area{grid-area:left;align-self:end}.bslib-value-box.showcase-top-right[data-full-screen=true] .value-box-grid{grid-template-columns:auto var(---bslib-value-box-showcase-w-fs, 1fr)}.bslib-value-box.showcase-top-right[data-full-screen=true] .value-box-grid>div{align-self:center}.bslib-value-box.showcase-top-right:not([data-full-screen=true]) .value-box-showcase{margin-top:0}@container bslib-value-box (max-width: 300px){.bslib-value-box.showcase-top-right:not([data-full-screen=true]) .value-box-grid .value-box-showcase{padding-left:1rem}}.bslib-value-box.showcase-left-center .value-box-grid{grid-template-columns:var(---bslib-value-box-showcase-w, 30%) auto}.bslib-value-box.showcase-left-center[data-full-screen=true] .value-box-grid{grid-template-columns:var(---bslib-value-box-showcase-w-fs, 1fr) auto}.bslib-value-box.showcase-left-center:not([data-fill-screen=true]) .value-box-grid .value-box-showcase{grid-area:left}.bslib-value-box.showcase-left-center:not([data-fill-screen=true]) .value-box-grid .value-box-area{grid-area:right}.bslib-value-box.showcase-bottom .value-box-grid{grid-template-columns:1fr;grid-template-rows:1fr var(---bslib-value-box-showcase-h, auto);grid-template-areas:"top" "bottom";overflow:hidden}.bslib-value-box.showcase-bottom .value-box-grid .value-box-showcase{grid-area:bottom;padding:0;margin:0}.bslib-value-box.showcase-bottom .value-box-grid .value-box-area{grid-area:top}.bslib-value-box.showcase-bottom[data-full-screen=true] .value-box-grid{grid-template-rows:1fr var(---bslib-value-box-showcase-h-fs, 2fr)}.bslib-value-box.showcase-bottom[data-full-screen=true] .value-box-grid .value-box-showcase{padding:1rem}[data-bs-theme=dark] .bslib-value-box{--bslib-value-box-shadow: 0 0.5rem 1rem rgb(0 0 0 / 50%)}.bslib-card{overflow:auto}.bslib-card .card-body+.card-body{padding-top:0}.bslib-card .card-body{overflow:auto}.bslib-card .card-body p{margin-top:0}.bslib-card .card-body p:last-child{margin-bottom:0}.bslib-card .card-body{max-height:var(--bslib-card-body-max-height, none)}.bslib-card[data-full-screen=true]>.card-body{max-height:var(--bslib-card-body-max-height-full-screen, none)}.bslib-card .card-header .form-group{margin-bottom:0}.bslib-card .card-header .selectize-control{margin-bottom:0}.bslib-card .card-header .selectize-control .item{margin-right:1.15rem}.bslib-card .card-footer{margin-top:auto}.bslib-card .bslib-navs-card-title{display:flex;flex-wrap:wrap;justify-content:space-between;align-items:center}.bslib-card .bslib-navs-card-title .nav{margin-left:auto}.bslib-card .bslib-sidebar-layout:not([data-bslib-sidebar-border=true]){border:none}.bslib-card .bslib-sidebar-layout:not([data-bslib-sidebar-border-radius=true]){border-top-left-radius:0;border-top-right-radius:0}[data-full-screen=true]{position:fixed;inset:3.5rem 1rem 1rem;height:auto !important;max-height:none !important;width:auto !important;z-index:1070}.bslib-full-screen-enter{display:none;position:absolute;bottom:var(--bslib-full-screen-enter-bottom, 0.2rem);right:var(--bslib-full-screen-enter-right, 0);top:var(--bslib-full-screen-enter-top);left:var(--bslib-full-screen-enter-left);color:var(--bslib-color-fg, var(--bs-card-color));background-color:var(--bslib-color-bg, var(--bs-card-bg, var(--bs-body-bg)));border:var(--bs-card-border-width) solid var(--bslib-color-fg, var(--bs-card-border-color));box-shadow:0 2px 4px rgba(0,0,0,.15);margin:.2rem .4rem;padding:.55rem !important;font-size:.8rem;cursor:pointer;opacity:.7;z-index:1070}.bslib-full-screen-enter:hover{opacity:1}.card[data-full-screen=false]:hover>*>.bslib-full-screen-enter{display:block}.bslib-has-full-screen .card:hover>*>.bslib-full-screen-enter{display:none}@media(max-width: 575.98px){.bslib-full-screen-enter{display:none !important}}.bslib-full-screen-exit{position:relative;top:1.35rem;font-size:.9rem;cursor:pointer;text-decoration:none;display:flex;float:right;margin-right:2.15rem;align-items:center;color:rgba(var(--bs-body-bg-rgb), 0.8)}.bslib-full-screen-exit:hover{color:rgba(var(--bs-body-bg-rgb), 1)}.bslib-full-screen-exit svg{margin-left:.5rem;font-size:1.5rem}#bslib-full-screen-overlay{position:fixed;inset:0;background-color:rgba(var(--bs-body-color-rgb), 0.6);backdrop-filter:blur(2px);-webkit-backdrop-filter:blur(2px);z-index:1069;animation:bslib-full-screen-overlay-enter 400ms cubic-bezier(0.6, 0.02, 0.65, 1) forwards}@keyframes bslib-full-screen-overlay-enter{0%{opacity:0}100%{opacity:1}}.navbar+.container-fluid:has(>.tab-content>.tab-pane.active.html-fill-container),.navbar+.container-sm:has(>.tab-content>.tab-pane.active.html-fill-container),.navbar+.container-md:has(>.tab-content>.tab-pane.active.html-fill-container),.navbar+.container-lg:has(>.tab-content>.tab-pane.active.html-fill-container),.navbar+.container-xl:has(>.tab-content>.tab-pane.active.html-fill-container),.navbar+.container-xxl:has(>.tab-content>.tab-pane.active.html-fill-container){padding-left:0;padding-right:0}.navbar+.container-fluid>.tab-content>.tab-pane.active.html-fill-container,.navbar+.container-sm>.tab-content>.tab-pane.active.html-fill-container,.navbar+.container-md>.tab-content>.tab-pane.active.html-fill-container,.navbar+.container-lg>.tab-content>.tab-pane.active.html-fill-container,.navbar+.container-xl>.tab-content>.tab-pane.active.html-fill-container,.navbar+.container-xxl>.tab-content>.tab-pane.active.html-fill-container{padding:var(--bslib-spacer, 1rem);gap:var(--bslib-spacer, 1rem)}.navbar+.container-fluid>.tab-content>.tab-pane.active.html-fill-container:has(>.bslib-sidebar-layout:only-child),.navbar+.container-sm>.tab-content>.tab-pane.active.html-fill-container:has(>.bslib-sidebar-layout:only-child),.navbar+.container-md>.tab-content>.tab-pane.active.html-fill-container:has(>.bslib-sidebar-layout:only-child),.navbar+.container-lg>.tab-content>.tab-pane.active.html-fill-container:has(>.bslib-sidebar-layout:only-child),.navbar+.container-xl>.tab-content>.tab-pane.active.html-fill-container:has(>.bslib-sidebar-layout:only-child),.navbar+.container-xxl>.tab-content>.tab-pane.active.html-fill-container:has(>.bslib-sidebar-layout:only-child){padding:0}.navbar+.container-fluid>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border=true]),.navbar+.container-sm>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border=true]),.navbar+.container-md>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border=true]),.navbar+.container-lg>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border=true]),.navbar+.container-xl>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border=true]),.navbar+.container-xxl>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border=true]){border-left:none;border-right:none;border-bottom:none}.navbar+.container-fluid>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border-radius=true]),.navbar+.container-sm>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border-radius=true]),.navbar+.container-md>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border-radius=true]),.navbar+.container-lg>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border-radius=true]),.navbar+.container-xl>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border-radius=true]),.navbar+.container-xxl>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border-radius=true]){border-radius:0}.navbar+div>.bslib-sidebar-layout{border-top:var(--bslib-sidebar-border)}:root{--bslib-page-sidebar-title-bg: #517699;--bslib-page-sidebar-title-color: #ffffff}.bslib-page-title{background-color:var(--bslib-page-sidebar-title-bg);color:var(--bslib-page-sidebar-title-color);font-size:1.25rem;font-weight:300;padding:var(--bslib-spacer, 1rem);padding-left:1.5rem;margin-bottom:0;border-bottom:1px solid #dee2e6}.html-fill-container{display:flex;flex-direction:column;min-height:0;min-width:0}.html-fill-container>.html-fill-item{flex:1 1 auto;min-height:0;min-width:0}.html-fill-container>:not(.html-fill-item){flex:0 0 auto}.tippy-box[data-theme~=quarto]{background-color:#fff;border:solid 1px #dee2e6;border-radius:.375rem;color:#212529;font-size:.875rem}.tippy-box[data-theme~=quarto]>.tippy-backdrop{background-color:#fff}.tippy-box[data-theme~=quarto]>.tippy-arrow:after,.tippy-box[data-theme~=quarto]>.tippy-svg-arrow:after{content:"";position:absolute;z-index:-1}.tippy-box[data-theme~=quarto]>.tippy-arrow:after{border-color:rgba(0,0,0,0);border-style:solid}.tippy-box[data-placement^=top]>.tippy-arrow:before{bottom:-6px}.tippy-box[data-placement^=bottom]>.tippy-arrow:before{top:-6px}.tippy-box[data-placement^=right]>.tippy-arrow:before{left:-6px}.tippy-box[data-placement^=left]>.tippy-arrow:before{right:-6px}.tippy-box[data-theme~=quarto][data-placement^=top]>.tippy-arrow:before{border-top-color:#fff}.tippy-box[data-theme~=quarto][data-placement^=top]>.tippy-arrow:after{border-top-color:#dee2e6;border-width:7px 7px 0;top:17px;left:1px}.tippy-box[data-theme~=quarto][data-placement^=top]>.tippy-svg-arrow>svg{top:16px}.tippy-box[data-theme~=quarto][data-placement^=top]>.tippy-svg-arrow:after{top:17px}.tippy-box[data-theme~=quarto][data-placement^=bottom]>.tippy-arrow:before{border-bottom-color:#fff;bottom:16px}.tippy-box[data-theme~=quarto][data-placement^=bottom]>.tippy-arrow:after{border-bottom-color:#dee2e6;border-width:0 7px 7px;bottom:17px;left:1px}.tippy-box[data-theme~=quarto][data-placement^=bottom]>.tippy-svg-arrow>svg{bottom:15px}.tippy-box[data-theme~=quarto][data-placement^=bottom]>.tippy-svg-arrow:after{bottom:17px}.tippy-box[data-theme~=quarto][data-placement^=left]>.tippy-arrow:before{border-left-color:#fff}.tippy-box[data-theme~=quarto][data-placement^=left]>.tippy-arrow:after{border-left-color:#dee2e6;border-width:7px 0 7px 7px;left:17px;top:1px}.tippy-box[data-theme~=quarto][data-placement^=left]>.tippy-svg-arrow>svg{left:11px}.tippy-box[data-theme~=quarto][data-placement^=left]>.tippy-svg-arrow:after{left:12px}.tippy-box[data-theme~=quarto][data-placement^=right]>.tippy-arrow:before{border-right-color:#fff;right:16px}.tippy-box[data-theme~=quarto][data-placement^=right]>.tippy-arrow:after{border-width:7px 7px 7px 0;right:17px;top:1px;border-right-color:#dee2e6}.tippy-box[data-theme~=quarto][data-placement^=right]>.tippy-svg-arrow>svg{right:11px}.tippy-box[data-theme~=quarto][data-placement^=right]>.tippy-svg-arrow:after{right:12px}.tippy-box[data-theme~=quarto]>.tippy-svg-arrow{fill:#212529}.tippy-box[data-theme~=quarto]>.tippy-svg-arrow:after{background-image:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iNiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMCA2czEuNzk2LS4wMTMgNC42Ny0zLjYxNUM1Ljg1MS45IDYuOTMuMDA2IDggMGMxLjA3LS4wMDYgMi4xNDguODg3IDMuMzQzIDIuMzg1QzE0LjIzMyA2LjAwNSAxNiA2IDE2IDZIMHoiIGZpbGw9InJnYmEoMCwgOCwgMTYsIDAuMikiLz48L3N2Zz4=);background-size:16px 6px;width:16px;height:6px}.top-right{position:absolute;top:1em;right:1em}.visually-hidden{border:0;clip:rect(0 0 0 0);height:auto;margin:0;overflow:hidden;padding:0;position:absolute;width:1px;white-space:nowrap}.hidden{display:none !important}.zindex-bottom{z-index:-1 !important}figure.figure{display:block}.quarto-layout-panel{margin-bottom:1em}.quarto-layout-panel>figure{width:100%}.quarto-layout-panel>figure>figcaption,.quarto-layout-panel>.panel-caption{margin-top:10pt}.quarto-layout-panel>.table-caption{margin-top:0px}.table-caption p{margin-bottom:.5em}.quarto-layout-row{display:flex;flex-direction:row;align-items:flex-start}.quarto-layout-valign-top{align-items:flex-start}.quarto-layout-valign-bottom{align-items:flex-end}.quarto-layout-valign-center{align-items:center}.quarto-layout-cell{position:relative;margin-right:20px}.quarto-layout-cell:last-child{margin-right:0}.quarto-layout-cell figure,.quarto-layout-cell>p{margin:.2em}.quarto-layout-cell img{max-width:100%}.quarto-layout-cell .html-widget{width:100% !important}.quarto-layout-cell div figure p{margin:0}.quarto-layout-cell figure{display:block;margin-inline-start:0;margin-inline-end:0}.quarto-layout-cell table{display:inline-table}.quarto-layout-cell-subref figcaption,figure .quarto-layout-row figure figcaption{text-align:center;font-style:italic}.quarto-figure{position:relative;margin-bottom:1em}.quarto-figure>figure{width:100%;margin-bottom:0}.quarto-figure-left>figure>p,.quarto-figure-left>figure>div{text-align:left}.quarto-figure-center>figure>p,.quarto-figure-center>figure>div{text-align:center}.quarto-figure-right>figure>p,.quarto-figure-right>figure>div{text-align:right}.quarto-figure>figure>div.cell-annotation,.quarto-figure>figure>div code{text-align:left}figure>p:empty{display:none}figure>p:first-child{margin-top:0;margin-bottom:0}figure>figcaption.quarto-float-caption-bottom{margin-bottom:.5em}figure>figcaption.quarto-float-caption-top{margin-top:.5em}div[id^=tbl-]{position:relative}.quarto-figure>.anchorjs-link{position:absolute;top:.6em;right:.5em}div[id^=tbl-]>.anchorjs-link{position:absolute;top:.7em;right:.3em}.quarto-figure:hover>.anchorjs-link,div[id^=tbl-]:hover>.anchorjs-link,h2:hover>.anchorjs-link,.h2:hover>.anchorjs-link,h3:hover>.anchorjs-link,.h3:hover>.anchorjs-link,h4:hover>.anchorjs-link,.h4:hover>.anchorjs-link,h5:hover>.anchorjs-link,.h5:hover>.anchorjs-link,h6:hover>.anchorjs-link,.h6:hover>.anchorjs-link,.reveal-anchorjs-link>.anchorjs-link{opacity:1}#title-block-header{margin-block-end:1rem;position:relative;margin-top:-1px}#title-block-header .abstract{margin-block-start:1rem}#title-block-header .abstract .abstract-title{font-weight:600}#title-block-header a{text-decoration:none}#title-block-header .author,#title-block-header .date,#title-block-header .doi{margin-block-end:.2rem}#title-block-header .quarto-title-block>div{display:flex}#title-block-header .quarto-title-block>div>h1,#title-block-header .quarto-title-block>div>.h1{flex-grow:1}#title-block-header .quarto-title-block>div>button{flex-shrink:0;height:2.25rem;margin-top:0}@media(min-width: 992px){#title-block-header .quarto-title-block>div>button{margin-top:5px}}tr.header>th>p:last-of-type{margin-bottom:0px}table,table.table{margin-top:.5rem;margin-bottom:.5rem}caption,.table-caption{padding-top:.5rem;padding-bottom:.5rem;text-align:center}figure.quarto-float-tbl figcaption.quarto-float-caption-top{margin-top:.5rem;margin-bottom:.25rem;text-align:center}figure.quarto-float-tbl figcaption.quarto-float-caption-bottom{padding-top:.25rem;margin-bottom:.5rem;text-align:center}.utterances{max-width:none;margin-left:-8px}iframe{margin-bottom:1em}details{margin-bottom:1em}details[show]{margin-bottom:0}details>summary{color:rgba(33,37,41,.75)}details>summary>p:only-child{display:inline}pre.sourceCode,code.sourceCode{position:relative}dd code:not(.sourceCode),p code:not(.sourceCode){white-space:pre-wrap}code{white-space:pre}@media print{code{white-space:pre-wrap}}pre>code{display:block}pre>code.sourceCode{white-space:pre}pre>code.sourceCode>span>a:first-child::before{text-decoration:none}pre.code-overflow-wrap>code.sourceCode{white-space:pre-wrap}pre.code-overflow-scroll>code.sourceCode{white-space:pre}code a:any-link{color:inherit;text-decoration:none}code a:hover{color:inherit;text-decoration:underline}ul.task-list{padding-left:1em}[data-tippy-root]{display:inline-block}.tippy-content .footnote-back{display:none}.footnote-back{margin-left:.2em}.tippy-content{overflow-x:auto}.quarto-embedded-source-code{display:none}.quarto-unresolved-ref{font-weight:600}.quarto-cover-image{max-width:35%;float:right;margin-left:30px}.cell-output-display .widget-subarea{margin-bottom:1em}.cell-output-display:not(.no-overflow-x),.knitsql-table:not(.no-overflow-x){overflow-x:auto}.panel-input{margin-bottom:1em}.panel-input>div,.panel-input>div>div{display:inline-block;vertical-align:top;padding-right:12px}.panel-input>p:last-child{margin-bottom:0}.layout-sidebar{margin-bottom:1em}.layout-sidebar .tab-content{border:none}.tab-content>.page-columns.active{display:grid}div.sourceCode>iframe{width:100%;height:300px;margin-bottom:-0.5em}a{text-underline-offset:3px}div.ansi-escaped-output{font-family:monospace;display:block}/*! -* -* ansi colors from IPython notebook's -* -* we also add `bright-[color]-` synonyms for the `-[color]-intense` classes since -* that seems to be what ansi_up emits -* -*/.ansi-black-fg{color:#3e424d}.ansi-black-bg{background-color:#3e424d}.ansi-black-intense-black,.ansi-bright-black-fg{color:#282c36}.ansi-black-intense-black,.ansi-bright-black-bg{background-color:#282c36}.ansi-red-fg{color:#e75c58}.ansi-red-bg{background-color:#e75c58}.ansi-red-intense-red,.ansi-bright-red-fg{color:#b22b31}.ansi-red-intense-red,.ansi-bright-red-bg{background-color:#b22b31}.ansi-green-fg{color:#00a250}.ansi-green-bg{background-color:#00a250}.ansi-green-intense-green,.ansi-bright-green-fg{color:#007427}.ansi-green-intense-green,.ansi-bright-green-bg{background-color:#007427}.ansi-yellow-fg{color:#ddb62b}.ansi-yellow-bg{background-color:#ddb62b}.ansi-yellow-intense-yellow,.ansi-bright-yellow-fg{color:#b27d12}.ansi-yellow-intense-yellow,.ansi-bright-yellow-bg{background-color:#b27d12}.ansi-blue-fg{color:#208ffb}.ansi-blue-bg{background-color:#208ffb}.ansi-blue-intense-blue,.ansi-bright-blue-fg{color:#0065ca}.ansi-blue-intense-blue,.ansi-bright-blue-bg{background-color:#0065ca}.ansi-magenta-fg{color:#d160c4}.ansi-magenta-bg{background-color:#d160c4}.ansi-magenta-intense-magenta,.ansi-bright-magenta-fg{color:#a03196}.ansi-magenta-intense-magenta,.ansi-bright-magenta-bg{background-color:#a03196}.ansi-cyan-fg{color:#60c6c8}.ansi-cyan-bg{background-color:#60c6c8}.ansi-cyan-intense-cyan,.ansi-bright-cyan-fg{color:#258f8f}.ansi-cyan-intense-cyan,.ansi-bright-cyan-bg{background-color:#258f8f}.ansi-white-fg{color:#c5c1b4}.ansi-white-bg{background-color:#c5c1b4}.ansi-white-intense-white,.ansi-bright-white-fg{color:#a1a6b2}.ansi-white-intense-white,.ansi-bright-white-bg{background-color:#a1a6b2}.ansi-default-inverse-fg{color:#fff}.ansi-default-inverse-bg{background-color:#000}.ansi-bold{font-weight:bold}.ansi-underline{text-decoration:underline}:root{--quarto-body-bg: #ffffff;--quarto-body-color: #212529;--quarto-text-muted: rgba(33, 37, 41, 0.75);--quarto-border-color: #dee2e6;--quarto-border-width: 1px;--quarto-border-radius: 0.375rem}table.gt_table{color:var(--quarto-body-color);font-size:1em;width:100%;background-color:rgba(0,0,0,0);border-top-width:inherit;border-bottom-width:inherit;border-color:var(--quarto-border-color)}table.gt_table th.gt_column_spanner_outer{color:var(--quarto-body-color);background-color:rgba(0,0,0,0);border-top-width:inherit;border-bottom-width:inherit;border-color:var(--quarto-border-color)}table.gt_table th.gt_col_heading{color:var(--quarto-body-color);font-weight:bold;background-color:rgba(0,0,0,0)}table.gt_table thead.gt_col_headings{border-bottom:1px solid currentColor;border-top-width:inherit;border-top-color:var(--quarto-border-color)}table.gt_table thead.gt_col_headings:not(:first-child){border-top-width:1px;border-top-color:var(--quarto-border-color)}table.gt_table td.gt_row{border-bottom-width:1px;border-bottom-color:var(--quarto-border-color);border-top-width:0px}table.gt_table tbody.gt_table_body{border-top-width:1px;border-bottom-width:1px;border-bottom-color:var(--quarto-border-color);border-top-color:currentColor}div.columns{display:initial;gap:initial}div.column{display:inline-block;overflow-x:initial;vertical-align:top;width:50%}.code-annotation-tip-content{word-wrap:break-word}.code-annotation-container-hidden{display:none !important}dl.code-annotation-container-grid{display:grid;grid-template-columns:min-content auto}dl.code-annotation-container-grid dt{grid-column:1}dl.code-annotation-container-grid dd{grid-column:2}pre.sourceCode.code-annotation-code{padding-right:0}code.sourceCode .code-annotation-anchor{z-index:100;position:relative;float:right;background-color:rgba(0,0,0,0)}input[type=checkbox]{margin-right:.5ch}:root{--mermaid-bg-color: #ffffff;--mermaid-edge-color: #6c757d;--mermaid-node-fg-color: #212529;--mermaid-fg-color: #212529;--mermaid-fg-color--lighter: #383f45;--mermaid-fg-color--lightest: #4e5862;--mermaid-font-family: system-ui, -apple-system, Segoe UI, Roboto, Helvetica Neue, Noto Sans, Liberation Sans, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol, Noto Color Emoji;--mermaid-label-bg-color: #ffffff;--mermaid-label-fg-color: #0d6efd;--mermaid-node-bg-color: rgba(13, 110, 253, 0.1);--mermaid-node-fg-color: #212529}@media print{:root{font-size:11pt}#quarto-sidebar,#TOC,.nav-page{display:none}.page-columns .content{grid-column-start:page-start}.fixed-top{position:relative}.panel-caption,.figure-caption,figcaption{color:#666}}.code-copy-button{position:absolute;top:0;right:0;border:0;margin-top:5px;margin-right:5px;background-color:rgba(0,0,0,0);z-index:3}.code-copy-button:focus{outline:none}.code-copy-button-tooltip{font-size:.75em}pre.sourceCode:hover>.code-copy-button>.bi::before{display:inline-block;height:1rem;width:1rem;content:"";vertical-align:-0.125em;background-image:url('data:image/svg+xml,');background-repeat:no-repeat;background-size:1rem 1rem}pre.sourceCode:hover>.code-copy-button-checked>.bi::before{background-image:url('data:image/svg+xml,')}pre.sourceCode:hover>.code-copy-button:hover>.bi::before{background-image:url('data:image/svg+xml,')}pre.sourceCode:hover>.code-copy-button-checked:hover>.bi::before{background-image:url('data:image/svg+xml,')}main ol ol,main ul ul,main ol ul,main ul ol{margin-bottom:1em}ul>li:not(:has(>p))>ul,ol>li:not(:has(>p))>ul,ul>li:not(:has(>p))>ol,ol>li:not(:has(>p))>ol{margin-bottom:0}ul>li:not(:has(>p))>ul>li:has(>p),ol>li:not(:has(>p))>ul>li:has(>p),ul>li:not(:has(>p))>ol>li:has(>p),ol>li:not(:has(>p))>ol>li:has(>p){margin-top:1rem}body{margin:0}main.page-columns>header>h1.title,main.page-columns>header>.title.h1{margin-bottom:0}@media(min-width: 992px){body .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset] 35px [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(500px, calc(850px - 3em)) [body-content-end] 1.5em [body-end] 35px [body-end-outset] minmax(75px, 145px) [page-end-inset] 35px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.fullcontent:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset] 35px [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(500px, calc(850px - 3em)) [body-content-end] 1.5em [body-end] 35px [body-end-outset] 35px [page-end-inset page-end] 5fr [screen-end-inset] 1.5em}body.slimcontent:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset] 35px [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(500px, calc(850px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(0px, 200px) [page-end-inset] 35px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.listing:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start] minmax(50px, 100px) [page-start-inset] 50px [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(500px, calc(850px - 3em)) [body-content-end] 3em [body-end] 50px [body-end-outset] minmax(0px, 250px) [page-end-inset] minmax(50px, 100px) [page-end] 1fr [screen-end-inset] 1.5em [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] 35px [page-start-inset] minmax(0px, 175px) [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(450px, calc(800px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(0px, 200px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] 35px [page-start-inset] minmax(0px, 175px) [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(450px, calc(800px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(0px, 200px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] minmax(25px, 50px) [page-start-inset] minmax(50px, 150px) [body-start-outset] minmax(25px, 50px) [body-start] 1.5em [body-content-start] minmax(500px, calc(800px - 3em)) [body-content-end] 1.5em [body-end] minmax(25px, 50px) [body-end-outset] minmax(50px, 150px) [page-end-inset] minmax(25px, 50px) [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start] minmax(50px, 100px) [page-start-inset] 50px [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(500px, calc(1000px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(50px, 100px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked.fullcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start] minmax(50px, 100px) [page-start-inset] 50px [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(500px, calc(1000px - 3em)) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating.fullcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] 50px [page-start-inset] minmax(50px, 150px) [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(500px, calc(800px - 3em)) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked.slimcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start] minmax(50px, 100px) [page-start-inset] 50px [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(450px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(0px, 200px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked.listing .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start] minmax(50px, 100px) [page-start-inset] 50px [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(500px, calc(1000px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(0px, 200px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating.slimcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] 50px [page-start-inset] minmax(50px, 150px) [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(450px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(50px, 150px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating.listing .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] minmax(25px, 50px) [page-start-inset] minmax(50px, 150px) [body-start-outset] minmax(25px, 50px) [body-start] 1.5em [body-content-start] minmax(500px, calc(800px - 3em)) [body-content-end] 1.5em [body-end] minmax(25px, 50px) [body-end-outset] minmax(50px, 150px) [page-end-inset] minmax(25px, 50px) [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}}@media(max-width: 991.98px){body .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset] 5fr [body-start] 1.5em [body-content-start] minmax(500px, calc(800px - 3em)) [body-content-end] 1.5em [body-end] 35px [body-end-outset] minmax(75px, 145px) [page-end-inset] 35px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.fullcontent:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset] 5fr [body-start] 1.5em [body-content-start] minmax(500px, calc(800px - 3em)) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.slimcontent:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset] 5fr [body-start] 1.5em [body-content-start] minmax(500px, calc(800px - 3em)) [body-content-end] 1.5em [body-end] 35px [body-end-outset] minmax(75px, 145px) [page-end-inset] 35px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.listing:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset] 5fr [body-start] 1.5em [body-content-start] minmax(500px, calc(1250px - 3em)) [body-content-end body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] 35px [page-start-inset] minmax(0px, 145px) [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(450px, calc(800px - 3em)) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] 35px [page-start-inset] minmax(0px, 145px) [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(450px, calc(800px - 3em)) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset body-start-outset body-start] 1.5em [body-content-start] minmax(500px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(75px, 150px) [page-end-inset] 25px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(500px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(25px, 50px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked.fullcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(500px, calc(1000px - 3em)) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating.fullcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset body-start-outset body-start] 1em [body-content-start] minmax(500px, calc(800px - 3em)) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 4fr [screen-end-inset] 1.5em [screen-end]}body.docked.slimcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(500px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(25px, 50px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked.listing .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(500px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(25px, 50px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating.slimcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset body-start-outset body-start] 1em [body-content-start] minmax(500px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 35px [body-end-outset] minmax(75px, 145px) [page-end-inset] 35px [page-end] 4fr [screen-end-inset] 1.5em [screen-end]}body.floating.listing .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset body-start-outset body-start] 1em [body-content-start] minmax(500px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(75px, 150px) [page-end-inset] 25px [page-end] 4fr [screen-end-inset] 1.5em [screen-end]}}@media(max-width: 767.98px){body .page-columns,body.fullcontent:not(.floating):not(.docked) .page-columns,body.slimcontent:not(.floating):not(.docked) .page-columns,body.docked .page-columns,body.docked.slimcontent .page-columns,body.docked.fullcontent .page-columns,body.floating .page-columns,body.floating.slimcontent .page-columns,body.floating.fullcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(0px, 1fr) [body-content-end body-end body-end-outset page-end-inset page-end screen-end-inset] 1.5em [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(0px, 1fr) [body-content-end body-end body-end-outset page-end-inset page-end screen-end-inset] 1.5em [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(0px, 1fr) [body-content-end body-end body-end-outset page-end-inset page-end screen-end-inset] 1.5em [screen-end]}nav[role=doc-toc]{display:none}}body,.page-row-navigation{grid-template-rows:[page-top] max-content [contents-top] max-content [contents-bottom] max-content [page-bottom]}.page-rows-contents{grid-template-rows:[content-top] minmax(max-content, 1fr) [content-bottom] minmax(60px, max-content) [page-bottom]}.page-full{grid-column:screen-start/screen-end !important}.page-columns>*{grid-column:body-content-start/body-content-end}.page-columns.column-page>*{grid-column:page-start/page-end}.page-columns.column-page-left .page-columns.page-full>*,.page-columns.column-page-left>*{grid-column:page-start/body-content-end}.page-columns.column-page-right .page-columns.page-full>*,.page-columns.column-page-right>*{grid-column:body-content-start/page-end}.page-rows{grid-auto-rows:auto}.header{grid-column:screen-start/screen-end;grid-row:page-top/contents-top}#quarto-content{padding:0;grid-column:screen-start/screen-end;grid-row:contents-top/contents-bottom}body.floating .sidebar.sidebar-navigation{grid-column:page-start/body-start;grid-row:content-top/page-bottom}body.docked .sidebar.sidebar-navigation{grid-column:screen-start/body-start;grid-row:content-top/page-bottom}.sidebar.toc-left{grid-column:page-start/body-start;grid-row:content-top/page-bottom}.sidebar.margin-sidebar{grid-column:body-end/page-end;grid-row:content-top/page-bottom}.page-columns .content{grid-column:body-content-start/body-content-end;grid-row:content-top/content-bottom;align-content:flex-start}.page-columns .page-navigation{grid-column:body-content-start/body-content-end;grid-row:content-bottom/page-bottom}.page-columns .footer{grid-column:screen-start/screen-end;grid-row:contents-bottom/page-bottom}.page-columns .column-body{grid-column:body-content-start/body-content-end}.page-columns .column-body-fullbleed{grid-column:body-start/body-end}.page-columns .column-body-outset{grid-column:body-start-outset/body-end-outset;z-index:998;opacity:.999}.page-columns .column-body-outset table{background:#fff}.page-columns .column-body-outset-left{grid-column:body-start-outset/body-content-end;z-index:998;opacity:.999}.page-columns .column-body-outset-left table{background:#fff}.page-columns .column-body-outset-right{grid-column:body-content-start/body-end-outset;z-index:998;opacity:.999}.page-columns .column-body-outset-right table{background:#fff}.page-columns .column-page{grid-column:page-start/page-end;z-index:998;opacity:.999}.page-columns .column-page table{background:#fff}.page-columns .column-page-inset{grid-column:page-start-inset/page-end-inset;z-index:998;opacity:.999}.page-columns .column-page-inset table{background:#fff}.page-columns .column-page-inset-left{grid-column:page-start-inset/body-content-end;z-index:998;opacity:.999}.page-columns .column-page-inset-left table{background:#fff}.page-columns .column-page-inset-right{grid-column:body-content-start/page-end-inset;z-index:998;opacity:.999}.page-columns .column-page-inset-right figcaption table{background:#fff}.page-columns .column-page-left{grid-column:page-start/body-content-end;z-index:998;opacity:.999}.page-columns .column-page-left table{background:#fff}.page-columns .column-page-right{grid-column:body-content-start/page-end;z-index:998;opacity:.999}.page-columns .column-page-right figcaption table{background:#fff}#quarto-content.page-columns #quarto-margin-sidebar,#quarto-content.page-columns #quarto-sidebar{z-index:1}@media(max-width: 991.98px){#quarto-content.page-columns #quarto-margin-sidebar.collapse,#quarto-content.page-columns #quarto-sidebar.collapse,#quarto-content.page-columns #quarto-margin-sidebar.collapsing,#quarto-content.page-columns #quarto-sidebar.collapsing{z-index:1055}}#quarto-content.page-columns main.column-page,#quarto-content.page-columns main.column-page-right,#quarto-content.page-columns main.column-page-left{z-index:0}.page-columns .column-screen-inset{grid-column:screen-start-inset/screen-end-inset;z-index:998;opacity:.999}.page-columns .column-screen-inset table{background:#fff}.page-columns .column-screen-inset-left{grid-column:screen-start-inset/body-content-end;z-index:998;opacity:.999}.page-columns .column-screen-inset-left table{background:#fff}.page-columns .column-screen-inset-right{grid-column:body-content-start/screen-end-inset;z-index:998;opacity:.999}.page-columns .column-screen-inset-right table{background:#fff}.page-columns .column-screen{grid-column:screen-start/screen-end;z-index:998;opacity:.999}.page-columns .column-screen table{background:#fff}.page-columns .column-screen-left{grid-column:screen-start/body-content-end;z-index:998;opacity:.999}.page-columns .column-screen-left table{background:#fff}.page-columns .column-screen-right{grid-column:body-content-start/screen-end;z-index:998;opacity:.999}.page-columns .column-screen-right table{background:#fff}.page-columns .column-screen-inset-shaded{grid-column:screen-start/screen-end;padding:1em;background:#f8f9fa;z-index:998;opacity:.999;margin-bottom:1em}.zindex-content{z-index:998;opacity:.999}.zindex-modal{z-index:1055;opacity:.999}.zindex-over-content{z-index:999;opacity:.999}img.img-fluid.column-screen,img.img-fluid.column-screen-inset-shaded,img.img-fluid.column-screen-inset,img.img-fluid.column-screen-inset-left,img.img-fluid.column-screen-inset-right,img.img-fluid.column-screen-left,img.img-fluid.column-screen-right{width:100%}@media(min-width: 992px){.margin-caption,div.aside,aside:not(.footnotes):not(.sidebar),.column-margin{grid-column:body-end/page-end !important;z-index:998}.column-sidebar{grid-column:page-start/body-start !important;z-index:998}.column-leftmargin{grid-column:screen-start-inset/body-start !important;z-index:998}.no-row-height{height:1em;overflow:visible}}@media(max-width: 991.98px){.margin-caption,div.aside,aside:not(.footnotes):not(.sidebar),.column-margin{grid-column:body-end/page-end !important;z-index:998}.no-row-height{height:1em;overflow:visible}.page-columns.page-full{overflow:visible}.page-columns.toc-left .margin-caption,.page-columns.toc-left div.aside,.page-columns.toc-left aside:not(.footnotes):not(.sidebar),.page-columns.toc-left .column-margin{grid-column:body-content-start/body-content-end !important;z-index:998;opacity:.999}.page-columns.toc-left .no-row-height{height:initial;overflow:initial}}@media(max-width: 767.98px){.margin-caption,div.aside,aside:not(.footnotes):not(.sidebar),.column-margin{grid-column:body-content-start/body-content-end !important;z-index:998;opacity:.999}.no-row-height{height:initial;overflow:initial}#quarto-margin-sidebar{display:none}#quarto-sidebar-toc-left{display:none}.hidden-sm{display:none}}.panel-grid{display:grid;grid-template-rows:repeat(1, 1fr);grid-template-columns:repeat(24, 1fr);gap:1em}.panel-grid .g-col-1{grid-column:auto/span 1}.panel-grid .g-col-2{grid-column:auto/span 2}.panel-grid .g-col-3{grid-column:auto/span 3}.panel-grid .g-col-4{grid-column:auto/span 4}.panel-grid .g-col-5{grid-column:auto/span 5}.panel-grid .g-col-6{grid-column:auto/span 6}.panel-grid .g-col-7{grid-column:auto/span 7}.panel-grid .g-col-8{grid-column:auto/span 8}.panel-grid .g-col-9{grid-column:auto/span 9}.panel-grid .g-col-10{grid-column:auto/span 10}.panel-grid .g-col-11{grid-column:auto/span 11}.panel-grid .g-col-12{grid-column:auto/span 12}.panel-grid .g-col-13{grid-column:auto/span 13}.panel-grid .g-col-14{grid-column:auto/span 14}.panel-grid .g-col-15{grid-column:auto/span 15}.panel-grid .g-col-16{grid-column:auto/span 16}.panel-grid .g-col-17{grid-column:auto/span 17}.panel-grid .g-col-18{grid-column:auto/span 18}.panel-grid .g-col-19{grid-column:auto/span 19}.panel-grid .g-col-20{grid-column:auto/span 20}.panel-grid .g-col-21{grid-column:auto/span 21}.panel-grid .g-col-22{grid-column:auto/span 22}.panel-grid .g-col-23{grid-column:auto/span 23}.panel-grid .g-col-24{grid-column:auto/span 24}.panel-grid .g-start-1{grid-column-start:1}.panel-grid .g-start-2{grid-column-start:2}.panel-grid .g-start-3{grid-column-start:3}.panel-grid .g-start-4{grid-column-start:4}.panel-grid .g-start-5{grid-column-start:5}.panel-grid .g-start-6{grid-column-start:6}.panel-grid .g-start-7{grid-column-start:7}.panel-grid .g-start-8{grid-column-start:8}.panel-grid .g-start-9{grid-column-start:9}.panel-grid .g-start-10{grid-column-start:10}.panel-grid .g-start-11{grid-column-start:11}.panel-grid .g-start-12{grid-column-start:12}.panel-grid .g-start-13{grid-column-start:13}.panel-grid .g-start-14{grid-column-start:14}.panel-grid .g-start-15{grid-column-start:15}.panel-grid .g-start-16{grid-column-start:16}.panel-grid .g-start-17{grid-column-start:17}.panel-grid .g-start-18{grid-column-start:18}.panel-grid .g-start-19{grid-column-start:19}.panel-grid .g-start-20{grid-column-start:20}.panel-grid .g-start-21{grid-column-start:21}.panel-grid .g-start-22{grid-column-start:22}.panel-grid .g-start-23{grid-column-start:23}@media(min-width: 576px){.panel-grid .g-col-sm-1{grid-column:auto/span 1}.panel-grid .g-col-sm-2{grid-column:auto/span 2}.panel-grid .g-col-sm-3{grid-column:auto/span 3}.panel-grid .g-col-sm-4{grid-column:auto/span 4}.panel-grid .g-col-sm-5{grid-column:auto/span 5}.panel-grid .g-col-sm-6{grid-column:auto/span 6}.panel-grid .g-col-sm-7{grid-column:auto/span 7}.panel-grid .g-col-sm-8{grid-column:auto/span 8}.panel-grid .g-col-sm-9{grid-column:auto/span 9}.panel-grid .g-col-sm-10{grid-column:auto/span 10}.panel-grid .g-col-sm-11{grid-column:auto/span 11}.panel-grid .g-col-sm-12{grid-column:auto/span 12}.panel-grid .g-col-sm-13{grid-column:auto/span 13}.panel-grid .g-col-sm-14{grid-column:auto/span 14}.panel-grid .g-col-sm-15{grid-column:auto/span 15}.panel-grid .g-col-sm-16{grid-column:auto/span 16}.panel-grid .g-col-sm-17{grid-column:auto/span 17}.panel-grid .g-col-sm-18{grid-column:auto/span 18}.panel-grid .g-col-sm-19{grid-column:auto/span 19}.panel-grid .g-col-sm-20{grid-column:auto/span 20}.panel-grid .g-col-sm-21{grid-column:auto/span 21}.panel-grid .g-col-sm-22{grid-column:auto/span 22}.panel-grid .g-col-sm-23{grid-column:auto/span 23}.panel-grid .g-col-sm-24{grid-column:auto/span 24}.panel-grid .g-start-sm-1{grid-column-start:1}.panel-grid .g-start-sm-2{grid-column-start:2}.panel-grid .g-start-sm-3{grid-column-start:3}.panel-grid .g-start-sm-4{grid-column-start:4}.panel-grid .g-start-sm-5{grid-column-start:5}.panel-grid .g-start-sm-6{grid-column-start:6}.panel-grid .g-start-sm-7{grid-column-start:7}.panel-grid .g-start-sm-8{grid-column-start:8}.panel-grid .g-start-sm-9{grid-column-start:9}.panel-grid .g-start-sm-10{grid-column-start:10}.panel-grid .g-start-sm-11{grid-column-start:11}.panel-grid .g-start-sm-12{grid-column-start:12}.panel-grid .g-start-sm-13{grid-column-start:13}.panel-grid .g-start-sm-14{grid-column-start:14}.panel-grid .g-start-sm-15{grid-column-start:15}.panel-grid .g-start-sm-16{grid-column-start:16}.panel-grid .g-start-sm-17{grid-column-start:17}.panel-grid .g-start-sm-18{grid-column-start:18}.panel-grid .g-start-sm-19{grid-column-start:19}.panel-grid .g-start-sm-20{grid-column-start:20}.panel-grid .g-start-sm-21{grid-column-start:21}.panel-grid .g-start-sm-22{grid-column-start:22}.panel-grid .g-start-sm-23{grid-column-start:23}}@media(min-width: 768px){.panel-grid .g-col-md-1{grid-column:auto/span 1}.panel-grid .g-col-md-2{grid-column:auto/span 2}.panel-grid .g-col-md-3{grid-column:auto/span 3}.panel-grid .g-col-md-4{grid-column:auto/span 4}.panel-grid .g-col-md-5{grid-column:auto/span 5}.panel-grid .g-col-md-6{grid-column:auto/span 6}.panel-grid .g-col-md-7{grid-column:auto/span 7}.panel-grid .g-col-md-8{grid-column:auto/span 8}.panel-grid .g-col-md-9{grid-column:auto/span 9}.panel-grid .g-col-md-10{grid-column:auto/span 10}.panel-grid .g-col-md-11{grid-column:auto/span 11}.panel-grid .g-col-md-12{grid-column:auto/span 12}.panel-grid .g-col-md-13{grid-column:auto/span 13}.panel-grid .g-col-md-14{grid-column:auto/span 14}.panel-grid .g-col-md-15{grid-column:auto/span 15}.panel-grid .g-col-md-16{grid-column:auto/span 16}.panel-grid .g-col-md-17{grid-column:auto/span 17}.panel-grid .g-col-md-18{grid-column:auto/span 18}.panel-grid .g-col-md-19{grid-column:auto/span 19}.panel-grid .g-col-md-20{grid-column:auto/span 20}.panel-grid .g-col-md-21{grid-column:auto/span 21}.panel-grid .g-col-md-22{grid-column:auto/span 22}.panel-grid .g-col-md-23{grid-column:auto/span 23}.panel-grid .g-col-md-24{grid-column:auto/span 24}.panel-grid .g-start-md-1{grid-column-start:1}.panel-grid .g-start-md-2{grid-column-start:2}.panel-grid .g-start-md-3{grid-column-start:3}.panel-grid .g-start-md-4{grid-column-start:4}.panel-grid .g-start-md-5{grid-column-start:5}.panel-grid .g-start-md-6{grid-column-start:6}.panel-grid .g-start-md-7{grid-column-start:7}.panel-grid .g-start-md-8{grid-column-start:8}.panel-grid .g-start-md-9{grid-column-start:9}.panel-grid .g-start-md-10{grid-column-start:10}.panel-grid .g-start-md-11{grid-column-start:11}.panel-grid .g-start-md-12{grid-column-start:12}.panel-grid .g-start-md-13{grid-column-start:13}.panel-grid .g-start-md-14{grid-column-start:14}.panel-grid .g-start-md-15{grid-column-start:15}.panel-grid .g-start-md-16{grid-column-start:16}.panel-grid .g-start-md-17{grid-column-start:17}.panel-grid .g-start-md-18{grid-column-start:18}.panel-grid .g-start-md-19{grid-column-start:19}.panel-grid .g-start-md-20{grid-column-start:20}.panel-grid .g-start-md-21{grid-column-start:21}.panel-grid .g-start-md-22{grid-column-start:22}.panel-grid .g-start-md-23{grid-column-start:23}}@media(min-width: 992px){.panel-grid .g-col-lg-1{grid-column:auto/span 1}.panel-grid .g-col-lg-2{grid-column:auto/span 2}.panel-grid .g-col-lg-3{grid-column:auto/span 3}.panel-grid .g-col-lg-4{grid-column:auto/span 4}.panel-grid .g-col-lg-5{grid-column:auto/span 5}.panel-grid .g-col-lg-6{grid-column:auto/span 6}.panel-grid .g-col-lg-7{grid-column:auto/span 7}.panel-grid .g-col-lg-8{grid-column:auto/span 8}.panel-grid .g-col-lg-9{grid-column:auto/span 9}.panel-grid .g-col-lg-10{grid-column:auto/span 10}.panel-grid .g-col-lg-11{grid-column:auto/span 11}.panel-grid .g-col-lg-12{grid-column:auto/span 12}.panel-grid .g-col-lg-13{grid-column:auto/span 13}.panel-grid .g-col-lg-14{grid-column:auto/span 14}.panel-grid .g-col-lg-15{grid-column:auto/span 15}.panel-grid .g-col-lg-16{grid-column:auto/span 16}.panel-grid .g-col-lg-17{grid-column:auto/span 17}.panel-grid .g-col-lg-18{grid-column:auto/span 18}.panel-grid .g-col-lg-19{grid-column:auto/span 19}.panel-grid .g-col-lg-20{grid-column:auto/span 20}.panel-grid .g-col-lg-21{grid-column:auto/span 21}.panel-grid .g-col-lg-22{grid-column:auto/span 22}.panel-grid .g-col-lg-23{grid-column:auto/span 23}.panel-grid .g-col-lg-24{grid-column:auto/span 24}.panel-grid .g-start-lg-1{grid-column-start:1}.panel-grid .g-start-lg-2{grid-column-start:2}.panel-grid .g-start-lg-3{grid-column-start:3}.panel-grid .g-start-lg-4{grid-column-start:4}.panel-grid .g-start-lg-5{grid-column-start:5}.panel-grid .g-start-lg-6{grid-column-start:6}.panel-grid .g-start-lg-7{grid-column-start:7}.panel-grid .g-start-lg-8{grid-column-start:8}.panel-grid .g-start-lg-9{grid-column-start:9}.panel-grid .g-start-lg-10{grid-column-start:10}.panel-grid .g-start-lg-11{grid-column-start:11}.panel-grid .g-start-lg-12{grid-column-start:12}.panel-grid .g-start-lg-13{grid-column-start:13}.panel-grid .g-start-lg-14{grid-column-start:14}.panel-grid .g-start-lg-15{grid-column-start:15}.panel-grid .g-start-lg-16{grid-column-start:16}.panel-grid .g-start-lg-17{grid-column-start:17}.panel-grid .g-start-lg-18{grid-column-start:18}.panel-grid .g-start-lg-19{grid-column-start:19}.panel-grid .g-start-lg-20{grid-column-start:20}.panel-grid .g-start-lg-21{grid-column-start:21}.panel-grid .g-start-lg-22{grid-column-start:22}.panel-grid .g-start-lg-23{grid-column-start:23}}@media(min-width: 1200px){.panel-grid .g-col-xl-1{grid-column:auto/span 1}.panel-grid .g-col-xl-2{grid-column:auto/span 2}.panel-grid .g-col-xl-3{grid-column:auto/span 3}.panel-grid .g-col-xl-4{grid-column:auto/span 4}.panel-grid .g-col-xl-5{grid-column:auto/span 5}.panel-grid .g-col-xl-6{grid-column:auto/span 6}.panel-grid .g-col-xl-7{grid-column:auto/span 7}.panel-grid .g-col-xl-8{grid-column:auto/span 8}.panel-grid .g-col-xl-9{grid-column:auto/span 9}.panel-grid .g-col-xl-10{grid-column:auto/span 10}.panel-grid .g-col-xl-11{grid-column:auto/span 11}.panel-grid .g-col-xl-12{grid-column:auto/span 12}.panel-grid .g-col-xl-13{grid-column:auto/span 13}.panel-grid .g-col-xl-14{grid-column:auto/span 14}.panel-grid .g-col-xl-15{grid-column:auto/span 15}.panel-grid .g-col-xl-16{grid-column:auto/span 16}.panel-grid .g-col-xl-17{grid-column:auto/span 17}.panel-grid .g-col-xl-18{grid-column:auto/span 18}.panel-grid .g-col-xl-19{grid-column:auto/span 19}.panel-grid .g-col-xl-20{grid-column:auto/span 20}.panel-grid .g-col-xl-21{grid-column:auto/span 21}.panel-grid .g-col-xl-22{grid-column:auto/span 22}.panel-grid .g-col-xl-23{grid-column:auto/span 23}.panel-grid .g-col-xl-24{grid-column:auto/span 24}.panel-grid .g-start-xl-1{grid-column-start:1}.panel-grid .g-start-xl-2{grid-column-start:2}.panel-grid .g-start-xl-3{grid-column-start:3}.panel-grid .g-start-xl-4{grid-column-start:4}.panel-grid .g-start-xl-5{grid-column-start:5}.panel-grid .g-start-xl-6{grid-column-start:6}.panel-grid .g-start-xl-7{grid-column-start:7}.panel-grid .g-start-xl-8{grid-column-start:8}.panel-grid .g-start-xl-9{grid-column-start:9}.panel-grid .g-start-xl-10{grid-column-start:10}.panel-grid .g-start-xl-11{grid-column-start:11}.panel-grid .g-start-xl-12{grid-column-start:12}.panel-grid .g-start-xl-13{grid-column-start:13}.panel-grid .g-start-xl-14{grid-column-start:14}.panel-grid .g-start-xl-15{grid-column-start:15}.panel-grid .g-start-xl-16{grid-column-start:16}.panel-grid .g-start-xl-17{grid-column-start:17}.panel-grid .g-start-xl-18{grid-column-start:18}.panel-grid .g-start-xl-19{grid-column-start:19}.panel-grid .g-start-xl-20{grid-column-start:20}.panel-grid .g-start-xl-21{grid-column-start:21}.panel-grid .g-start-xl-22{grid-column-start:22}.panel-grid .g-start-xl-23{grid-column-start:23}}@media(min-width: 1400px){.panel-grid .g-col-xxl-1{grid-column:auto/span 1}.panel-grid .g-col-xxl-2{grid-column:auto/span 2}.panel-grid .g-col-xxl-3{grid-column:auto/span 3}.panel-grid .g-col-xxl-4{grid-column:auto/span 4}.panel-grid .g-col-xxl-5{grid-column:auto/span 5}.panel-grid .g-col-xxl-6{grid-column:auto/span 6}.panel-grid .g-col-xxl-7{grid-column:auto/span 7}.panel-grid .g-col-xxl-8{grid-column:auto/span 8}.panel-grid .g-col-xxl-9{grid-column:auto/span 9}.panel-grid .g-col-xxl-10{grid-column:auto/span 10}.panel-grid .g-col-xxl-11{grid-column:auto/span 11}.panel-grid .g-col-xxl-12{grid-column:auto/span 12}.panel-grid .g-col-xxl-13{grid-column:auto/span 13}.panel-grid .g-col-xxl-14{grid-column:auto/span 14}.panel-grid .g-col-xxl-15{grid-column:auto/span 15}.panel-grid .g-col-xxl-16{grid-column:auto/span 16}.panel-grid .g-col-xxl-17{grid-column:auto/span 17}.panel-grid .g-col-xxl-18{grid-column:auto/span 18}.panel-grid .g-col-xxl-19{grid-column:auto/span 19}.panel-grid .g-col-xxl-20{grid-column:auto/span 20}.panel-grid .g-col-xxl-21{grid-column:auto/span 21}.panel-grid .g-col-xxl-22{grid-column:auto/span 22}.panel-grid .g-col-xxl-23{grid-column:auto/span 23}.panel-grid .g-col-xxl-24{grid-column:auto/span 24}.panel-grid .g-start-xxl-1{grid-column-start:1}.panel-grid .g-start-xxl-2{grid-column-start:2}.panel-grid .g-start-xxl-3{grid-column-start:3}.panel-grid .g-start-xxl-4{grid-column-start:4}.panel-grid .g-start-xxl-5{grid-column-start:5}.panel-grid .g-start-xxl-6{grid-column-start:6}.panel-grid .g-start-xxl-7{grid-column-start:7}.panel-grid .g-start-xxl-8{grid-column-start:8}.panel-grid .g-start-xxl-9{grid-column-start:9}.panel-grid .g-start-xxl-10{grid-column-start:10}.panel-grid .g-start-xxl-11{grid-column-start:11}.panel-grid .g-start-xxl-12{grid-column-start:12}.panel-grid .g-start-xxl-13{grid-column-start:13}.panel-grid .g-start-xxl-14{grid-column-start:14}.panel-grid .g-start-xxl-15{grid-column-start:15}.panel-grid .g-start-xxl-16{grid-column-start:16}.panel-grid .g-start-xxl-17{grid-column-start:17}.panel-grid .g-start-xxl-18{grid-column-start:18}.panel-grid .g-start-xxl-19{grid-column-start:19}.panel-grid .g-start-xxl-20{grid-column-start:20}.panel-grid .g-start-xxl-21{grid-column-start:21}.panel-grid .g-start-xxl-22{grid-column-start:22}.panel-grid .g-start-xxl-23{grid-column-start:23}}main{margin-top:1em;margin-bottom:1em}h1,.h1,h2,.h2{color:inherit;margin-top:2rem;margin-bottom:1rem;font-weight:600}h1.title,.title.h1{margin-top:0}main.content>section:first-of-type>h2:first-child,main.content>section:first-of-type>.h2:first-child{margin-top:0}h2,.h2{border-bottom:1px solid #dee2e6;padding-bottom:.5rem}h3,.h3{font-weight:600}h3,.h3,h4,.h4{opacity:.9;margin-top:1.5rem}h5,.h5,h6,.h6{opacity:.9}.header-section-number{color:#5a6570}.nav-link.active .header-section-number{color:inherit}mark,.mark{padding:0em}.panel-caption,.figure-caption,.subfigure-caption,.table-caption,figcaption,caption{font-size:.9rem;color:#5a6570}.quarto-layout-cell[data-ref-parent] caption{color:#5a6570}.column-margin figcaption,.margin-caption,div.aside,aside,.column-margin{color:#5a6570;font-size:.825rem}.panel-caption.margin-caption{text-align:inherit}.column-margin.column-container p{margin-bottom:0}.column-margin.column-container>*:not(.collapse):first-child{padding-bottom:.5em;display:block}.column-margin.column-container>*:not(.collapse):not(:first-child){padding-top:.5em;padding-bottom:.5em;display:block}.column-margin.column-container>*.collapse:not(.show){display:none}@media(min-width: 768px){.column-margin.column-container .callout-margin-content:first-child{margin-top:4.5em}.column-margin.column-container .callout-margin-content-simple:first-child{margin-top:3.5em}}.margin-caption>*{padding-top:.5em;padding-bottom:.5em}@media(max-width: 767.98px){.quarto-layout-row{flex-direction:column}}.nav-tabs .nav-item{margin-top:1px;cursor:pointer}.tab-content{margin-top:0px;border-left:#dee2e6 1px solid;border-right:#dee2e6 1px solid;border-bottom:#dee2e6 1px solid;margin-left:0;padding:1em;margin-bottom:1em}@media(max-width: 767.98px){.layout-sidebar{margin-left:0;margin-right:0}}.panel-sidebar,.panel-sidebar .form-control,.panel-input,.panel-input .form-control,.selectize-dropdown{font-size:.9rem}.panel-sidebar .form-control,.panel-input .form-control{padding-top:.1rem}.tab-pane div.sourceCode{margin-top:0px}.tab-pane>p{padding-top:0}.tab-pane>p:nth-child(1){padding-top:0}.tab-pane>p:last-child{margin-bottom:0}.tab-pane>pre:last-child{margin-bottom:0}.tab-content>.tab-pane:not(.active){display:none !important}div.sourceCode{background-color:rgba(233,236,239,.65);border:1px solid rgba(233,236,239,.65);border-radius:.375rem}pre.sourceCode{background-color:rgba(0,0,0,0)}pre.sourceCode{border:none;font-size:.875em;overflow:visible !important;padding:.4em}.callout pre.sourceCode{padding-left:0}div.sourceCode{overflow-y:hidden}.callout div.sourceCode{margin-left:initial}.blockquote{font-size:inherit;padding-left:1rem;padding-right:1.5rem;color:#5a6570}.blockquote h1:first-child,.blockquote .h1:first-child,.blockquote h2:first-child,.blockquote .h2:first-child,.blockquote h3:first-child,.blockquote .h3:first-child,.blockquote h4:first-child,.blockquote .h4:first-child,.blockquote h5:first-child,.blockquote .h5:first-child{margin-top:0}pre{background-color:initial;padding:initial;border:initial}p pre code:not(.sourceCode),li pre code:not(.sourceCode),pre code:not(.sourceCode){background-color:initial}p code:not(.sourceCode),li code:not(.sourceCode),td code:not(.sourceCode){background-color:#f8f9fa;padding:.2em}nav p code:not(.sourceCode),nav li code:not(.sourceCode),nav td code:not(.sourceCode){background-color:rgba(0,0,0,0);padding:0}td code:not(.sourceCode){white-space:pre-wrap}#quarto-embedded-source-code-modal>.modal-dialog{max-width:1000px;padding-left:1.75rem;padding-right:1.75rem}#quarto-embedded-source-code-modal>.modal-dialog>.modal-content>.modal-body{padding:0}#quarto-embedded-source-code-modal>.modal-dialog>.modal-content>.modal-body div.sourceCode{margin:0;padding:.2rem .2rem;border-radius:0px;border:none}#quarto-embedded-source-code-modal>.modal-dialog>.modal-content>.modal-header{padding:.7rem}.code-tools-button{font-size:1rem;padding:.15rem .15rem;margin-left:5px;color:rgba(33,37,41,.75);background-color:rgba(0,0,0,0);transition:initial;cursor:pointer}.code-tools-button>.bi::before{display:inline-block;height:1rem;width:1rem;content:"";vertical-align:-0.125em;background-image:url('data:image/svg+xml,');background-repeat:no-repeat;background-size:1rem 1rem}.code-tools-button:hover>.bi::before{background-image:url('data:image/svg+xml,')}#quarto-embedded-source-code-modal .code-copy-button>.bi::before{background-image:url('data:image/svg+xml,')}#quarto-embedded-source-code-modal .code-copy-button-checked>.bi::before{background-image:url('data:image/svg+xml,')}.sidebar{will-change:top;transition:top 200ms linear;position:sticky;overflow-y:auto;padding-top:1.2em;max-height:100vh}.sidebar.toc-left,.sidebar.margin-sidebar{top:0px;padding-top:1em}.sidebar.quarto-banner-title-block-sidebar>*{padding-top:1.65em}figure .quarto-notebook-link{margin-top:.5em}.quarto-notebook-link{font-size:.75em;color:rgba(33,37,41,.75);margin-bottom:1em;text-decoration:none;display:block}.quarto-notebook-link:hover{text-decoration:underline;color:#0d6efd}.quarto-notebook-link::before{display:inline-block;height:.75rem;width:.75rem;margin-bottom:0em;margin-right:.25em;content:"";vertical-align:-0.125em;background-image:url('data:image/svg+xml,');background-repeat:no-repeat;background-size:.75rem .75rem}.toc-actions i.bi,.quarto-code-links i.bi,.quarto-other-links i.bi,.quarto-alternate-notebooks i.bi,.quarto-alternate-formats i.bi{margin-right:.4em;font-size:.8rem}.quarto-other-links-text-target .quarto-code-links i.bi,.quarto-other-links-text-target .quarto-other-links i.bi{margin-right:.2em}.quarto-other-formats-text-target .quarto-alternate-formats i.bi{margin-right:.1em}.toc-actions i.bi.empty,.quarto-code-links i.bi.empty,.quarto-other-links i.bi.empty,.quarto-alternate-notebooks i.bi.empty,.quarto-alternate-formats i.bi.empty{padding-left:1em}.quarto-notebook h2,.quarto-notebook .h2{border-bottom:none}.quarto-notebook .cell-container{display:flex}.quarto-notebook .cell-container .cell{flex-grow:4}.quarto-notebook .cell-container .cell-decorator{padding-top:1.5em;padding-right:1em;text-align:right}.quarto-notebook .cell-container.code-fold .cell-decorator{padding-top:3em}.quarto-notebook .cell-code code{white-space:pre-wrap}.quarto-notebook .cell .cell-output-stderr pre code,.quarto-notebook .cell .cell-output-stdout pre code{white-space:pre-wrap;overflow-wrap:anywhere}.toc-actions,.quarto-alternate-formats,.quarto-other-links,.quarto-code-links,.quarto-alternate-notebooks{padding-left:0em}.sidebar .toc-actions a,.sidebar .quarto-alternate-formats a,.sidebar .quarto-other-links a,.sidebar .quarto-code-links a,.sidebar .quarto-alternate-notebooks a,.sidebar nav[role=doc-toc] a{text-decoration:none}.sidebar .toc-actions a:hover,.sidebar .quarto-other-links a:hover,.sidebar .quarto-code-links a:hover,.sidebar .quarto-alternate-formats a:hover,.sidebar .quarto-alternate-notebooks a:hover{color:#0d6efd}.sidebar .toc-actions h2,.sidebar .toc-actions .h2,.sidebar .quarto-code-links h2,.sidebar .quarto-code-links .h2,.sidebar .quarto-other-links h2,.sidebar .quarto-other-links .h2,.sidebar .quarto-alternate-notebooks h2,.sidebar .quarto-alternate-notebooks .h2,.sidebar .quarto-alternate-formats h2,.sidebar .quarto-alternate-formats .h2,.sidebar nav[role=doc-toc]>h2,.sidebar nav[role=doc-toc]>.h2{font-weight:500;margin-bottom:.2rem;margin-top:.3rem;font-family:inherit;border-bottom:0;padding-bottom:0;padding-top:0px}.sidebar .toc-actions>h2,.sidebar .toc-actions>.h2,.sidebar .quarto-code-links>h2,.sidebar .quarto-code-links>.h2,.sidebar .quarto-other-links>h2,.sidebar .quarto-other-links>.h2,.sidebar .quarto-alternate-notebooks>h2,.sidebar .quarto-alternate-notebooks>.h2,.sidebar .quarto-alternate-formats>h2,.sidebar .quarto-alternate-formats>.h2{font-size:.8rem}.sidebar nav[role=doc-toc]>h2,.sidebar nav[role=doc-toc]>.h2{font-size:.875rem}.sidebar nav[role=doc-toc]>ul a{border-left:1px solid #e9ecef;padding-left:.6rem}.sidebar .toc-actions h2>ul a,.sidebar .toc-actions .h2>ul a,.sidebar .quarto-code-links h2>ul a,.sidebar .quarto-code-links .h2>ul a,.sidebar .quarto-other-links h2>ul a,.sidebar .quarto-other-links .h2>ul a,.sidebar .quarto-alternate-notebooks h2>ul a,.sidebar .quarto-alternate-notebooks .h2>ul a,.sidebar .quarto-alternate-formats h2>ul a,.sidebar .quarto-alternate-formats .h2>ul a{border-left:none;padding-left:.6rem}.sidebar .toc-actions ul a:empty,.sidebar .quarto-code-links ul a:empty,.sidebar .quarto-other-links ul a:empty,.sidebar .quarto-alternate-notebooks ul a:empty,.sidebar .quarto-alternate-formats ul a:empty,.sidebar nav[role=doc-toc]>ul a:empty{display:none}.sidebar .toc-actions ul,.sidebar .quarto-code-links ul,.sidebar .quarto-other-links ul,.sidebar .quarto-alternate-notebooks ul,.sidebar .quarto-alternate-formats ul{padding-left:0;list-style:none}.sidebar nav[role=doc-toc] ul{list-style:none;padding-left:0;list-style:none}.sidebar nav[role=doc-toc]>ul{margin-left:.45em}.quarto-margin-sidebar nav[role=doc-toc]{padding-left:.5em}.sidebar .toc-actions>ul,.sidebar .quarto-code-links>ul,.sidebar .quarto-other-links>ul,.sidebar .quarto-alternate-notebooks>ul,.sidebar .quarto-alternate-formats>ul{font-size:.8rem}.sidebar nav[role=doc-toc]>ul{font-size:.875rem}.sidebar .toc-actions ul li a,.sidebar .quarto-code-links ul li a,.sidebar .quarto-other-links ul li a,.sidebar .quarto-alternate-notebooks ul li a,.sidebar .quarto-alternate-formats ul li a,.sidebar nav[role=doc-toc]>ul li a{line-height:1.1rem;padding-bottom:.2rem;padding-top:.2rem;color:inherit}.sidebar nav[role=doc-toc] ul>li>ul>li>a{padding-left:1.2em}.sidebar nav[role=doc-toc] ul>li>ul>li>ul>li>a{padding-left:2.4em}.sidebar nav[role=doc-toc] ul>li>ul>li>ul>li>ul>li>a{padding-left:3.6em}.sidebar nav[role=doc-toc] ul>li>ul>li>ul>li>ul>li>ul>li>a{padding-left:4.8em}.sidebar nav[role=doc-toc] ul>li>ul>li>ul>li>ul>li>ul>li>ul>li>a{padding-left:6em}.sidebar nav[role=doc-toc] ul>li>a.active,.sidebar nav[role=doc-toc] ul>li>ul>li>a.active{border-left:1px solid #0d6efd;color:#0d6efd !important}.sidebar nav[role=doc-toc] ul>li>a:hover,.sidebar nav[role=doc-toc] ul>li>ul>li>a:hover{color:#0d6efd !important}kbd,.kbd{color:#212529;background-color:#f8f9fa;border:1px solid;border-radius:5px;border-color:#dee2e6}.quarto-appendix-contents div.hanging-indent{margin-left:0em}.quarto-appendix-contents div.hanging-indent div.csl-entry{margin-left:1em;text-indent:-1em}.citation a,.footnote-ref{text-decoration:none}.footnotes ol{padding-left:1em}.tippy-content>*{margin-bottom:.7em}.tippy-content>*:last-child{margin-bottom:0}.callout{margin-top:1.25rem;margin-bottom:1.25rem;border-radius:.375rem;overflow-wrap:break-word}.callout .callout-title-container{overflow-wrap:anywhere}.callout.callout-style-simple{padding:.4em .7em;border-left:5px solid;border-right:1px solid #dee2e6;border-top:1px solid #dee2e6;border-bottom:1px solid #dee2e6}.callout.callout-style-default{border-left:5px solid;border-right:1px solid #dee2e6;border-top:1px solid #dee2e6;border-bottom:1px solid #dee2e6}.callout .callout-body-container{flex-grow:1}.callout.callout-style-simple .callout-body{font-size:.9rem;font-weight:400}.callout.callout-style-default .callout-body{font-size:.9rem;font-weight:400}.callout:not(.no-icon).callout-titled.callout-style-simple .callout-body{padding-left:1.6em}.callout.callout-titled>.callout-header{padding-top:.2em;margin-bottom:-0.2em}.callout.callout-style-simple>div.callout-header{border-bottom:none;font-size:.9rem;font-weight:600;opacity:75%}.callout.callout-style-default>div.callout-header{border-bottom:none;font-weight:600;opacity:85%;font-size:.9rem;padding-left:.5em;padding-right:.5em}.callout.callout-style-default .callout-body{padding-left:.5em;padding-right:.5em}.callout.callout-style-default .callout-body>:first-child{padding-top:.5rem;margin-top:0}.callout>div.callout-header[data-bs-toggle=collapse]{cursor:pointer}.callout.callout-style-default .callout-header[aria-expanded=false],.callout.callout-style-default .callout-header[aria-expanded=true]{padding-top:0px;margin-bottom:0px;align-items:center}.callout.callout-titled .callout-body>:last-child:not(.sourceCode),.callout.callout-titled .callout-body>div>:last-child:not(.sourceCode){padding-bottom:.5rem;margin-bottom:0}.callout:not(.callout-titled) .callout-body>:first-child,.callout:not(.callout-titled) .callout-body>div>:first-child{margin-top:.25rem}.callout:not(.callout-titled) .callout-body>:last-child,.callout:not(.callout-titled) .callout-body>div>:last-child{margin-bottom:.2rem}.callout.callout-style-simple .callout-icon::before,.callout.callout-style-simple .callout-toggle::before{height:1rem;width:1rem;display:inline-block;content:"";background-repeat:no-repeat;background-size:1rem 1rem}.callout.callout-style-default .callout-icon::before,.callout.callout-style-default .callout-toggle::before{height:.9rem;width:.9rem;display:inline-block;content:"";background-repeat:no-repeat;background-size:.9rem .9rem}.callout.callout-style-default .callout-toggle::before{margin-top:5px}.callout .callout-btn-toggle .callout-toggle::before{transition:transform .2s linear}.callout .callout-header[aria-expanded=false] .callout-toggle::before{transform:rotate(-90deg)}.callout .callout-header[aria-expanded=true] .callout-toggle::before{transform:none}.callout.callout-style-simple:not(.no-icon) div.callout-icon-container{padding-top:.2em;padding-right:.55em}.callout.callout-style-default:not(.no-icon) div.callout-icon-container{padding-top:.1em;padding-right:.35em}.callout.callout-style-default:not(.no-icon) div.callout-title-container{margin-top:-1px}.callout.callout-style-default.callout-caution:not(.no-icon) div.callout-icon-container{padding-top:.3em;padding-right:.35em}.callout>.callout-body>.callout-icon-container>.no-icon,.callout>.callout-header>.callout-icon-container>.no-icon{display:none}div.callout.callout{border-left-color:rgba(33,37,41,.75)}div.callout.callout-style-default>.callout-header{background-color:rgba(33,37,41,.75)}div.callout-note.callout{border-left-color:#0d6efd}div.callout-note.callout-style-default>.callout-header{background-color:#e7f1ff}div.callout-note:not(.callout-titled) .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-note.callout-titled .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-note .callout-toggle::before{background-image:url('data:image/svg+xml,')}div.callout-tip.callout{border-left-color:#198754}div.callout-tip.callout-style-default>.callout-header{background-color:#e8f3ee}div.callout-tip:not(.callout-titled) .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-tip.callout-titled .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-tip .callout-toggle::before{background-image:url('data:image/svg+xml,')}div.callout-warning.callout{border-left-color:#ffc107}div.callout-warning.callout-style-default>.callout-header{background-color:#fff9e6}div.callout-warning:not(.callout-titled) .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-warning.callout-titled .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-warning .callout-toggle::before{background-image:url('data:image/svg+xml,')}div.callout-caution.callout{border-left-color:#fd7e14}div.callout-caution.callout-style-default>.callout-header{background-color:#fff2e8}div.callout-caution:not(.callout-titled) .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-caution.callout-titled .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-caution .callout-toggle::before{background-image:url('data:image/svg+xml,')}div.callout-important.callout{border-left-color:#dc3545}div.callout-important.callout-style-default>.callout-header{background-color:#fcebec}div.callout-important:not(.callout-titled) .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-important.callout-titled .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-important .callout-toggle::before{background-image:url('data:image/svg+xml,')}.quarto-toggle-container{display:flex;align-items:center}.quarto-reader-toggle .bi::before,.quarto-color-scheme-toggle .bi::before{display:inline-block;height:1rem;width:1rem;content:"";background-repeat:no-repeat;background-size:1rem 1rem}.sidebar-navigation{padding-left:20px}.navbar{background-color:#517699;color:#fdfefe}.navbar .quarto-color-scheme-toggle:not(.alternate) .bi::before{background-image:url('data:image/svg+xml,')}.navbar .quarto-color-scheme-toggle.alternate .bi::before{background-image:url('data:image/svg+xml,')}.sidebar-navigation .quarto-color-scheme-toggle:not(.alternate) .bi::before{background-image:url('data:image/svg+xml,')}.sidebar-navigation .quarto-color-scheme-toggle.alternate .bi::before{background-image:url('data:image/svg+xml,')}.quarto-sidebar-toggle{border-color:#dee2e6;border-bottom-left-radius:.375rem;border-bottom-right-radius:.375rem;border-style:solid;border-width:1px;overflow:hidden;border-top-width:0px;padding-top:0px !important}.quarto-sidebar-toggle-title{cursor:pointer;padding-bottom:2px;margin-left:.25em;text-align:center;font-weight:400;font-size:.775em}#quarto-content .quarto-sidebar-toggle{background:#fafafa}#quarto-content .quarto-sidebar-toggle-title{color:#212529}.quarto-sidebar-toggle-icon{color:#dee2e6;margin-right:.5em;float:right;transition:transform .2s ease}.quarto-sidebar-toggle-icon::before{padding-top:5px}.quarto-sidebar-toggle.expanded .quarto-sidebar-toggle-icon{transform:rotate(-180deg)}.quarto-sidebar-toggle.expanded .quarto-sidebar-toggle-title{border-bottom:solid #dee2e6 1px}.quarto-sidebar-toggle-contents{background-color:#fff;padding-right:10px;padding-left:10px;margin-top:0px !important;transition:max-height .5s ease}.quarto-sidebar-toggle.expanded .quarto-sidebar-toggle-contents{padding-top:1em;padding-bottom:10px}@media(max-width: 767.98px){.sidebar-menu-container{padding-bottom:5em}}.quarto-sidebar-toggle:not(.expanded) .quarto-sidebar-toggle-contents{padding-top:0px !important;padding-bottom:0px}nav[role=doc-toc]{z-index:1020}#quarto-sidebar>*,nav[role=doc-toc]>*{transition:opacity .1s ease,border .1s ease}#quarto-sidebar.slow>*,nav[role=doc-toc].slow>*{transition:opacity .4s ease,border .4s ease}.quarto-color-scheme-toggle:not(.alternate).top-right .bi::before{background-image:url('data:image/svg+xml,')}.quarto-color-scheme-toggle.alternate.top-right .bi::before{background-image:url('data:image/svg+xml,')}#quarto-appendix.default{border-top:1px solid #dee2e6}#quarto-appendix.default{background-color:#fff;padding-top:1.5em;margin-top:2em;z-index:998}#quarto-appendix.default .quarto-appendix-heading{margin-top:0;line-height:1.4em;font-weight:600;opacity:.9;border-bottom:none;margin-bottom:0}#quarto-appendix.default .footnotes ol,#quarto-appendix.default .footnotes ol li>p:last-of-type,#quarto-appendix.default .quarto-appendix-contents>p:last-of-type{margin-bottom:0}#quarto-appendix.default .footnotes ol{margin-left:.5em}#quarto-appendix.default .quarto-appendix-secondary-label{margin-bottom:.4em}#quarto-appendix.default .quarto-appendix-bibtex{font-size:.7em;padding:1em;border:solid 1px #dee2e6;margin-bottom:1em}#quarto-appendix.default .quarto-appendix-bibtex code.sourceCode{white-space:pre-wrap}#quarto-appendix.default .quarto-appendix-citeas{font-size:.9em;padding:1em;border:solid 1px #dee2e6;margin-bottom:1em}#quarto-appendix.default .quarto-appendix-heading{font-size:1em !important}#quarto-appendix.default *[role=doc-endnotes]>ol,#quarto-appendix.default .quarto-appendix-contents>*:not(h2):not(.h2){font-size:.9em}#quarto-appendix.default section{padding-bottom:1.5em}#quarto-appendix.default section *[role=doc-endnotes],#quarto-appendix.default section>*:not(a){opacity:.9;word-wrap:break-word}.btn.btn-quarto,div.cell-output-display .btn-quarto{--bs-btn-color: #fefefe;--bs-btn-bg: #6c757d;--bs-btn-border-color: #6c757d;--bs-btn-hover-color: #fefefe;--bs-btn-hover-bg: #828a91;--bs-btn-hover-border-color: #7b838a;--bs-btn-focus-shadow-rgb: 130, 138, 144;--bs-btn-active-color: #000;--bs-btn-active-bg: #899197;--bs-btn-active-border-color: #7b838a;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #ffffff;--bs-btn-disabled-bg: #6c757d;--bs-btn-disabled-border-color: #6c757d}nav.quarto-secondary-nav.color-navbar{background-color:#517699;color:#fdfefe}nav.quarto-secondary-nav.color-navbar h1,nav.quarto-secondary-nav.color-navbar .h1,nav.quarto-secondary-nav.color-navbar .quarto-btn-toggle{color:#fdfefe}@media(max-width: 991.98px){body.nav-sidebar .quarto-title-banner{margin-bottom:0;padding-bottom:1em}body.nav-sidebar #title-block-header{margin-block-end:0}}p.subtitle{margin-top:.25em;margin-bottom:.5em}code a:any-link{color:inherit;text-decoration-color:#6c757d}/*! light */div.observablehq table thead tr th{background-color:var(--bs-body-bg)}input,button,select,optgroup,textarea{background-color:var(--bs-body-bg)}.code-annotated .code-copy-button{margin-right:1.25em;margin-top:0;padding-bottom:0;padding-top:3px}.code-annotation-gutter-bg{background-color:#fff}.code-annotation-gutter{background-color:rgba(233,236,239,.65)}.code-annotation-gutter,.code-annotation-gutter-bg{height:100%;width:calc(20px + .5em);position:absolute;top:0;right:0}dl.code-annotation-container-grid dt{margin-right:1em;margin-top:.25rem}dl.code-annotation-container-grid dt{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;color:#383f45;border:solid #383f45 1px;border-radius:50%;height:22px;width:22px;line-height:22px;font-size:11px;text-align:center;vertical-align:middle;text-decoration:none}dl.code-annotation-container-grid dt[data-target-cell]{cursor:pointer}dl.code-annotation-container-grid dt[data-target-cell].code-annotation-active{color:#fff;border:solid #aaa 1px;background-color:#aaa}pre.code-annotation-code{padding-top:0;padding-bottom:0}pre.code-annotation-code code{z-index:3}#code-annotation-line-highlight-gutter{width:100%;border-top:solid rgba(170,170,170,.2666666667) 1px;border-bottom:solid rgba(170,170,170,.2666666667) 1px;z-index:2;background-color:rgba(170,170,170,.1333333333)}#code-annotation-line-highlight{margin-left:-4em;width:calc(100% + 4em);border-top:solid rgba(170,170,170,.2666666667) 1px;border-bottom:solid rgba(170,170,170,.2666666667) 1px;z-index:2;background-color:rgba(170,170,170,.1333333333)}code.sourceCode .code-annotation-anchor.code-annotation-active{background-color:var(--quarto-hl-normal-color, #aaaaaa);border:solid var(--quarto-hl-normal-color, #aaaaaa) 1px;color:#e9ecef;font-weight:bolder}code.sourceCode .code-annotation-anchor{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;color:var(--quarto-hl-co-color);border:solid var(--quarto-hl-co-color) 1px;border-radius:50%;height:18px;width:18px;font-size:9px;margin-top:2px}code.sourceCode button.code-annotation-anchor{padding:2px;user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none}code.sourceCode a.code-annotation-anchor{line-height:18px;text-align:center;vertical-align:middle;cursor:default;text-decoration:none}@media print{.page-columns .column-screen-inset{grid-column:page-start-inset/page-end-inset;z-index:998;opacity:.999}.page-columns .column-screen-inset table{background:#fff}.page-columns .column-screen-inset-left{grid-column:page-start-inset/body-content-end;z-index:998;opacity:.999}.page-columns .column-screen-inset-left table{background:#fff}.page-columns .column-screen-inset-right{grid-column:body-content-start/page-end-inset;z-index:998;opacity:.999}.page-columns .column-screen-inset-right table{background:#fff}.page-columns .column-screen{grid-column:page-start/page-end;z-index:998;opacity:.999}.page-columns .column-screen table{background:#fff}.page-columns .column-screen-left{grid-column:page-start/body-content-end;z-index:998;opacity:.999}.page-columns .column-screen-left table{background:#fff}.page-columns .column-screen-right{grid-column:body-content-start/page-end;z-index:998;opacity:.999}.page-columns .column-screen-right table{background:#fff}.page-columns .column-screen-inset-shaded{grid-column:page-start-inset/page-end-inset;padding:1em;background:#f8f9fa;z-index:998;opacity:.999;margin-bottom:1em}}.quarto-video{margin-bottom:1em}.table{border-top:1px solid #d3d8dc;border-bottom:1px solid #d3d8dc}.table>thead{border-top-width:0;border-bottom:1px solid #9ba5ae}.table a{word-break:break-word}.table>:not(caption)>*>*{background-color:unset;color:unset}#quarto-document-content .crosstalk-input .checkbox input[type=checkbox],#quarto-document-content .crosstalk-input .checkbox-inline input[type=checkbox]{position:unset;margin-top:unset;margin-left:unset}#quarto-document-content .row{margin-left:unset;margin-right:unset}.quarto-xref{white-space:nowrap}#quarto-draft-alert{margin-top:0px;margin-bottom:0px;padding:.3em;text-align:center;font-size:.9em}#quarto-draft-alert i{margin-right:.3em}a.external:after{content:"";background-image:url('data:image/svg+xml,');background-size:contain;background-repeat:no-repeat;background-position:center center;margin-left:.2em;padding-right:.75em}div.sourceCode code a.external:after{content:none}a.external:after:hover{cursor:pointer}.quarto-ext-icon{display:inline-block;font-size:.75em;padding-left:.3em}.code-with-filename .code-with-filename-file{margin-bottom:0;padding-bottom:2px;padding-top:2px;padding-left:.7em;border:var(--quarto-border-width) solid var(--quarto-border-color);border-radius:var(--quarto-border-radius);border-bottom:0;border-bottom-left-radius:0%;border-bottom-right-radius:0%}.code-with-filename div.sourceCode,.reveal .code-with-filename div.sourceCode{margin-top:0;border-top-left-radius:0%;border-top-right-radius:0%}.code-with-filename .code-with-filename-file pre{margin-bottom:0}.code-with-filename .code-with-filename-file{background-color:rgba(219,219,219,.8)}.quarto-dark .code-with-filename .code-with-filename-file{background-color:#555}.code-with-filename .code-with-filename-file strong{font-weight:400}.quarto-title-banner{margin-bottom:1em;color:#fdfefe;background:#517699}.quarto-title-banner a{color:#fdfefe}.quarto-title-banner h1,.quarto-title-banner .h1,.quarto-title-banner h2,.quarto-title-banner .h2{color:#fdfefe}.quarto-title-banner .code-tools-button{color:#b9dcdc}.quarto-title-banner .code-tools-button:hover{color:#fdfefe}.quarto-title-banner .code-tools-button>.bi::before{background-image:url('data:image/svg+xml,')}.quarto-title-banner .code-tools-button:hover>.bi::before{background-image:url('data:image/svg+xml,')}.quarto-title-banner .quarto-title .title{font-weight:600}.quarto-title-banner .quarto-categories{margin-top:.75em}@media(min-width: 992px){.quarto-title-banner{padding-top:2.5em;padding-bottom:2.5em}}@media(max-width: 991.98px){.quarto-title-banner{padding-top:1em;padding-bottom:1em}}@media(max-width: 767.98px){body.hypothesis-enabled #title-block-header>*{padding-right:20px}}main.quarto-banner-title-block>section:first-child>h2,main.quarto-banner-title-block>section:first-child>.h2,main.quarto-banner-title-block>section:first-child>h3,main.quarto-banner-title-block>section:first-child>.h3,main.quarto-banner-title-block>section:first-child>h4,main.quarto-banner-title-block>section:first-child>.h4{margin-top:0}.quarto-title .quarto-categories{display:flex;flex-wrap:wrap;row-gap:.5em;column-gap:.4em;padding-bottom:.5em;margin-top:.75em}.quarto-title .quarto-categories .quarto-category{padding:.25em .75em;font-size:.65em;text-transform:uppercase;border:solid 1px;border-radius:.375rem;opacity:.6}.quarto-title .quarto-categories .quarto-category a{color:inherit}.quarto-title-meta-container{display:grid;grid-template-columns:1fr auto}.quarto-title-meta-column-end{display:flex;flex-direction:column;padding-left:1em}.quarto-title-meta-column-end a .bi{margin-right:.3em}#title-block-header.quarto-title-block.default .quarto-title-meta{display:grid;grid-template-columns:repeat(2, 1fr);grid-column-gap:1em}#title-block-header.quarto-title-block.default .quarto-title .title{margin-bottom:0}#title-block-header.quarto-title-block.default .quarto-title-author-orcid img{margin-top:-0.2em;height:.8em;width:.8em}#title-block-header.quarto-title-block.default .quarto-title-author-email{opacity:.7}#title-block-header.quarto-title-block.default .quarto-description p:last-of-type{margin-bottom:0}#title-block-header.quarto-title-block.default .quarto-title-meta-contents p,#title-block-header.quarto-title-block.default .quarto-title-authors p,#title-block-header.quarto-title-block.default .quarto-title-affiliations p{margin-bottom:.1em}#title-block-header.quarto-title-block.default .quarto-title-meta-heading{text-transform:uppercase;margin-top:1em;font-size:.8em;opacity:.8;font-weight:400}#title-block-header.quarto-title-block.default .quarto-title-meta-contents{font-size:.9em}#title-block-header.quarto-title-block.default .quarto-title-meta-contents p.affiliation:last-of-type{margin-bottom:.1em}#title-block-header.quarto-title-block.default p.affiliation{margin-bottom:.1em}#title-block-header.quarto-title-block.default .keywords,#title-block-header.quarto-title-block.default .description,#title-block-header.quarto-title-block.default .abstract{margin-top:0}#title-block-header.quarto-title-block.default .keywords>p,#title-block-header.quarto-title-block.default .description>p,#title-block-header.quarto-title-block.default .abstract>p{font-size:.9em}#title-block-header.quarto-title-block.default .keywords>p:last-of-type,#title-block-header.quarto-title-block.default .description>p:last-of-type,#title-block-header.quarto-title-block.default .abstract>p:last-of-type{margin-bottom:0}#title-block-header.quarto-title-block.default .keywords .block-title,#title-block-header.quarto-title-block.default .description .block-title,#title-block-header.quarto-title-block.default .abstract .block-title{margin-top:1em;text-transform:uppercase;font-size:.8em;opacity:.8;font-weight:400}#title-block-header.quarto-title-block.default .quarto-title-meta-author{display:grid;grid-template-columns:minmax(max-content, 1fr) 1fr;grid-column-gap:1em}.quarto-title-tools-only{display:flex;justify-content:right} diff --git a/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/uncertainty_files/libs/bootstrap/bootstrap.min.js b/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/uncertainty_files/libs/bootstrap/bootstrap.min.js deleted file mode 100644 index e8f21f703..000000000 --- a/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/uncertainty_files/libs/bootstrap/bootstrap.min.js +++ /dev/null @@ -1,7 +0,0 @@ -/*! - * Bootstrap v5.3.1 (https://getbootstrap.com/) - * Copyright 2011-2023 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) - */ -!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).bootstrap=e()}(this,(function(){"use strict";const t=new Map,e={set(e,i,n){t.has(e)||t.set(e,new Map);const s=t.get(e);s.has(i)||0===s.size?s.set(i,n):console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(s.keys())[0]}.`)},get:(e,i)=>t.has(e)&&t.get(e).get(i)||null,remove(e,i){if(!t.has(e))return;const n=t.get(e);n.delete(i),0===n.size&&t.delete(e)}},i="transitionend",n=t=>(t&&window.CSS&&window.CSS.escape&&(t=t.replace(/#([^\s"#']+)/g,((t,e)=>`#${CSS.escape(e)}`))),t),s=t=>{t.dispatchEvent(new Event(i))},o=t=>!(!t||"object"!=typeof t)&&(void 0!==t.jquery&&(t=t[0]),void 0!==t.nodeType),r=t=>o(t)?t.jquery?t[0]:t:"string"==typeof t&&t.length>0?document.querySelector(n(t)):null,a=t=>{if(!o(t)||0===t.getClientRects().length)return!1;const e="visible"===getComputedStyle(t).getPropertyValue("visibility"),i=t.closest("details:not([open])");if(!i)return e;if(i!==t){const e=t.closest("summary");if(e&&e.parentNode!==i)return!1;if(null===e)return!1}return e},l=t=>!t||t.nodeType!==Node.ELEMENT_NODE||!!t.classList.contains("disabled")||(void 0!==t.disabled?t.disabled:t.hasAttribute("disabled")&&"false"!==t.getAttribute("disabled")),c=t=>{if(!document.documentElement.attachShadow)return null;if("function"==typeof t.getRootNode){const e=t.getRootNode();return e instanceof ShadowRoot?e:null}return t instanceof ShadowRoot?t:t.parentNode?c(t.parentNode):null},h=()=>{},d=t=>{t.offsetHeight},u=()=>window.jQuery&&!document.body.hasAttribute("data-bs-no-jquery")?window.jQuery:null,f=[],p=()=>"rtl"===document.documentElement.dir,m=t=>{var e;e=()=>{const e=u();if(e){const i=t.NAME,n=e.fn[i];e.fn[i]=t.jQueryInterface,e.fn[i].Constructor=t,e.fn[i].noConflict=()=>(e.fn[i]=n,t.jQueryInterface)}},"loading"===document.readyState?(f.length||document.addEventListener("DOMContentLoaded",(()=>{for(const t of f)t()})),f.push(e)):e()},g=(t,e=[],i=t)=>"function"==typeof t?t(...e):i,_=(t,e,n=!0)=>{if(!n)return void g(t);const o=(t=>{if(!t)return 0;let{transitionDuration:e,transitionDelay:i}=window.getComputedStyle(t);const n=Number.parseFloat(e),s=Number.parseFloat(i);return n||s?(e=e.split(",")[0],i=i.split(",")[0],1e3*(Number.parseFloat(e)+Number.parseFloat(i))):0})(e)+5;let r=!1;const a=({target:n})=>{n===e&&(r=!0,e.removeEventListener(i,a),g(t))};e.addEventListener(i,a),setTimeout((()=>{r||s(e)}),o)},b=(t,e,i,n)=>{const s=t.length;let o=t.indexOf(e);return-1===o?!i&&n?t[s-1]:t[0]:(o+=i?1:-1,n&&(o=(o+s)%s),t[Math.max(0,Math.min(o,s-1))])},v=/[^.]*(?=\..*)\.|.*/,y=/\..*/,w=/::\d+$/,A={};let E=1;const T={mouseenter:"mouseover",mouseleave:"mouseout"},C=new Set(["click","dblclick","mouseup","mousedown","contextmenu","mousewheel","DOMMouseScroll","mouseover","mouseout","mousemove","selectstart","selectend","keydown","keypress","keyup","orientationchange","touchstart","touchmove","touchend","touchcancel","pointerdown","pointermove","pointerup","pointerleave","pointercancel","gesturestart","gesturechange","gestureend","focus","blur","change","reset","select","submit","focusin","focusout","load","unload","beforeunload","resize","move","DOMContentLoaded","readystatechange","error","abort","scroll"]);function O(t,e){return e&&`${e}::${E++}`||t.uidEvent||E++}function x(t){const e=O(t);return t.uidEvent=e,A[e]=A[e]||{},A[e]}function k(t,e,i=null){return Object.values(t).find((t=>t.callable===e&&t.delegationSelector===i))}function L(t,e,i){const n="string"==typeof e,s=n?i:e||i;let o=I(t);return C.has(o)||(o=t),[n,s,o]}function S(t,e,i,n,s){if("string"!=typeof e||!t)return;let[o,r,a]=L(e,i,n);if(e in T){const t=t=>function(e){if(!e.relatedTarget||e.relatedTarget!==e.delegateTarget&&!e.delegateTarget.contains(e.relatedTarget))return t.call(this,e)};r=t(r)}const l=x(t),c=l[a]||(l[a]={}),h=k(c,r,o?i:null);if(h)return void(h.oneOff=h.oneOff&&s);const d=O(r,e.replace(v,"")),u=o?function(t,e,i){return function n(s){const o=t.querySelectorAll(e);for(let{target:r}=s;r&&r!==this;r=r.parentNode)for(const a of o)if(a===r)return P(s,{delegateTarget:r}),n.oneOff&&N.off(t,s.type,e,i),i.apply(r,[s])}}(t,i,r):function(t,e){return function i(n){return P(n,{delegateTarget:t}),i.oneOff&&N.off(t,n.type,e),e.apply(t,[n])}}(t,r);u.delegationSelector=o?i:null,u.callable=r,u.oneOff=s,u.uidEvent=d,c[d]=u,t.addEventListener(a,u,o)}function D(t,e,i,n,s){const o=k(e[i],n,s);o&&(t.removeEventListener(i,o,Boolean(s)),delete e[i][o.uidEvent])}function $(t,e,i,n){const s=e[i]||{};for(const[o,r]of Object.entries(s))o.includes(n)&&D(t,e,i,r.callable,r.delegationSelector)}function I(t){return t=t.replace(y,""),T[t]||t}const N={on(t,e,i,n){S(t,e,i,n,!1)},one(t,e,i,n){S(t,e,i,n,!0)},off(t,e,i,n){if("string"!=typeof e||!t)return;const[s,o,r]=L(e,i,n),a=r!==e,l=x(t),c=l[r]||{},h=e.startsWith(".");if(void 0===o){if(h)for(const i of Object.keys(l))$(t,l,i,e.slice(1));for(const[i,n]of Object.entries(c)){const s=i.replace(w,"");a&&!e.includes(s)||D(t,l,r,n.callable,n.delegationSelector)}}else{if(!Object.keys(c).length)return;D(t,l,r,o,s?i:null)}},trigger(t,e,i){if("string"!=typeof e||!t)return null;const n=u();let s=null,o=!0,r=!0,a=!1;e!==I(e)&&n&&(s=n.Event(e,i),n(t).trigger(s),o=!s.isPropagationStopped(),r=!s.isImmediatePropagationStopped(),a=s.isDefaultPrevented());const l=P(new Event(e,{bubbles:o,cancelable:!0}),i);return a&&l.preventDefault(),r&&t.dispatchEvent(l),l.defaultPrevented&&s&&s.preventDefault(),l}};function P(t,e={}){for(const[i,n]of Object.entries(e))try{t[i]=n}catch(e){Object.defineProperty(t,i,{configurable:!0,get:()=>n})}return t}function M(t){if("true"===t)return!0;if("false"===t)return!1;if(t===Number(t).toString())return Number(t);if(""===t||"null"===t)return null;if("string"!=typeof t)return t;try{return JSON.parse(decodeURIComponent(t))}catch(e){return t}}function j(t){return t.replace(/[A-Z]/g,(t=>`-${t.toLowerCase()}`))}const F={setDataAttribute(t,e,i){t.setAttribute(`data-bs-${j(e)}`,i)},removeDataAttribute(t,e){t.removeAttribute(`data-bs-${j(e)}`)},getDataAttributes(t){if(!t)return{};const e={},i=Object.keys(t.dataset).filter((t=>t.startsWith("bs")&&!t.startsWith("bsConfig")));for(const n of i){let i=n.replace(/^bs/,"");i=i.charAt(0).toLowerCase()+i.slice(1,i.length),e[i]=M(t.dataset[n])}return e},getDataAttribute:(t,e)=>M(t.getAttribute(`data-bs-${j(e)}`))};class H{static get Default(){return{}}static get DefaultType(){return{}}static get NAME(){throw new Error('You have to implement the static method "NAME", for each component!')}_getConfig(t){return t=this._mergeConfigObj(t),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}_configAfterMerge(t){return t}_mergeConfigObj(t,e){const i=o(e)?F.getDataAttribute(e,"config"):{};return{...this.constructor.Default,..."object"==typeof i?i:{},...o(e)?F.getDataAttributes(e):{},..."object"==typeof t?t:{}}}_typeCheckConfig(t,e=this.constructor.DefaultType){for(const[n,s]of Object.entries(e)){const e=t[n],r=o(e)?"element":null==(i=e)?`${i}`:Object.prototype.toString.call(i).match(/\s([a-z]+)/i)[1].toLowerCase();if(!new RegExp(s).test(r))throw new TypeError(`${this.constructor.NAME.toUpperCase()}: Option "${n}" provided type "${r}" but expected type "${s}".`)}var i}}class W extends H{constructor(t,i){super(),(t=r(t))&&(this._element=t,this._config=this._getConfig(i),e.set(this._element,this.constructor.DATA_KEY,this))}dispose(){e.remove(this._element,this.constructor.DATA_KEY),N.off(this._element,this.constructor.EVENT_KEY);for(const t of Object.getOwnPropertyNames(this))this[t]=null}_queueCallback(t,e,i=!0){_(t,e,i)}_getConfig(t){return t=this._mergeConfigObj(t,this._element),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}static getInstance(t){return e.get(r(t),this.DATA_KEY)}static getOrCreateInstance(t,e={}){return this.getInstance(t)||new this(t,"object"==typeof e?e:null)}static get VERSION(){return"5.3.1"}static get DATA_KEY(){return`bs.${this.NAME}`}static get EVENT_KEY(){return`.${this.DATA_KEY}`}static eventName(t){return`${t}${this.EVENT_KEY}`}}const B=t=>{let e=t.getAttribute("data-bs-target");if(!e||"#"===e){let i=t.getAttribute("href");if(!i||!i.includes("#")&&!i.startsWith("."))return null;i.includes("#")&&!i.startsWith("#")&&(i=`#${i.split("#")[1]}`),e=i&&"#"!==i?i.trim():null}return n(e)},z={find:(t,e=document.documentElement)=>[].concat(...Element.prototype.querySelectorAll.call(e,t)),findOne:(t,e=document.documentElement)=>Element.prototype.querySelector.call(e,t),children:(t,e)=>[].concat(...t.children).filter((t=>t.matches(e))),parents(t,e){const i=[];let n=t.parentNode.closest(e);for(;n;)i.push(n),n=n.parentNode.closest(e);return i},prev(t,e){let i=t.previousElementSibling;for(;i;){if(i.matches(e))return[i];i=i.previousElementSibling}return[]},next(t,e){let i=t.nextElementSibling;for(;i;){if(i.matches(e))return[i];i=i.nextElementSibling}return[]},focusableChildren(t){const e=["a","button","input","textarea","select","details","[tabindex]",'[contenteditable="true"]'].map((t=>`${t}:not([tabindex^="-"])`)).join(",");return this.find(e,t).filter((t=>!l(t)&&a(t)))},getSelectorFromElement(t){const e=B(t);return e&&z.findOne(e)?e:null},getElementFromSelector(t){const e=B(t);return e?z.findOne(e):null},getMultipleElementsFromSelector(t){const e=B(t);return e?z.find(e):[]}},R=(t,e="hide")=>{const i=`click.dismiss${t.EVENT_KEY}`,n=t.NAME;N.on(document,i,`[data-bs-dismiss="${n}"]`,(function(i){if(["A","AREA"].includes(this.tagName)&&i.preventDefault(),l(this))return;const s=z.getElementFromSelector(this)||this.closest(`.${n}`);t.getOrCreateInstance(s)[e]()}))},q=".bs.alert",V=`close${q}`,K=`closed${q}`;class Q extends W{static get NAME(){return"alert"}close(){if(N.trigger(this._element,V).defaultPrevented)return;this._element.classList.remove("show");const t=this._element.classList.contains("fade");this._queueCallback((()=>this._destroyElement()),this._element,t)}_destroyElement(){this._element.remove(),N.trigger(this._element,K),this.dispose()}static jQueryInterface(t){return this.each((function(){const e=Q.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}R(Q,"close"),m(Q);const X='[data-bs-toggle="button"]';class Y extends W{static get NAME(){return"button"}toggle(){this._element.setAttribute("aria-pressed",this._element.classList.toggle("active"))}static jQueryInterface(t){return this.each((function(){const e=Y.getOrCreateInstance(this);"toggle"===t&&e[t]()}))}}N.on(document,"click.bs.button.data-api",X,(t=>{t.preventDefault();const e=t.target.closest(X);Y.getOrCreateInstance(e).toggle()})),m(Y);const U=".bs.swipe",G=`touchstart${U}`,J=`touchmove${U}`,Z=`touchend${U}`,tt=`pointerdown${U}`,et=`pointerup${U}`,it={endCallback:null,leftCallback:null,rightCallback:null},nt={endCallback:"(function|null)",leftCallback:"(function|null)",rightCallback:"(function|null)"};class st extends H{constructor(t,e){super(),this._element=t,t&&st.isSupported()&&(this._config=this._getConfig(e),this._deltaX=0,this._supportPointerEvents=Boolean(window.PointerEvent),this._initEvents())}static get Default(){return it}static get DefaultType(){return nt}static get NAME(){return"swipe"}dispose(){N.off(this._element,U)}_start(t){this._supportPointerEvents?this._eventIsPointerPenTouch(t)&&(this._deltaX=t.clientX):this._deltaX=t.touches[0].clientX}_end(t){this._eventIsPointerPenTouch(t)&&(this._deltaX=t.clientX-this._deltaX),this._handleSwipe(),g(this._config.endCallback)}_move(t){this._deltaX=t.touches&&t.touches.length>1?0:t.touches[0].clientX-this._deltaX}_handleSwipe(){const t=Math.abs(this._deltaX);if(t<=40)return;const e=t/this._deltaX;this._deltaX=0,e&&g(e>0?this._config.rightCallback:this._config.leftCallback)}_initEvents(){this._supportPointerEvents?(N.on(this._element,tt,(t=>this._start(t))),N.on(this._element,et,(t=>this._end(t))),this._element.classList.add("pointer-event")):(N.on(this._element,G,(t=>this._start(t))),N.on(this._element,J,(t=>this._move(t))),N.on(this._element,Z,(t=>this._end(t))))}_eventIsPointerPenTouch(t){return this._supportPointerEvents&&("pen"===t.pointerType||"touch"===t.pointerType)}static isSupported(){return"ontouchstart"in document.documentElement||navigator.maxTouchPoints>0}}const ot=".bs.carousel",rt=".data-api",at="next",lt="prev",ct="left",ht="right",dt=`slide${ot}`,ut=`slid${ot}`,ft=`keydown${ot}`,pt=`mouseenter${ot}`,mt=`mouseleave${ot}`,gt=`dragstart${ot}`,_t=`load${ot}${rt}`,bt=`click${ot}${rt}`,vt="carousel",yt="active",wt=".active",At=".carousel-item",Et=wt+At,Tt={ArrowLeft:ht,ArrowRight:ct},Ct={interval:5e3,keyboard:!0,pause:"hover",ride:!1,touch:!0,wrap:!0},Ot={interval:"(number|boolean)",keyboard:"boolean",pause:"(string|boolean)",ride:"(boolean|string)",touch:"boolean",wrap:"boolean"};class xt extends W{constructor(t,e){super(t,e),this._interval=null,this._activeElement=null,this._isSliding=!1,this.touchTimeout=null,this._swipeHelper=null,this._indicatorsElement=z.findOne(".carousel-indicators",this._element),this._addEventListeners(),this._config.ride===vt&&this.cycle()}static get Default(){return Ct}static get DefaultType(){return Ot}static get NAME(){return"carousel"}next(){this._slide(at)}nextWhenVisible(){!document.hidden&&a(this._element)&&this.next()}prev(){this._slide(lt)}pause(){this._isSliding&&s(this._element),this._clearInterval()}cycle(){this._clearInterval(),this._updateInterval(),this._interval=setInterval((()=>this.nextWhenVisible()),this._config.interval)}_maybeEnableCycle(){this._config.ride&&(this._isSliding?N.one(this._element,ut,(()=>this.cycle())):this.cycle())}to(t){const e=this._getItems();if(t>e.length-1||t<0)return;if(this._isSliding)return void N.one(this._element,ut,(()=>this.to(t)));const i=this._getItemIndex(this._getActive());if(i===t)return;const n=t>i?at:lt;this._slide(n,e[t])}dispose(){this._swipeHelper&&this._swipeHelper.dispose(),super.dispose()}_configAfterMerge(t){return t.defaultInterval=t.interval,t}_addEventListeners(){this._config.keyboard&&N.on(this._element,ft,(t=>this._keydown(t))),"hover"===this._config.pause&&(N.on(this._element,pt,(()=>this.pause())),N.on(this._element,mt,(()=>this._maybeEnableCycle()))),this._config.touch&&st.isSupported()&&this._addTouchEventListeners()}_addTouchEventListeners(){for(const t of z.find(".carousel-item img",this._element))N.on(t,gt,(t=>t.preventDefault()));const t={leftCallback:()=>this._slide(this._directionToOrder(ct)),rightCallback:()=>this._slide(this._directionToOrder(ht)),endCallback:()=>{"hover"===this._config.pause&&(this.pause(),this.touchTimeout&&clearTimeout(this.touchTimeout),this.touchTimeout=setTimeout((()=>this._maybeEnableCycle()),500+this._config.interval))}};this._swipeHelper=new st(this._element,t)}_keydown(t){if(/input|textarea/i.test(t.target.tagName))return;const e=Tt[t.key];e&&(t.preventDefault(),this._slide(this._directionToOrder(e)))}_getItemIndex(t){return this._getItems().indexOf(t)}_setActiveIndicatorElement(t){if(!this._indicatorsElement)return;const e=z.findOne(wt,this._indicatorsElement);e.classList.remove(yt),e.removeAttribute("aria-current");const i=z.findOne(`[data-bs-slide-to="${t}"]`,this._indicatorsElement);i&&(i.classList.add(yt),i.setAttribute("aria-current","true"))}_updateInterval(){const t=this._activeElement||this._getActive();if(!t)return;const e=Number.parseInt(t.getAttribute("data-bs-interval"),10);this._config.interval=e||this._config.defaultInterval}_slide(t,e=null){if(this._isSliding)return;const i=this._getActive(),n=t===at,s=e||b(this._getItems(),i,n,this._config.wrap);if(s===i)return;const o=this._getItemIndex(s),r=e=>N.trigger(this._element,e,{relatedTarget:s,direction:this._orderToDirection(t),from:this._getItemIndex(i),to:o});if(r(dt).defaultPrevented)return;if(!i||!s)return;const a=Boolean(this._interval);this.pause(),this._isSliding=!0,this._setActiveIndicatorElement(o),this._activeElement=s;const l=n?"carousel-item-start":"carousel-item-end",c=n?"carousel-item-next":"carousel-item-prev";s.classList.add(c),d(s),i.classList.add(l),s.classList.add(l),this._queueCallback((()=>{s.classList.remove(l,c),s.classList.add(yt),i.classList.remove(yt,c,l),this._isSliding=!1,r(ut)}),i,this._isAnimated()),a&&this.cycle()}_isAnimated(){return this._element.classList.contains("slide")}_getActive(){return z.findOne(Et,this._element)}_getItems(){return z.find(At,this._element)}_clearInterval(){this._interval&&(clearInterval(this._interval),this._interval=null)}_directionToOrder(t){return p()?t===ct?lt:at:t===ct?at:lt}_orderToDirection(t){return p()?t===lt?ct:ht:t===lt?ht:ct}static jQueryInterface(t){return this.each((function(){const e=xt.getOrCreateInstance(this,t);if("number"!=typeof t){if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}else e.to(t)}))}}N.on(document,bt,"[data-bs-slide], [data-bs-slide-to]",(function(t){const e=z.getElementFromSelector(this);if(!e||!e.classList.contains(vt))return;t.preventDefault();const i=xt.getOrCreateInstance(e),n=this.getAttribute("data-bs-slide-to");return n?(i.to(n),void i._maybeEnableCycle()):"next"===F.getDataAttribute(this,"slide")?(i.next(),void i._maybeEnableCycle()):(i.prev(),void i._maybeEnableCycle())})),N.on(window,_t,(()=>{const t=z.find('[data-bs-ride="carousel"]');for(const e of t)xt.getOrCreateInstance(e)})),m(xt);const kt=".bs.collapse",Lt=`show${kt}`,St=`shown${kt}`,Dt=`hide${kt}`,$t=`hidden${kt}`,It=`click${kt}.data-api`,Nt="show",Pt="collapse",Mt="collapsing",jt=`:scope .${Pt} .${Pt}`,Ft='[data-bs-toggle="collapse"]',Ht={parent:null,toggle:!0},Wt={parent:"(null|element)",toggle:"boolean"};class Bt extends W{constructor(t,e){super(t,e),this._isTransitioning=!1,this._triggerArray=[];const i=z.find(Ft);for(const t of i){const e=z.getSelectorFromElement(t),i=z.find(e).filter((t=>t===this._element));null!==e&&i.length&&this._triggerArray.push(t)}this._initializeChildren(),this._config.parent||this._addAriaAndCollapsedClass(this._triggerArray,this._isShown()),this._config.toggle&&this.toggle()}static get Default(){return Ht}static get DefaultType(){return Wt}static get NAME(){return"collapse"}toggle(){this._isShown()?this.hide():this.show()}show(){if(this._isTransitioning||this._isShown())return;let t=[];if(this._config.parent&&(t=this._getFirstLevelChildren(".collapse.show, .collapse.collapsing").filter((t=>t!==this._element)).map((t=>Bt.getOrCreateInstance(t,{toggle:!1})))),t.length&&t[0]._isTransitioning)return;if(N.trigger(this._element,Lt).defaultPrevented)return;for(const e of t)e.hide();const e=this._getDimension();this._element.classList.remove(Pt),this._element.classList.add(Mt),this._element.style[e]=0,this._addAriaAndCollapsedClass(this._triggerArray,!0),this._isTransitioning=!0;const i=`scroll${e[0].toUpperCase()+e.slice(1)}`;this._queueCallback((()=>{this._isTransitioning=!1,this._element.classList.remove(Mt),this._element.classList.add(Pt,Nt),this._element.style[e]="",N.trigger(this._element,St)}),this._element,!0),this._element.style[e]=`${this._element[i]}px`}hide(){if(this._isTransitioning||!this._isShown())return;if(N.trigger(this._element,Dt).defaultPrevented)return;const t=this._getDimension();this._element.style[t]=`${this._element.getBoundingClientRect()[t]}px`,d(this._element),this._element.classList.add(Mt),this._element.classList.remove(Pt,Nt);for(const t of this._triggerArray){const e=z.getElementFromSelector(t);e&&!this._isShown(e)&&this._addAriaAndCollapsedClass([t],!1)}this._isTransitioning=!0,this._element.style[t]="",this._queueCallback((()=>{this._isTransitioning=!1,this._element.classList.remove(Mt),this._element.classList.add(Pt),N.trigger(this._element,$t)}),this._element,!0)}_isShown(t=this._element){return t.classList.contains(Nt)}_configAfterMerge(t){return t.toggle=Boolean(t.toggle),t.parent=r(t.parent),t}_getDimension(){return this._element.classList.contains("collapse-horizontal")?"width":"height"}_initializeChildren(){if(!this._config.parent)return;const t=this._getFirstLevelChildren(Ft);for(const e of t){const t=z.getElementFromSelector(e);t&&this._addAriaAndCollapsedClass([e],this._isShown(t))}}_getFirstLevelChildren(t){const e=z.find(jt,this._config.parent);return z.find(t,this._config.parent).filter((t=>!e.includes(t)))}_addAriaAndCollapsedClass(t,e){if(t.length)for(const i of t)i.classList.toggle("collapsed",!e),i.setAttribute("aria-expanded",e)}static jQueryInterface(t){const e={};return"string"==typeof t&&/show|hide/.test(t)&&(e.toggle=!1),this.each((function(){const i=Bt.getOrCreateInstance(this,e);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t]()}}))}}N.on(document,It,Ft,(function(t){("A"===t.target.tagName||t.delegateTarget&&"A"===t.delegateTarget.tagName)&&t.preventDefault();for(const t of z.getMultipleElementsFromSelector(this))Bt.getOrCreateInstance(t,{toggle:!1}).toggle()})),m(Bt);var zt="top",Rt="bottom",qt="right",Vt="left",Kt="auto",Qt=[zt,Rt,qt,Vt],Xt="start",Yt="end",Ut="clippingParents",Gt="viewport",Jt="popper",Zt="reference",te=Qt.reduce((function(t,e){return t.concat([e+"-"+Xt,e+"-"+Yt])}),[]),ee=[].concat(Qt,[Kt]).reduce((function(t,e){return t.concat([e,e+"-"+Xt,e+"-"+Yt])}),[]),ie="beforeRead",ne="read",se="afterRead",oe="beforeMain",re="main",ae="afterMain",le="beforeWrite",ce="write",he="afterWrite",de=[ie,ne,se,oe,re,ae,le,ce,he];function ue(t){return t?(t.nodeName||"").toLowerCase():null}function fe(t){if(null==t)return window;if("[object Window]"!==t.toString()){var e=t.ownerDocument;return e&&e.defaultView||window}return t}function pe(t){return t instanceof fe(t).Element||t instanceof Element}function me(t){return t instanceof fe(t).HTMLElement||t instanceof HTMLElement}function ge(t){return"undefined"!=typeof ShadowRoot&&(t instanceof fe(t).ShadowRoot||t instanceof ShadowRoot)}const _e={name:"applyStyles",enabled:!0,phase:"write",fn:function(t){var e=t.state;Object.keys(e.elements).forEach((function(t){var i=e.styles[t]||{},n=e.attributes[t]||{},s=e.elements[t];me(s)&&ue(s)&&(Object.assign(s.style,i),Object.keys(n).forEach((function(t){var e=n[t];!1===e?s.removeAttribute(t):s.setAttribute(t,!0===e?"":e)})))}))},effect:function(t){var e=t.state,i={popper:{position:e.options.strategy,left:"0",top:"0",margin:"0"},arrow:{position:"absolute"},reference:{}};return Object.assign(e.elements.popper.style,i.popper),e.styles=i,e.elements.arrow&&Object.assign(e.elements.arrow.style,i.arrow),function(){Object.keys(e.elements).forEach((function(t){var n=e.elements[t],s=e.attributes[t]||{},o=Object.keys(e.styles.hasOwnProperty(t)?e.styles[t]:i[t]).reduce((function(t,e){return t[e]="",t}),{});me(n)&&ue(n)&&(Object.assign(n.style,o),Object.keys(s).forEach((function(t){n.removeAttribute(t)})))}))}},requires:["computeStyles"]};function be(t){return t.split("-")[0]}var ve=Math.max,ye=Math.min,we=Math.round;function Ae(){var t=navigator.userAgentData;return null!=t&&t.brands&&Array.isArray(t.brands)?t.brands.map((function(t){return t.brand+"/"+t.version})).join(" "):navigator.userAgent}function Ee(){return!/^((?!chrome|android).)*safari/i.test(Ae())}function Te(t,e,i){void 0===e&&(e=!1),void 0===i&&(i=!1);var n=t.getBoundingClientRect(),s=1,o=1;e&&me(t)&&(s=t.offsetWidth>0&&we(n.width)/t.offsetWidth||1,o=t.offsetHeight>0&&we(n.height)/t.offsetHeight||1);var r=(pe(t)?fe(t):window).visualViewport,a=!Ee()&&i,l=(n.left+(a&&r?r.offsetLeft:0))/s,c=(n.top+(a&&r?r.offsetTop:0))/o,h=n.width/s,d=n.height/o;return{width:h,height:d,top:c,right:l+h,bottom:c+d,left:l,x:l,y:c}}function Ce(t){var e=Te(t),i=t.offsetWidth,n=t.offsetHeight;return Math.abs(e.width-i)<=1&&(i=e.width),Math.abs(e.height-n)<=1&&(n=e.height),{x:t.offsetLeft,y:t.offsetTop,width:i,height:n}}function Oe(t,e){var i=e.getRootNode&&e.getRootNode();if(t.contains(e))return!0;if(i&&ge(i)){var n=e;do{if(n&&t.isSameNode(n))return!0;n=n.parentNode||n.host}while(n)}return!1}function xe(t){return fe(t).getComputedStyle(t)}function ke(t){return["table","td","th"].indexOf(ue(t))>=0}function Le(t){return((pe(t)?t.ownerDocument:t.document)||window.document).documentElement}function Se(t){return"html"===ue(t)?t:t.assignedSlot||t.parentNode||(ge(t)?t.host:null)||Le(t)}function De(t){return me(t)&&"fixed"!==xe(t).position?t.offsetParent:null}function $e(t){for(var e=fe(t),i=De(t);i&&ke(i)&&"static"===xe(i).position;)i=De(i);return i&&("html"===ue(i)||"body"===ue(i)&&"static"===xe(i).position)?e:i||function(t){var e=/firefox/i.test(Ae());if(/Trident/i.test(Ae())&&me(t)&&"fixed"===xe(t).position)return null;var i=Se(t);for(ge(i)&&(i=i.host);me(i)&&["html","body"].indexOf(ue(i))<0;){var n=xe(i);if("none"!==n.transform||"none"!==n.perspective||"paint"===n.contain||-1!==["transform","perspective"].indexOf(n.willChange)||e&&"filter"===n.willChange||e&&n.filter&&"none"!==n.filter)return i;i=i.parentNode}return null}(t)||e}function Ie(t){return["top","bottom"].indexOf(t)>=0?"x":"y"}function Ne(t,e,i){return ve(t,ye(e,i))}function Pe(t){return Object.assign({},{top:0,right:0,bottom:0,left:0},t)}function Me(t,e){return e.reduce((function(e,i){return e[i]=t,e}),{})}const je={name:"arrow",enabled:!0,phase:"main",fn:function(t){var e,i=t.state,n=t.name,s=t.options,o=i.elements.arrow,r=i.modifiersData.popperOffsets,a=be(i.placement),l=Ie(a),c=[Vt,qt].indexOf(a)>=0?"height":"width";if(o&&r){var h=function(t,e){return Pe("number"!=typeof(t="function"==typeof t?t(Object.assign({},e.rects,{placement:e.placement})):t)?t:Me(t,Qt))}(s.padding,i),d=Ce(o),u="y"===l?zt:Vt,f="y"===l?Rt:qt,p=i.rects.reference[c]+i.rects.reference[l]-r[l]-i.rects.popper[c],m=r[l]-i.rects.reference[l],g=$e(o),_=g?"y"===l?g.clientHeight||0:g.clientWidth||0:0,b=p/2-m/2,v=h[u],y=_-d[c]-h[f],w=_/2-d[c]/2+b,A=Ne(v,w,y),E=l;i.modifiersData[n]=((e={})[E]=A,e.centerOffset=A-w,e)}},effect:function(t){var e=t.state,i=t.options.element,n=void 0===i?"[data-popper-arrow]":i;null!=n&&("string"!=typeof n||(n=e.elements.popper.querySelector(n)))&&Oe(e.elements.popper,n)&&(e.elements.arrow=n)},requires:["popperOffsets"],requiresIfExists:["preventOverflow"]};function Fe(t){return t.split("-")[1]}var He={top:"auto",right:"auto",bottom:"auto",left:"auto"};function We(t){var e,i=t.popper,n=t.popperRect,s=t.placement,o=t.variation,r=t.offsets,a=t.position,l=t.gpuAcceleration,c=t.adaptive,h=t.roundOffsets,d=t.isFixed,u=r.x,f=void 0===u?0:u,p=r.y,m=void 0===p?0:p,g="function"==typeof h?h({x:f,y:m}):{x:f,y:m};f=g.x,m=g.y;var _=r.hasOwnProperty("x"),b=r.hasOwnProperty("y"),v=Vt,y=zt,w=window;if(c){var A=$e(i),E="clientHeight",T="clientWidth";A===fe(i)&&"static"!==xe(A=Le(i)).position&&"absolute"===a&&(E="scrollHeight",T="scrollWidth"),(s===zt||(s===Vt||s===qt)&&o===Yt)&&(y=Rt,m-=(d&&A===w&&w.visualViewport?w.visualViewport.height:A[E])-n.height,m*=l?1:-1),s!==Vt&&(s!==zt&&s!==Rt||o!==Yt)||(v=qt,f-=(d&&A===w&&w.visualViewport?w.visualViewport.width:A[T])-n.width,f*=l?1:-1)}var C,O=Object.assign({position:a},c&&He),x=!0===h?function(t,e){var i=t.x,n=t.y,s=e.devicePixelRatio||1;return{x:we(i*s)/s||0,y:we(n*s)/s||0}}({x:f,y:m},fe(i)):{x:f,y:m};return f=x.x,m=x.y,l?Object.assign({},O,((C={})[y]=b?"0":"",C[v]=_?"0":"",C.transform=(w.devicePixelRatio||1)<=1?"translate("+f+"px, "+m+"px)":"translate3d("+f+"px, "+m+"px, 0)",C)):Object.assign({},O,((e={})[y]=b?m+"px":"",e[v]=_?f+"px":"",e.transform="",e))}const Be={name:"computeStyles",enabled:!0,phase:"beforeWrite",fn:function(t){var e=t.state,i=t.options,n=i.gpuAcceleration,s=void 0===n||n,o=i.adaptive,r=void 0===o||o,a=i.roundOffsets,l=void 0===a||a,c={placement:be(e.placement),variation:Fe(e.placement),popper:e.elements.popper,popperRect:e.rects.popper,gpuAcceleration:s,isFixed:"fixed"===e.options.strategy};null!=e.modifiersData.popperOffsets&&(e.styles.popper=Object.assign({},e.styles.popper,We(Object.assign({},c,{offsets:e.modifiersData.popperOffsets,position:e.options.strategy,adaptive:r,roundOffsets:l})))),null!=e.modifiersData.arrow&&(e.styles.arrow=Object.assign({},e.styles.arrow,We(Object.assign({},c,{offsets:e.modifiersData.arrow,position:"absolute",adaptive:!1,roundOffsets:l})))),e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-placement":e.placement})},data:{}};var ze={passive:!0};const Re={name:"eventListeners",enabled:!0,phase:"write",fn:function(){},effect:function(t){var e=t.state,i=t.instance,n=t.options,s=n.scroll,o=void 0===s||s,r=n.resize,a=void 0===r||r,l=fe(e.elements.popper),c=[].concat(e.scrollParents.reference,e.scrollParents.popper);return o&&c.forEach((function(t){t.addEventListener("scroll",i.update,ze)})),a&&l.addEventListener("resize",i.update,ze),function(){o&&c.forEach((function(t){t.removeEventListener("scroll",i.update,ze)})),a&&l.removeEventListener("resize",i.update,ze)}},data:{}};var qe={left:"right",right:"left",bottom:"top",top:"bottom"};function Ve(t){return t.replace(/left|right|bottom|top/g,(function(t){return qe[t]}))}var Ke={start:"end",end:"start"};function Qe(t){return t.replace(/start|end/g,(function(t){return Ke[t]}))}function Xe(t){var e=fe(t);return{scrollLeft:e.pageXOffset,scrollTop:e.pageYOffset}}function Ye(t){return Te(Le(t)).left+Xe(t).scrollLeft}function Ue(t){var e=xe(t),i=e.overflow,n=e.overflowX,s=e.overflowY;return/auto|scroll|overlay|hidden/.test(i+s+n)}function Ge(t){return["html","body","#document"].indexOf(ue(t))>=0?t.ownerDocument.body:me(t)&&Ue(t)?t:Ge(Se(t))}function Je(t,e){var i;void 0===e&&(e=[]);var n=Ge(t),s=n===(null==(i=t.ownerDocument)?void 0:i.body),o=fe(n),r=s?[o].concat(o.visualViewport||[],Ue(n)?n:[]):n,a=e.concat(r);return s?a:a.concat(Je(Se(r)))}function Ze(t){return Object.assign({},t,{left:t.x,top:t.y,right:t.x+t.width,bottom:t.y+t.height})}function ti(t,e,i){return e===Gt?Ze(function(t,e){var i=fe(t),n=Le(t),s=i.visualViewport,o=n.clientWidth,r=n.clientHeight,a=0,l=0;if(s){o=s.width,r=s.height;var c=Ee();(c||!c&&"fixed"===e)&&(a=s.offsetLeft,l=s.offsetTop)}return{width:o,height:r,x:a+Ye(t),y:l}}(t,i)):pe(e)?function(t,e){var i=Te(t,!1,"fixed"===e);return i.top=i.top+t.clientTop,i.left=i.left+t.clientLeft,i.bottom=i.top+t.clientHeight,i.right=i.left+t.clientWidth,i.width=t.clientWidth,i.height=t.clientHeight,i.x=i.left,i.y=i.top,i}(e,i):Ze(function(t){var e,i=Le(t),n=Xe(t),s=null==(e=t.ownerDocument)?void 0:e.body,o=ve(i.scrollWidth,i.clientWidth,s?s.scrollWidth:0,s?s.clientWidth:0),r=ve(i.scrollHeight,i.clientHeight,s?s.scrollHeight:0,s?s.clientHeight:0),a=-n.scrollLeft+Ye(t),l=-n.scrollTop;return"rtl"===xe(s||i).direction&&(a+=ve(i.clientWidth,s?s.clientWidth:0)-o),{width:o,height:r,x:a,y:l}}(Le(t)))}function ei(t){var e,i=t.reference,n=t.element,s=t.placement,o=s?be(s):null,r=s?Fe(s):null,a=i.x+i.width/2-n.width/2,l=i.y+i.height/2-n.height/2;switch(o){case zt:e={x:a,y:i.y-n.height};break;case Rt:e={x:a,y:i.y+i.height};break;case qt:e={x:i.x+i.width,y:l};break;case Vt:e={x:i.x-n.width,y:l};break;default:e={x:i.x,y:i.y}}var c=o?Ie(o):null;if(null!=c){var h="y"===c?"height":"width";switch(r){case Xt:e[c]=e[c]-(i[h]/2-n[h]/2);break;case Yt:e[c]=e[c]+(i[h]/2-n[h]/2)}}return e}function ii(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=void 0===n?t.placement:n,o=i.strategy,r=void 0===o?t.strategy:o,a=i.boundary,l=void 0===a?Ut:a,c=i.rootBoundary,h=void 0===c?Gt:c,d=i.elementContext,u=void 0===d?Jt:d,f=i.altBoundary,p=void 0!==f&&f,m=i.padding,g=void 0===m?0:m,_=Pe("number"!=typeof g?g:Me(g,Qt)),b=u===Jt?Zt:Jt,v=t.rects.popper,y=t.elements[p?b:u],w=function(t,e,i,n){var s="clippingParents"===e?function(t){var e=Je(Se(t)),i=["absolute","fixed"].indexOf(xe(t).position)>=0&&me(t)?$e(t):t;return pe(i)?e.filter((function(t){return pe(t)&&Oe(t,i)&&"body"!==ue(t)})):[]}(t):[].concat(e),o=[].concat(s,[i]),r=o[0],a=o.reduce((function(e,i){var s=ti(t,i,n);return e.top=ve(s.top,e.top),e.right=ye(s.right,e.right),e.bottom=ye(s.bottom,e.bottom),e.left=ve(s.left,e.left),e}),ti(t,r,n));return a.width=a.right-a.left,a.height=a.bottom-a.top,a.x=a.left,a.y=a.top,a}(pe(y)?y:y.contextElement||Le(t.elements.popper),l,h,r),A=Te(t.elements.reference),E=ei({reference:A,element:v,strategy:"absolute",placement:s}),T=Ze(Object.assign({},v,E)),C=u===Jt?T:A,O={top:w.top-C.top+_.top,bottom:C.bottom-w.bottom+_.bottom,left:w.left-C.left+_.left,right:C.right-w.right+_.right},x=t.modifiersData.offset;if(u===Jt&&x){var k=x[s];Object.keys(O).forEach((function(t){var e=[qt,Rt].indexOf(t)>=0?1:-1,i=[zt,Rt].indexOf(t)>=0?"y":"x";O[t]+=k[i]*e}))}return O}function ni(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=i.boundary,o=i.rootBoundary,r=i.padding,a=i.flipVariations,l=i.allowedAutoPlacements,c=void 0===l?ee:l,h=Fe(n),d=h?a?te:te.filter((function(t){return Fe(t)===h})):Qt,u=d.filter((function(t){return c.indexOf(t)>=0}));0===u.length&&(u=d);var f=u.reduce((function(e,i){return e[i]=ii(t,{placement:i,boundary:s,rootBoundary:o,padding:r})[be(i)],e}),{});return Object.keys(f).sort((function(t,e){return f[t]-f[e]}))}const si={name:"flip",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,n=t.name;if(!e.modifiersData[n]._skip){for(var s=i.mainAxis,o=void 0===s||s,r=i.altAxis,a=void 0===r||r,l=i.fallbackPlacements,c=i.padding,h=i.boundary,d=i.rootBoundary,u=i.altBoundary,f=i.flipVariations,p=void 0===f||f,m=i.allowedAutoPlacements,g=e.options.placement,_=be(g),b=l||(_!==g&&p?function(t){if(be(t)===Kt)return[];var e=Ve(t);return[Qe(t),e,Qe(e)]}(g):[Ve(g)]),v=[g].concat(b).reduce((function(t,i){return t.concat(be(i)===Kt?ni(e,{placement:i,boundary:h,rootBoundary:d,padding:c,flipVariations:p,allowedAutoPlacements:m}):i)}),[]),y=e.rects.reference,w=e.rects.popper,A=new Map,E=!0,T=v[0],C=0;C=0,S=L?"width":"height",D=ii(e,{placement:O,boundary:h,rootBoundary:d,altBoundary:u,padding:c}),$=L?k?qt:Vt:k?Rt:zt;y[S]>w[S]&&($=Ve($));var I=Ve($),N=[];if(o&&N.push(D[x]<=0),a&&N.push(D[$]<=0,D[I]<=0),N.every((function(t){return t}))){T=O,E=!1;break}A.set(O,N)}if(E)for(var P=function(t){var e=v.find((function(e){var i=A.get(e);if(i)return i.slice(0,t).every((function(t){return t}))}));if(e)return T=e,"break"},M=p?3:1;M>0&&"break"!==P(M);M--);e.placement!==T&&(e.modifiersData[n]._skip=!0,e.placement=T,e.reset=!0)}},requiresIfExists:["offset"],data:{_skip:!1}};function oi(t,e,i){return void 0===i&&(i={x:0,y:0}),{top:t.top-e.height-i.y,right:t.right-e.width+i.x,bottom:t.bottom-e.height+i.y,left:t.left-e.width-i.x}}function ri(t){return[zt,qt,Rt,Vt].some((function(e){return t[e]>=0}))}const ai={name:"hide",enabled:!0,phase:"main",requiresIfExists:["preventOverflow"],fn:function(t){var e=t.state,i=t.name,n=e.rects.reference,s=e.rects.popper,o=e.modifiersData.preventOverflow,r=ii(e,{elementContext:"reference"}),a=ii(e,{altBoundary:!0}),l=oi(r,n),c=oi(a,s,o),h=ri(l),d=ri(c);e.modifiersData[i]={referenceClippingOffsets:l,popperEscapeOffsets:c,isReferenceHidden:h,hasPopperEscaped:d},e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-reference-hidden":h,"data-popper-escaped":d})}},li={name:"offset",enabled:!0,phase:"main",requires:["popperOffsets"],fn:function(t){var e=t.state,i=t.options,n=t.name,s=i.offset,o=void 0===s?[0,0]:s,r=ee.reduce((function(t,i){return t[i]=function(t,e,i){var n=be(t),s=[Vt,zt].indexOf(n)>=0?-1:1,o="function"==typeof i?i(Object.assign({},e,{placement:t})):i,r=o[0],a=o[1];return r=r||0,a=(a||0)*s,[Vt,qt].indexOf(n)>=0?{x:a,y:r}:{x:r,y:a}}(i,e.rects,o),t}),{}),a=r[e.placement],l=a.x,c=a.y;null!=e.modifiersData.popperOffsets&&(e.modifiersData.popperOffsets.x+=l,e.modifiersData.popperOffsets.y+=c),e.modifiersData[n]=r}},ci={name:"popperOffsets",enabled:!0,phase:"read",fn:function(t){var e=t.state,i=t.name;e.modifiersData[i]=ei({reference:e.rects.reference,element:e.rects.popper,strategy:"absolute",placement:e.placement})},data:{}},hi={name:"preventOverflow",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,n=t.name,s=i.mainAxis,o=void 0===s||s,r=i.altAxis,a=void 0!==r&&r,l=i.boundary,c=i.rootBoundary,h=i.altBoundary,d=i.padding,u=i.tether,f=void 0===u||u,p=i.tetherOffset,m=void 0===p?0:p,g=ii(e,{boundary:l,rootBoundary:c,padding:d,altBoundary:h}),_=be(e.placement),b=Fe(e.placement),v=!b,y=Ie(_),w="x"===y?"y":"x",A=e.modifiersData.popperOffsets,E=e.rects.reference,T=e.rects.popper,C="function"==typeof m?m(Object.assign({},e.rects,{placement:e.placement})):m,O="number"==typeof C?{mainAxis:C,altAxis:C}:Object.assign({mainAxis:0,altAxis:0},C),x=e.modifiersData.offset?e.modifiersData.offset[e.placement]:null,k={x:0,y:0};if(A){if(o){var L,S="y"===y?zt:Vt,D="y"===y?Rt:qt,$="y"===y?"height":"width",I=A[y],N=I+g[S],P=I-g[D],M=f?-T[$]/2:0,j=b===Xt?E[$]:T[$],F=b===Xt?-T[$]:-E[$],H=e.elements.arrow,W=f&&H?Ce(H):{width:0,height:0},B=e.modifiersData["arrow#persistent"]?e.modifiersData["arrow#persistent"].padding:{top:0,right:0,bottom:0,left:0},z=B[S],R=B[D],q=Ne(0,E[$],W[$]),V=v?E[$]/2-M-q-z-O.mainAxis:j-q-z-O.mainAxis,K=v?-E[$]/2+M+q+R+O.mainAxis:F+q+R+O.mainAxis,Q=e.elements.arrow&&$e(e.elements.arrow),X=Q?"y"===y?Q.clientTop||0:Q.clientLeft||0:0,Y=null!=(L=null==x?void 0:x[y])?L:0,U=I+K-Y,G=Ne(f?ye(N,I+V-Y-X):N,I,f?ve(P,U):P);A[y]=G,k[y]=G-I}if(a){var J,Z="x"===y?zt:Vt,tt="x"===y?Rt:qt,et=A[w],it="y"===w?"height":"width",nt=et+g[Z],st=et-g[tt],ot=-1!==[zt,Vt].indexOf(_),rt=null!=(J=null==x?void 0:x[w])?J:0,at=ot?nt:et-E[it]-T[it]-rt+O.altAxis,lt=ot?et+E[it]+T[it]-rt-O.altAxis:st,ct=f&&ot?function(t,e,i){var n=Ne(t,e,i);return n>i?i:n}(at,et,lt):Ne(f?at:nt,et,f?lt:st);A[w]=ct,k[w]=ct-et}e.modifiersData[n]=k}},requiresIfExists:["offset"]};function di(t,e,i){void 0===i&&(i=!1);var n,s,o=me(e),r=me(e)&&function(t){var e=t.getBoundingClientRect(),i=we(e.width)/t.offsetWidth||1,n=we(e.height)/t.offsetHeight||1;return 1!==i||1!==n}(e),a=Le(e),l=Te(t,r,i),c={scrollLeft:0,scrollTop:0},h={x:0,y:0};return(o||!o&&!i)&&(("body"!==ue(e)||Ue(a))&&(c=(n=e)!==fe(n)&&me(n)?{scrollLeft:(s=n).scrollLeft,scrollTop:s.scrollTop}:Xe(n)),me(e)?((h=Te(e,!0)).x+=e.clientLeft,h.y+=e.clientTop):a&&(h.x=Ye(a))),{x:l.left+c.scrollLeft-h.x,y:l.top+c.scrollTop-h.y,width:l.width,height:l.height}}function ui(t){var e=new Map,i=new Set,n=[];function s(t){i.add(t.name),[].concat(t.requires||[],t.requiresIfExists||[]).forEach((function(t){if(!i.has(t)){var n=e.get(t);n&&s(n)}})),n.push(t)}return t.forEach((function(t){e.set(t.name,t)})),t.forEach((function(t){i.has(t.name)||s(t)})),n}var fi={placement:"bottom",modifiers:[],strategy:"absolute"};function pi(){for(var t=arguments.length,e=new Array(t),i=0;iNumber.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_getPopperConfig(){const t={placement:this._getPlacement(),modifiers:[{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"offset",options:{offset:this._getOffset()}}]};return(this._inNavbar||"static"===this._config.display)&&(F.setDataAttribute(this._menu,"popper","static"),t.modifiers=[{name:"applyStyles",enabled:!1}]),{...t,...g(this._config.popperConfig,[t])}}_selectMenuItem({key:t,target:e}){const i=z.find(".dropdown-menu .dropdown-item:not(.disabled):not(:disabled)",this._menu).filter((t=>a(t)));i.length&&b(i,e,t===Ti,!i.includes(e)).focus()}static jQueryInterface(t){return this.each((function(){const e=qi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}static clearMenus(t){if(2===t.button||"keyup"===t.type&&"Tab"!==t.key)return;const e=z.find(Ni);for(const i of e){const e=qi.getInstance(i);if(!e||!1===e._config.autoClose)continue;const n=t.composedPath(),s=n.includes(e._menu);if(n.includes(e._element)||"inside"===e._config.autoClose&&!s||"outside"===e._config.autoClose&&s)continue;if(e._menu.contains(t.target)&&("keyup"===t.type&&"Tab"===t.key||/input|select|option|textarea|form/i.test(t.target.tagName)))continue;const o={relatedTarget:e._element};"click"===t.type&&(o.clickEvent=t),e._completeHide(o)}}static dataApiKeydownHandler(t){const e=/input|textarea/i.test(t.target.tagName),i="Escape"===t.key,n=[Ei,Ti].includes(t.key);if(!n&&!i)return;if(e&&!i)return;t.preventDefault();const s=this.matches(Ii)?this:z.prev(this,Ii)[0]||z.next(this,Ii)[0]||z.findOne(Ii,t.delegateTarget.parentNode),o=qi.getOrCreateInstance(s);if(n)return t.stopPropagation(),o.show(),void o._selectMenuItem(t);o._isShown()&&(t.stopPropagation(),o.hide(),s.focus())}}N.on(document,Si,Ii,qi.dataApiKeydownHandler),N.on(document,Si,Pi,qi.dataApiKeydownHandler),N.on(document,Li,qi.clearMenus),N.on(document,Di,qi.clearMenus),N.on(document,Li,Ii,(function(t){t.preventDefault(),qi.getOrCreateInstance(this).toggle()})),m(qi);const Vi="backdrop",Ki="show",Qi=`mousedown.bs.${Vi}`,Xi={className:"modal-backdrop",clickCallback:null,isAnimated:!1,isVisible:!0,rootElement:"body"},Yi={className:"string",clickCallback:"(function|null)",isAnimated:"boolean",isVisible:"boolean",rootElement:"(element|string)"};class Ui extends H{constructor(t){super(),this._config=this._getConfig(t),this._isAppended=!1,this._element=null}static get Default(){return Xi}static get DefaultType(){return Yi}static get NAME(){return Vi}show(t){if(!this._config.isVisible)return void g(t);this._append();const e=this._getElement();this._config.isAnimated&&d(e),e.classList.add(Ki),this._emulateAnimation((()=>{g(t)}))}hide(t){this._config.isVisible?(this._getElement().classList.remove(Ki),this._emulateAnimation((()=>{this.dispose(),g(t)}))):g(t)}dispose(){this._isAppended&&(N.off(this._element,Qi),this._element.remove(),this._isAppended=!1)}_getElement(){if(!this._element){const t=document.createElement("div");t.className=this._config.className,this._config.isAnimated&&t.classList.add("fade"),this._element=t}return this._element}_configAfterMerge(t){return t.rootElement=r(t.rootElement),t}_append(){if(this._isAppended)return;const t=this._getElement();this._config.rootElement.append(t),N.on(t,Qi,(()=>{g(this._config.clickCallback)})),this._isAppended=!0}_emulateAnimation(t){_(t,this._getElement(),this._config.isAnimated)}}const Gi=".bs.focustrap",Ji=`focusin${Gi}`,Zi=`keydown.tab${Gi}`,tn="backward",en={autofocus:!0,trapElement:null},nn={autofocus:"boolean",trapElement:"element"};class sn extends H{constructor(t){super(),this._config=this._getConfig(t),this._isActive=!1,this._lastTabNavDirection=null}static get Default(){return en}static get DefaultType(){return nn}static get NAME(){return"focustrap"}activate(){this._isActive||(this._config.autofocus&&this._config.trapElement.focus(),N.off(document,Gi),N.on(document,Ji,(t=>this._handleFocusin(t))),N.on(document,Zi,(t=>this._handleKeydown(t))),this._isActive=!0)}deactivate(){this._isActive&&(this._isActive=!1,N.off(document,Gi))}_handleFocusin(t){const{trapElement:e}=this._config;if(t.target===document||t.target===e||e.contains(t.target))return;const i=z.focusableChildren(e);0===i.length?e.focus():this._lastTabNavDirection===tn?i[i.length-1].focus():i[0].focus()}_handleKeydown(t){"Tab"===t.key&&(this._lastTabNavDirection=t.shiftKey?tn:"forward")}}const on=".fixed-top, .fixed-bottom, .is-fixed, .sticky-top",rn=".sticky-top",an="padding-right",ln="margin-right";class cn{constructor(){this._element=document.body}getWidth(){const t=document.documentElement.clientWidth;return Math.abs(window.innerWidth-t)}hide(){const t=this.getWidth();this._disableOverFlow(),this._setElementAttributes(this._element,an,(e=>e+t)),this._setElementAttributes(on,an,(e=>e+t)),this._setElementAttributes(rn,ln,(e=>e-t))}reset(){this._resetElementAttributes(this._element,"overflow"),this._resetElementAttributes(this._element,an),this._resetElementAttributes(on,an),this._resetElementAttributes(rn,ln)}isOverflowing(){return this.getWidth()>0}_disableOverFlow(){this._saveInitialAttribute(this._element,"overflow"),this._element.style.overflow="hidden"}_setElementAttributes(t,e,i){const n=this.getWidth();this._applyManipulationCallback(t,(t=>{if(t!==this._element&&window.innerWidth>t.clientWidth+n)return;this._saveInitialAttribute(t,e);const s=window.getComputedStyle(t).getPropertyValue(e);t.style.setProperty(e,`${i(Number.parseFloat(s))}px`)}))}_saveInitialAttribute(t,e){const i=t.style.getPropertyValue(e);i&&F.setDataAttribute(t,e,i)}_resetElementAttributes(t,e){this._applyManipulationCallback(t,(t=>{const i=F.getDataAttribute(t,e);null!==i?(F.removeDataAttribute(t,e),t.style.setProperty(e,i)):t.style.removeProperty(e)}))}_applyManipulationCallback(t,e){if(o(t))e(t);else for(const i of z.find(t,this._element))e(i)}}const hn=".bs.modal",dn=`hide${hn}`,un=`hidePrevented${hn}`,fn=`hidden${hn}`,pn=`show${hn}`,mn=`shown${hn}`,gn=`resize${hn}`,_n=`click.dismiss${hn}`,bn=`mousedown.dismiss${hn}`,vn=`keydown.dismiss${hn}`,yn=`click${hn}.data-api`,wn="modal-open",An="show",En="modal-static",Tn={backdrop:!0,focus:!0,keyboard:!0},Cn={backdrop:"(boolean|string)",focus:"boolean",keyboard:"boolean"};class On extends W{constructor(t,e){super(t,e),this._dialog=z.findOne(".modal-dialog",this._element),this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._isShown=!1,this._isTransitioning=!1,this._scrollBar=new cn,this._addEventListeners()}static get Default(){return Tn}static get DefaultType(){return Cn}static get NAME(){return"modal"}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||this._isTransitioning||N.trigger(this._element,pn,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._isTransitioning=!0,this._scrollBar.hide(),document.body.classList.add(wn),this._adjustDialog(),this._backdrop.show((()=>this._showElement(t))))}hide(){this._isShown&&!this._isTransitioning&&(N.trigger(this._element,dn).defaultPrevented||(this._isShown=!1,this._isTransitioning=!0,this._focustrap.deactivate(),this._element.classList.remove(An),this._queueCallback((()=>this._hideModal()),this._element,this._isAnimated())))}dispose(){N.off(window,hn),N.off(this._dialog,hn),this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}handleUpdate(){this._adjustDialog()}_initializeBackDrop(){return new Ui({isVisible:Boolean(this._config.backdrop),isAnimated:this._isAnimated()})}_initializeFocusTrap(){return new sn({trapElement:this._element})}_showElement(t){document.body.contains(this._element)||document.body.append(this._element),this._element.style.display="block",this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.scrollTop=0;const e=z.findOne(".modal-body",this._dialog);e&&(e.scrollTop=0),d(this._element),this._element.classList.add(An),this._queueCallback((()=>{this._config.focus&&this._focustrap.activate(),this._isTransitioning=!1,N.trigger(this._element,mn,{relatedTarget:t})}),this._dialog,this._isAnimated())}_addEventListeners(){N.on(this._element,vn,(t=>{"Escape"===t.key&&(this._config.keyboard?this.hide():this._triggerBackdropTransition())})),N.on(window,gn,(()=>{this._isShown&&!this._isTransitioning&&this._adjustDialog()})),N.on(this._element,bn,(t=>{N.one(this._element,_n,(e=>{this._element===t.target&&this._element===e.target&&("static"!==this._config.backdrop?this._config.backdrop&&this.hide():this._triggerBackdropTransition())}))}))}_hideModal(){this._element.style.display="none",this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._isTransitioning=!1,this._backdrop.hide((()=>{document.body.classList.remove(wn),this._resetAdjustments(),this._scrollBar.reset(),N.trigger(this._element,fn)}))}_isAnimated(){return this._element.classList.contains("fade")}_triggerBackdropTransition(){if(N.trigger(this._element,un).defaultPrevented)return;const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._element.style.overflowY;"hidden"===e||this._element.classList.contains(En)||(t||(this._element.style.overflowY="hidden"),this._element.classList.add(En),this._queueCallback((()=>{this._element.classList.remove(En),this._queueCallback((()=>{this._element.style.overflowY=e}),this._dialog)}),this._dialog),this._element.focus())}_adjustDialog(){const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._scrollBar.getWidth(),i=e>0;if(i&&!t){const t=p()?"paddingLeft":"paddingRight";this._element.style[t]=`${e}px`}if(!i&&t){const t=p()?"paddingRight":"paddingLeft";this._element.style[t]=`${e}px`}}_resetAdjustments(){this._element.style.paddingLeft="",this._element.style.paddingRight=""}static jQueryInterface(t,e){return this.each((function(){const i=On.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t](e)}}))}}N.on(document,yn,'[data-bs-toggle="modal"]',(function(t){const e=z.getElementFromSelector(this);["A","AREA"].includes(this.tagName)&&t.preventDefault(),N.one(e,pn,(t=>{t.defaultPrevented||N.one(e,fn,(()=>{a(this)&&this.focus()}))}));const i=z.findOne(".modal.show");i&&On.getInstance(i).hide(),On.getOrCreateInstance(e).toggle(this)})),R(On),m(On);const xn=".bs.offcanvas",kn=".data-api",Ln=`load${xn}${kn}`,Sn="show",Dn="showing",$n="hiding",In=".offcanvas.show",Nn=`show${xn}`,Pn=`shown${xn}`,Mn=`hide${xn}`,jn=`hidePrevented${xn}`,Fn=`hidden${xn}`,Hn=`resize${xn}`,Wn=`click${xn}${kn}`,Bn=`keydown.dismiss${xn}`,zn={backdrop:!0,keyboard:!0,scroll:!1},Rn={backdrop:"(boolean|string)",keyboard:"boolean",scroll:"boolean"};class qn extends W{constructor(t,e){super(t,e),this._isShown=!1,this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._addEventListeners()}static get Default(){return zn}static get DefaultType(){return Rn}static get NAME(){return"offcanvas"}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||N.trigger(this._element,Nn,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._backdrop.show(),this._config.scroll||(new cn).hide(),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.classList.add(Dn),this._queueCallback((()=>{this._config.scroll&&!this._config.backdrop||this._focustrap.activate(),this._element.classList.add(Sn),this._element.classList.remove(Dn),N.trigger(this._element,Pn,{relatedTarget:t})}),this._element,!0))}hide(){this._isShown&&(N.trigger(this._element,Mn).defaultPrevented||(this._focustrap.deactivate(),this._element.blur(),this._isShown=!1,this._element.classList.add($n),this._backdrop.hide(),this._queueCallback((()=>{this._element.classList.remove(Sn,$n),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._config.scroll||(new cn).reset(),N.trigger(this._element,Fn)}),this._element,!0)))}dispose(){this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}_initializeBackDrop(){const t=Boolean(this._config.backdrop);return new Ui({className:"offcanvas-backdrop",isVisible:t,isAnimated:!0,rootElement:this._element.parentNode,clickCallback:t?()=>{"static"!==this._config.backdrop?this.hide():N.trigger(this._element,jn)}:null})}_initializeFocusTrap(){return new sn({trapElement:this._element})}_addEventListeners(){N.on(this._element,Bn,(t=>{"Escape"===t.key&&(this._config.keyboard?this.hide():N.trigger(this._element,jn))}))}static jQueryInterface(t){return this.each((function(){const e=qn.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}N.on(document,Wn,'[data-bs-toggle="offcanvas"]',(function(t){const e=z.getElementFromSelector(this);if(["A","AREA"].includes(this.tagName)&&t.preventDefault(),l(this))return;N.one(e,Fn,(()=>{a(this)&&this.focus()}));const i=z.findOne(In);i&&i!==e&&qn.getInstance(i).hide(),qn.getOrCreateInstance(e).toggle(this)})),N.on(window,Ln,(()=>{for(const t of z.find(In))qn.getOrCreateInstance(t).show()})),N.on(window,Hn,(()=>{for(const t of z.find("[aria-modal][class*=show][class*=offcanvas-]"))"fixed"!==getComputedStyle(t).position&&qn.getOrCreateInstance(t).hide()})),R(qn),m(qn);const Vn={"*":["class","dir","id","lang","role",/^aria-[\w-]*$/i],a:["target","href","title","rel"],area:[],b:[],br:[],col:[],code:[],div:[],em:[],hr:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],i:[],img:["src","srcset","alt","title","width","height"],li:[],ol:[],p:[],pre:[],s:[],small:[],span:[],sub:[],sup:[],strong:[],u:[],ul:[]},Kn=new Set(["background","cite","href","itemtype","longdesc","poster","src","xlink:href"]),Qn=/^(?!javascript:)(?:[a-z0-9+.-]+:|[^&:/?#]*(?:[/?#]|$))/i,Xn=(t,e)=>{const i=t.nodeName.toLowerCase();return e.includes(i)?!Kn.has(i)||Boolean(Qn.test(t.nodeValue)):e.filter((t=>t instanceof RegExp)).some((t=>t.test(i)))},Yn={allowList:Vn,content:{},extraClass:"",html:!1,sanitize:!0,sanitizeFn:null,template:"
"},Un={allowList:"object",content:"object",extraClass:"(string|function)",html:"boolean",sanitize:"boolean",sanitizeFn:"(null|function)",template:"string"},Gn={entry:"(string|element|function|null)",selector:"(string|element)"};class Jn extends H{constructor(t){super(),this._config=this._getConfig(t)}static get Default(){return Yn}static get DefaultType(){return Un}static get NAME(){return"TemplateFactory"}getContent(){return Object.values(this._config.content).map((t=>this._resolvePossibleFunction(t))).filter(Boolean)}hasContent(){return this.getContent().length>0}changeContent(t){return this._checkContent(t),this._config.content={...this._config.content,...t},this}toHtml(){const t=document.createElement("div");t.innerHTML=this._maybeSanitize(this._config.template);for(const[e,i]of Object.entries(this._config.content))this._setContent(t,i,e);const e=t.children[0],i=this._resolvePossibleFunction(this._config.extraClass);return i&&e.classList.add(...i.split(" ")),e}_typeCheckConfig(t){super._typeCheckConfig(t),this._checkContent(t.content)}_checkContent(t){for(const[e,i]of Object.entries(t))super._typeCheckConfig({selector:e,entry:i},Gn)}_setContent(t,e,i){const n=z.findOne(i,t);n&&((e=this._resolvePossibleFunction(e))?o(e)?this._putElementInTemplate(r(e),n):this._config.html?n.innerHTML=this._maybeSanitize(e):n.textContent=e:n.remove())}_maybeSanitize(t){return this._config.sanitize?function(t,e,i){if(!t.length)return t;if(i&&"function"==typeof i)return i(t);const n=(new window.DOMParser).parseFromString(t,"text/html"),s=[].concat(...n.body.querySelectorAll("*"));for(const t of s){const i=t.nodeName.toLowerCase();if(!Object.keys(e).includes(i)){t.remove();continue}const n=[].concat(...t.attributes),s=[].concat(e["*"]||[],e[i]||[]);for(const e of n)Xn(e,s)||t.removeAttribute(e.nodeName)}return n.body.innerHTML}(t,this._config.allowList,this._config.sanitizeFn):t}_resolvePossibleFunction(t){return g(t,[this])}_putElementInTemplate(t,e){if(this._config.html)return e.innerHTML="",void e.append(t);e.textContent=t.textContent}}const Zn=new Set(["sanitize","allowList","sanitizeFn"]),ts="fade",es="show",is=".modal",ns="hide.bs.modal",ss="hover",os="focus",rs={AUTO:"auto",TOP:"top",RIGHT:p()?"left":"right",BOTTOM:"bottom",LEFT:p()?"right":"left"},as={allowList:Vn,animation:!0,boundary:"clippingParents",container:!1,customClass:"",delay:0,fallbackPlacements:["top","right","bottom","left"],html:!1,offset:[0,6],placement:"top",popperConfig:null,sanitize:!0,sanitizeFn:null,selector:!1,template:'',title:"",trigger:"hover focus"},ls={allowList:"object",animation:"boolean",boundary:"(string|element)",container:"(string|element|boolean)",customClass:"(string|function)",delay:"(number|object)",fallbackPlacements:"array",html:"boolean",offset:"(array|string|function)",placement:"(string|function)",popperConfig:"(null|object|function)",sanitize:"boolean",sanitizeFn:"(null|function)",selector:"(string|boolean)",template:"string",title:"(string|element|function)",trigger:"string"};class cs extends W{constructor(t,e){if(void 0===vi)throw new TypeError("Bootstrap's tooltips require Popper (https://popper.js.org)");super(t,e),this._isEnabled=!0,this._timeout=0,this._isHovered=null,this._activeTrigger={},this._popper=null,this._templateFactory=null,this._newContent=null,this.tip=null,this._setListeners(),this._config.selector||this._fixTitle()}static get Default(){return as}static get DefaultType(){return ls}static get NAME(){return"tooltip"}enable(){this._isEnabled=!0}disable(){this._isEnabled=!1}toggleEnabled(){this._isEnabled=!this._isEnabled}toggle(){this._isEnabled&&(this._activeTrigger.click=!this._activeTrigger.click,this._isShown()?this._leave():this._enter())}dispose(){clearTimeout(this._timeout),N.off(this._element.closest(is),ns,this._hideModalHandler),this._element.getAttribute("data-bs-original-title")&&this._element.setAttribute("title",this._element.getAttribute("data-bs-original-title")),this._disposePopper(),super.dispose()}show(){if("none"===this._element.style.display)throw new Error("Please use show on visible elements");if(!this._isWithContent()||!this._isEnabled)return;const t=N.trigger(this._element,this.constructor.eventName("show")),e=(c(this._element)||this._element.ownerDocument.documentElement).contains(this._element);if(t.defaultPrevented||!e)return;this._disposePopper();const i=this._getTipElement();this._element.setAttribute("aria-describedby",i.getAttribute("id"));const{container:n}=this._config;if(this._element.ownerDocument.documentElement.contains(this.tip)||(n.append(i),N.trigger(this._element,this.constructor.eventName("inserted"))),this._popper=this._createPopper(i),i.classList.add(es),"ontouchstart"in document.documentElement)for(const t of[].concat(...document.body.children))N.on(t,"mouseover",h);this._queueCallback((()=>{N.trigger(this._element,this.constructor.eventName("shown")),!1===this._isHovered&&this._leave(),this._isHovered=!1}),this.tip,this._isAnimated())}hide(){if(this._isShown()&&!N.trigger(this._element,this.constructor.eventName("hide")).defaultPrevented){if(this._getTipElement().classList.remove(es),"ontouchstart"in document.documentElement)for(const t of[].concat(...document.body.children))N.off(t,"mouseover",h);this._activeTrigger.click=!1,this._activeTrigger[os]=!1,this._activeTrigger[ss]=!1,this._isHovered=null,this._queueCallback((()=>{this._isWithActiveTrigger()||(this._isHovered||this._disposePopper(),this._element.removeAttribute("aria-describedby"),N.trigger(this._element,this.constructor.eventName("hidden")))}),this.tip,this._isAnimated())}}update(){this._popper&&this._popper.update()}_isWithContent(){return Boolean(this._getTitle())}_getTipElement(){return this.tip||(this.tip=this._createTipElement(this._newContent||this._getContentForTemplate())),this.tip}_createTipElement(t){const e=this._getTemplateFactory(t).toHtml();if(!e)return null;e.classList.remove(ts,es),e.classList.add(`bs-${this.constructor.NAME}-auto`);const i=(t=>{do{t+=Math.floor(1e6*Math.random())}while(document.getElementById(t));return t})(this.constructor.NAME).toString();return e.setAttribute("id",i),this._isAnimated()&&e.classList.add(ts),e}setContent(t){this._newContent=t,this._isShown()&&(this._disposePopper(),this.show())}_getTemplateFactory(t){return this._templateFactory?this._templateFactory.changeContent(t):this._templateFactory=new Jn({...this._config,content:t,extraClass:this._resolvePossibleFunction(this._config.customClass)}),this._templateFactory}_getContentForTemplate(){return{".tooltip-inner":this._getTitle()}}_getTitle(){return this._resolvePossibleFunction(this._config.title)||this._element.getAttribute("data-bs-original-title")}_initializeOnDelegatedTarget(t){return this.constructor.getOrCreateInstance(t.delegateTarget,this._getDelegateConfig())}_isAnimated(){return this._config.animation||this.tip&&this.tip.classList.contains(ts)}_isShown(){return this.tip&&this.tip.classList.contains(es)}_createPopper(t){const e=g(this._config.placement,[this,t,this._element]),i=rs[e.toUpperCase()];return bi(this._element,t,this._getPopperConfig(i))}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map((t=>Number.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_resolvePossibleFunction(t){return g(t,[this._element])}_getPopperConfig(t){const e={placement:t,modifiers:[{name:"flip",options:{fallbackPlacements:this._config.fallbackPlacements}},{name:"offset",options:{offset:this._getOffset()}},{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"arrow",options:{element:`.${this.constructor.NAME}-arrow`}},{name:"preSetPlacement",enabled:!0,phase:"beforeMain",fn:t=>{this._getTipElement().setAttribute("data-popper-placement",t.state.placement)}}]};return{...e,...g(this._config.popperConfig,[e])}}_setListeners(){const t=this._config.trigger.split(" ");for(const e of t)if("click"===e)N.on(this._element,this.constructor.eventName("click"),this._config.selector,(t=>{this._initializeOnDelegatedTarget(t).toggle()}));else if("manual"!==e){const t=e===ss?this.constructor.eventName("mouseenter"):this.constructor.eventName("focusin"),i=e===ss?this.constructor.eventName("mouseleave"):this.constructor.eventName("focusout");N.on(this._element,t,this._config.selector,(t=>{const e=this._initializeOnDelegatedTarget(t);e._activeTrigger["focusin"===t.type?os:ss]=!0,e._enter()})),N.on(this._element,i,this._config.selector,(t=>{const e=this._initializeOnDelegatedTarget(t);e._activeTrigger["focusout"===t.type?os:ss]=e._element.contains(t.relatedTarget),e._leave()}))}this._hideModalHandler=()=>{this._element&&this.hide()},N.on(this._element.closest(is),ns,this._hideModalHandler)}_fixTitle(){const t=this._element.getAttribute("title");t&&(this._element.getAttribute("aria-label")||this._element.textContent.trim()||this._element.setAttribute("aria-label",t),this._element.setAttribute("data-bs-original-title",t),this._element.removeAttribute("title"))}_enter(){this._isShown()||this._isHovered?this._isHovered=!0:(this._isHovered=!0,this._setTimeout((()=>{this._isHovered&&this.show()}),this._config.delay.show))}_leave(){this._isWithActiveTrigger()||(this._isHovered=!1,this._setTimeout((()=>{this._isHovered||this.hide()}),this._config.delay.hide))}_setTimeout(t,e){clearTimeout(this._timeout),this._timeout=setTimeout(t,e)}_isWithActiveTrigger(){return Object.values(this._activeTrigger).includes(!0)}_getConfig(t){const e=F.getDataAttributes(this._element);for(const t of Object.keys(e))Zn.has(t)&&delete e[t];return t={...e,..."object"==typeof t&&t?t:{}},t=this._mergeConfigObj(t),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}_configAfterMerge(t){return t.container=!1===t.container?document.body:r(t.container),"number"==typeof t.delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),t}_getDelegateConfig(){const t={};for(const[e,i]of Object.entries(this._config))this.constructor.Default[e]!==i&&(t[e]=i);return t.selector=!1,t.trigger="manual",t}_disposePopper(){this._popper&&(this._popper.destroy(),this._popper=null),this.tip&&(this.tip.remove(),this.tip=null)}static jQueryInterface(t){return this.each((function(){const e=cs.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}m(cs);const hs={...cs.Default,content:"",offset:[0,8],placement:"right",template:'',trigger:"click"},ds={...cs.DefaultType,content:"(null|string|element|function)"};class us extends cs{static get Default(){return hs}static get DefaultType(){return ds}static get NAME(){return"popover"}_isWithContent(){return this._getTitle()||this._getContent()}_getContentForTemplate(){return{".popover-header":this._getTitle(),".popover-body":this._getContent()}}_getContent(){return this._resolvePossibleFunction(this._config.content)}static jQueryInterface(t){return this.each((function(){const e=us.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}m(us);const fs=".bs.scrollspy",ps=`activate${fs}`,ms=`click${fs}`,gs=`load${fs}.data-api`,_s="active",bs="[href]",vs=".nav-link",ys=`${vs}, .nav-item > ${vs}, .list-group-item`,ws={offset:null,rootMargin:"0px 0px -25%",smoothScroll:!1,target:null,threshold:[.1,.5,1]},As={offset:"(number|null)",rootMargin:"string",smoothScroll:"boolean",target:"element",threshold:"array"};class Es extends W{constructor(t,e){super(t,e),this._targetLinks=new Map,this._observableSections=new Map,this._rootElement="visible"===getComputedStyle(this._element).overflowY?null:this._element,this._activeTarget=null,this._observer=null,this._previousScrollData={visibleEntryTop:0,parentScrollTop:0},this.refresh()}static get Default(){return ws}static get DefaultType(){return As}static get NAME(){return"scrollspy"}refresh(){this._initializeTargetsAndObservables(),this._maybeEnableSmoothScroll(),this._observer?this._observer.disconnect():this._observer=this._getNewObserver();for(const t of this._observableSections.values())this._observer.observe(t)}dispose(){this._observer.disconnect(),super.dispose()}_configAfterMerge(t){return t.target=r(t.target)||document.body,t.rootMargin=t.offset?`${t.offset}px 0px -30%`:t.rootMargin,"string"==typeof t.threshold&&(t.threshold=t.threshold.split(",").map((t=>Number.parseFloat(t)))),t}_maybeEnableSmoothScroll(){this._config.smoothScroll&&(N.off(this._config.target,ms),N.on(this._config.target,ms,bs,(t=>{const e=this._observableSections.get(t.target.hash);if(e){t.preventDefault();const i=this._rootElement||window,n=e.offsetTop-this._element.offsetTop;if(i.scrollTo)return void i.scrollTo({top:n,behavior:"smooth"});i.scrollTop=n}})))}_getNewObserver(){const t={root:this._rootElement,threshold:this._config.threshold,rootMargin:this._config.rootMargin};return new IntersectionObserver((t=>this._observerCallback(t)),t)}_observerCallback(t){const e=t=>this._targetLinks.get(`#${t.target.id}`),i=t=>{this._previousScrollData.visibleEntryTop=t.target.offsetTop,this._process(e(t))},n=(this._rootElement||document.documentElement).scrollTop,s=n>=this._previousScrollData.parentScrollTop;this._previousScrollData.parentScrollTop=n;for(const o of t){if(!o.isIntersecting){this._activeTarget=null,this._clearActiveClass(e(o));continue}const t=o.target.offsetTop>=this._previousScrollData.visibleEntryTop;if(s&&t){if(i(o),!n)return}else s||t||i(o)}}_initializeTargetsAndObservables(){this._targetLinks=new Map,this._observableSections=new Map;const t=z.find(bs,this._config.target);for(const e of t){if(!e.hash||l(e))continue;const t=z.findOne(decodeURI(e.hash),this._element);a(t)&&(this._targetLinks.set(decodeURI(e.hash),e),this._observableSections.set(e.hash,t))}}_process(t){this._activeTarget!==t&&(this._clearActiveClass(this._config.target),this._activeTarget=t,t.classList.add(_s),this._activateParents(t),N.trigger(this._element,ps,{relatedTarget:t}))}_activateParents(t){if(t.classList.contains("dropdown-item"))z.findOne(".dropdown-toggle",t.closest(".dropdown")).classList.add(_s);else for(const e of z.parents(t,".nav, .list-group"))for(const t of z.prev(e,ys))t.classList.add(_s)}_clearActiveClass(t){t.classList.remove(_s);const e=z.find(`${bs}.${_s}`,t);for(const t of e)t.classList.remove(_s)}static jQueryInterface(t){return this.each((function(){const e=Es.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}))}}N.on(window,gs,(()=>{for(const t of z.find('[data-bs-spy="scroll"]'))Es.getOrCreateInstance(t)})),m(Es);const Ts=".bs.tab",Cs=`hide${Ts}`,Os=`hidden${Ts}`,xs=`show${Ts}`,ks=`shown${Ts}`,Ls=`click${Ts}`,Ss=`keydown${Ts}`,Ds=`load${Ts}`,$s="ArrowLeft",Is="ArrowRight",Ns="ArrowUp",Ps="ArrowDown",Ms="Home",js="End",Fs="active",Hs="fade",Ws="show",Bs=":not(.dropdown-toggle)",zs='[data-bs-toggle="tab"], [data-bs-toggle="pill"], [data-bs-toggle="list"]',Rs=`.nav-link${Bs}, .list-group-item${Bs}, [role="tab"]${Bs}, ${zs}`,qs=`.${Fs}[data-bs-toggle="tab"], .${Fs}[data-bs-toggle="pill"], .${Fs}[data-bs-toggle="list"]`;class Vs extends W{constructor(t){super(t),this._parent=this._element.closest('.list-group, .nav, [role="tablist"]'),this._parent&&(this._setInitialAttributes(this._parent,this._getChildren()),N.on(this._element,Ss,(t=>this._keydown(t))))}static get NAME(){return"tab"}show(){const t=this._element;if(this._elemIsActive(t))return;const e=this._getActiveElem(),i=e?N.trigger(e,Cs,{relatedTarget:t}):null;N.trigger(t,xs,{relatedTarget:e}).defaultPrevented||i&&i.defaultPrevented||(this._deactivate(e,t),this._activate(t,e))}_activate(t,e){t&&(t.classList.add(Fs),this._activate(z.getElementFromSelector(t)),this._queueCallback((()=>{"tab"===t.getAttribute("role")?(t.removeAttribute("tabindex"),t.setAttribute("aria-selected",!0),this._toggleDropDown(t,!0),N.trigger(t,ks,{relatedTarget:e})):t.classList.add(Ws)}),t,t.classList.contains(Hs)))}_deactivate(t,e){t&&(t.classList.remove(Fs),t.blur(),this._deactivate(z.getElementFromSelector(t)),this._queueCallback((()=>{"tab"===t.getAttribute("role")?(t.setAttribute("aria-selected",!1),t.setAttribute("tabindex","-1"),this._toggleDropDown(t,!1),N.trigger(t,Os,{relatedTarget:e})):t.classList.remove(Ws)}),t,t.classList.contains(Hs)))}_keydown(t){if(![$s,Is,Ns,Ps,Ms,js].includes(t.key))return;t.stopPropagation(),t.preventDefault();const e=this._getChildren().filter((t=>!l(t)));let i;if([Ms,js].includes(t.key))i=e[t.key===Ms?0:e.length-1];else{const n=[Is,Ps].includes(t.key);i=b(e,t.target,n,!0)}i&&(i.focus({preventScroll:!0}),Vs.getOrCreateInstance(i).show())}_getChildren(){return z.find(Rs,this._parent)}_getActiveElem(){return this._getChildren().find((t=>this._elemIsActive(t)))||null}_setInitialAttributes(t,e){this._setAttributeIfNotExists(t,"role","tablist");for(const t of e)this._setInitialAttributesOnChild(t)}_setInitialAttributesOnChild(t){t=this._getInnerElement(t);const e=this._elemIsActive(t),i=this._getOuterElement(t);t.setAttribute("aria-selected",e),i!==t&&this._setAttributeIfNotExists(i,"role","presentation"),e||t.setAttribute("tabindex","-1"),this._setAttributeIfNotExists(t,"role","tab"),this._setInitialAttributesOnTargetPanel(t)}_setInitialAttributesOnTargetPanel(t){const e=z.getElementFromSelector(t);e&&(this._setAttributeIfNotExists(e,"role","tabpanel"),t.id&&this._setAttributeIfNotExists(e,"aria-labelledby",`${t.id}`))}_toggleDropDown(t,e){const i=this._getOuterElement(t);if(!i.classList.contains("dropdown"))return;const n=(t,n)=>{const s=z.findOne(t,i);s&&s.classList.toggle(n,e)};n(".dropdown-toggle",Fs),n(".dropdown-menu",Ws),i.setAttribute("aria-expanded",e)}_setAttributeIfNotExists(t,e,i){t.hasAttribute(e)||t.setAttribute(e,i)}_elemIsActive(t){return t.classList.contains(Fs)}_getInnerElement(t){return t.matches(Rs)?t:z.findOne(Rs,t)}_getOuterElement(t){return t.closest(".nav-item, .list-group-item")||t}static jQueryInterface(t){return this.each((function(){const e=Vs.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}))}}N.on(document,Ls,zs,(function(t){["A","AREA"].includes(this.tagName)&&t.preventDefault(),l(this)||Vs.getOrCreateInstance(this).show()})),N.on(window,Ds,(()=>{for(const t of z.find(qs))Vs.getOrCreateInstance(t)})),m(Vs);const Ks=".bs.toast",Qs=`mouseover${Ks}`,Xs=`mouseout${Ks}`,Ys=`focusin${Ks}`,Us=`focusout${Ks}`,Gs=`hide${Ks}`,Js=`hidden${Ks}`,Zs=`show${Ks}`,to=`shown${Ks}`,eo="hide",io="show",no="showing",so={animation:"boolean",autohide:"boolean",delay:"number"},oo={animation:!0,autohide:!0,delay:5e3};class ro extends W{constructor(t,e){super(t,e),this._timeout=null,this._hasMouseInteraction=!1,this._hasKeyboardInteraction=!1,this._setListeners()}static get Default(){return oo}static get DefaultType(){return so}static get NAME(){return"toast"}show(){N.trigger(this._element,Zs).defaultPrevented||(this._clearTimeout(),this._config.animation&&this._element.classList.add("fade"),this._element.classList.remove(eo),d(this._element),this._element.classList.add(io,no),this._queueCallback((()=>{this._element.classList.remove(no),N.trigger(this._element,to),this._maybeScheduleHide()}),this._element,this._config.animation))}hide(){this.isShown()&&(N.trigger(this._element,Gs).defaultPrevented||(this._element.classList.add(no),this._queueCallback((()=>{this._element.classList.add(eo),this._element.classList.remove(no,io),N.trigger(this._element,Js)}),this._element,this._config.animation)))}dispose(){this._clearTimeout(),this.isShown()&&this._element.classList.remove(io),super.dispose()}isShown(){return this._element.classList.contains(io)}_maybeScheduleHide(){this._config.autohide&&(this._hasMouseInteraction||this._hasKeyboardInteraction||(this._timeout=setTimeout((()=>{this.hide()}),this._config.delay)))}_onInteraction(t,e){switch(t.type){case"mouseover":case"mouseout":this._hasMouseInteraction=e;break;case"focusin":case"focusout":this._hasKeyboardInteraction=e}if(e)return void this._clearTimeout();const i=t.relatedTarget;this._element===i||this._element.contains(i)||this._maybeScheduleHide()}_setListeners(){N.on(this._element,Qs,(t=>this._onInteraction(t,!0))),N.on(this._element,Xs,(t=>this._onInteraction(t,!1))),N.on(this._element,Ys,(t=>this._onInteraction(t,!0))),N.on(this._element,Us,(t=>this._onInteraction(t,!1)))}_clearTimeout(){clearTimeout(this._timeout),this._timeout=null}static jQueryInterface(t){return this.each((function(){const e=ro.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}return R(ro),m(ro),{Alert:Q,Button:Y,Carousel:xt,Collapse:Bt,Dropdown:qi,Modal:On,Offcanvas:qn,Popover:us,ScrollSpy:Es,Tab:Vs,Toast:ro,Tooltip:cs}})); -//# sourceMappingURL=bootstrap.bundle.min.js.map \ No newline at end of file diff --git a/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/uncertainty_files/libs/clipboard/clipboard.min.js b/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/uncertainty_files/libs/clipboard/clipboard.min.js deleted file mode 100644 index 1103f811e..000000000 --- a/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/uncertainty_files/libs/clipboard/clipboard.min.js +++ /dev/null @@ -1,7 +0,0 @@ -/*! - * clipboard.js v2.0.11 - * https://clipboardjs.com/ - * - * Licensed MIT © Zeno Rocha - */ -!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ClipboardJS=e():t.ClipboardJS=e()}(this,function(){return n={686:function(t,e,n){"use strict";n.d(e,{default:function(){return b}});var e=n(279),i=n.n(e),e=n(370),u=n.n(e),e=n(817),r=n.n(e);function c(t){try{return document.execCommand(t)}catch(t){return}}var a=function(t){t=r()(t);return c("cut"),t};function o(t,e){var n,o,t=(n=t,o="rtl"===document.documentElement.getAttribute("dir"),(t=document.createElement("textarea")).style.fontSize="12pt",t.style.border="0",t.style.padding="0",t.style.margin="0",t.style.position="absolute",t.style[o?"right":"left"]="-9999px",o=window.pageYOffset||document.documentElement.scrollTop,t.style.top="".concat(o,"px"),t.setAttribute("readonly",""),t.value=n,t);return e.container.appendChild(t),e=r()(t),c("copy"),t.remove(),e}var f=function(t){var e=1.anchorjs-link,.anchorjs-link:focus{opacity:1}",A.sheet.cssRules.length),A.sheet.insertRule("[data-anchorjs-icon]::after{content:attr(data-anchorjs-icon)}",A.sheet.cssRules.length),A.sheet.insertRule('@font-face{font-family:anchorjs-icons;src:url(data:n/a;base64,AAEAAAALAIAAAwAwT1MvMg8yG2cAAAE4AAAAYGNtYXDp3gC3AAABpAAAAExnYXNwAAAAEAAAA9wAAAAIZ2x5ZlQCcfwAAAH4AAABCGhlYWQHFvHyAAAAvAAAADZoaGVhBnACFwAAAPQAAAAkaG10eASAADEAAAGYAAAADGxvY2EACACEAAAB8AAAAAhtYXhwAAYAVwAAARgAAAAgbmFtZQGOH9cAAAMAAAAAunBvc3QAAwAAAAADvAAAACAAAQAAAAEAAHzE2p9fDzz1AAkEAAAAAADRecUWAAAAANQA6R8AAAAAAoACwAAAAAgAAgAAAAAAAAABAAADwP/AAAACgAAA/9MCrQABAAAAAAAAAAAAAAAAAAAAAwABAAAAAwBVAAIAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAMCQAGQAAUAAAKZAswAAACPApkCzAAAAesAMwEJAAAAAAAAAAAAAAAAAAAAARAAAAAAAAAAAAAAAAAAAAAAQAAg//0DwP/AAEADwABAAAAAAQAAAAAAAAAAAAAAIAAAAAAAAAIAAAACgAAxAAAAAwAAAAMAAAAcAAEAAwAAABwAAwABAAAAHAAEADAAAAAIAAgAAgAAACDpy//9//8AAAAg6cv//f///+EWNwADAAEAAAAAAAAAAAAAAAAACACEAAEAAAAAAAAAAAAAAAAxAAACAAQARAKAAsAAKwBUAAABIiYnJjQ3NzY2MzIWFxYUBwcGIicmNDc3NjQnJiYjIgYHBwYUFxYUBwYGIwciJicmNDc3NjIXFhQHBwYUFxYWMzI2Nzc2NCcmNDc2MhcWFAcHBgYjARQGDAUtLXoWOR8fORYtLTgKGwoKCjgaGg0gEhIgDXoaGgkJBQwHdR85Fi0tOAobCgoKOBoaDSASEiANehoaCQkKGwotLXoWOR8BMwUFLYEuehYXFxYugC44CQkKGwo4GkoaDQ0NDXoaShoKGwoFBe8XFi6ALjgJCQobCjgaShoNDQ0NehpKGgobCgoKLYEuehYXAAAADACWAAEAAAAAAAEACAAAAAEAAAAAAAIAAwAIAAEAAAAAAAMACAAAAAEAAAAAAAQACAAAAAEAAAAAAAUAAQALAAEAAAAAAAYACAAAAAMAAQQJAAEAEAAMAAMAAQQJAAIABgAcAAMAAQQJAAMAEAAMAAMAAQQJAAQAEAAMAAMAAQQJAAUAAgAiAAMAAQQJAAYAEAAMYW5jaG9yanM0MDBAAGEAbgBjAGgAbwByAGoAcwA0ADAAMABAAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAH//wAP) format("truetype")}',A.sheet.cssRules.length)),h=document.querySelectorAll("[id]"),t=[].map.call(h,function(A){return A.id}),i=0;i\]./()*\\\n\t\b\v\u00A0]/g,"-").replace(/-{2,}/g,"-").substring(0,this.options.truncate).replace(/^-+|-+$/gm,"").toLowerCase()},this.hasAnchorJSLink=function(A){var e=A.firstChild&&-1<(" "+A.firstChild.className+" ").indexOf(" anchorjs-link "),A=A.lastChild&&-1<(" "+A.lastChild.className+" ").indexOf(" anchorjs-link ");return e||A||!1}}}); -// @license-end \ No newline at end of file diff --git a/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/uncertainty_files/libs/quarto-html/popper.min.js b/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/uncertainty_files/libs/quarto-html/popper.min.js deleted file mode 100644 index e3726d728..000000000 --- a/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/uncertainty_files/libs/quarto-html/popper.min.js +++ /dev/null @@ -1,6 +0,0 @@ -/** - * @popperjs/core v2.11.7 - MIT License - */ - -!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).Popper={})}(this,(function(e){"use strict";function t(e){if(null==e)return window;if("[object Window]"!==e.toString()){var t=e.ownerDocument;return t&&t.defaultView||window}return e}function n(e){return e instanceof t(e).Element||e instanceof Element}function r(e){return e instanceof t(e).HTMLElement||e instanceof HTMLElement}function o(e){return"undefined"!=typeof ShadowRoot&&(e instanceof t(e).ShadowRoot||e instanceof ShadowRoot)}var i=Math.max,a=Math.min,s=Math.round;function f(){var e=navigator.userAgentData;return null!=e&&e.brands&&Array.isArray(e.brands)?e.brands.map((function(e){return e.brand+"/"+e.version})).join(" "):navigator.userAgent}function c(){return!/^((?!chrome|android).)*safari/i.test(f())}function p(e,o,i){void 0===o&&(o=!1),void 0===i&&(i=!1);var a=e.getBoundingClientRect(),f=1,p=1;o&&r(e)&&(f=e.offsetWidth>0&&s(a.width)/e.offsetWidth||1,p=e.offsetHeight>0&&s(a.height)/e.offsetHeight||1);var u=(n(e)?t(e):window).visualViewport,l=!c()&&i,d=(a.left+(l&&u?u.offsetLeft:0))/f,h=(a.top+(l&&u?u.offsetTop:0))/p,m=a.width/f,v=a.height/p;return{width:m,height:v,top:h,right:d+m,bottom:h+v,left:d,x:d,y:h}}function u(e){var n=t(e);return{scrollLeft:n.pageXOffset,scrollTop:n.pageYOffset}}function l(e){return e?(e.nodeName||"").toLowerCase():null}function d(e){return((n(e)?e.ownerDocument:e.document)||window.document).documentElement}function h(e){return p(d(e)).left+u(e).scrollLeft}function m(e){return t(e).getComputedStyle(e)}function v(e){var t=m(e),n=t.overflow,r=t.overflowX,o=t.overflowY;return/auto|scroll|overlay|hidden/.test(n+o+r)}function y(e,n,o){void 0===o&&(o=!1);var i,a,f=r(n),c=r(n)&&function(e){var t=e.getBoundingClientRect(),n=s(t.width)/e.offsetWidth||1,r=s(t.height)/e.offsetHeight||1;return 1!==n||1!==r}(n),m=d(n),y=p(e,c,o),g={scrollLeft:0,scrollTop:0},b={x:0,y:0};return(f||!f&&!o)&&(("body"!==l(n)||v(m))&&(g=(i=n)!==t(i)&&r(i)?{scrollLeft:(a=i).scrollLeft,scrollTop:a.scrollTop}:u(i)),r(n)?((b=p(n,!0)).x+=n.clientLeft,b.y+=n.clientTop):m&&(b.x=h(m))),{x:y.left+g.scrollLeft-b.x,y:y.top+g.scrollTop-b.y,width:y.width,height:y.height}}function g(e){var t=p(e),n=e.offsetWidth,r=e.offsetHeight;return Math.abs(t.width-n)<=1&&(n=t.width),Math.abs(t.height-r)<=1&&(r=t.height),{x:e.offsetLeft,y:e.offsetTop,width:n,height:r}}function b(e){return"html"===l(e)?e:e.assignedSlot||e.parentNode||(o(e)?e.host:null)||d(e)}function x(e){return["html","body","#document"].indexOf(l(e))>=0?e.ownerDocument.body:r(e)&&v(e)?e:x(b(e))}function w(e,n){var r;void 0===n&&(n=[]);var o=x(e),i=o===(null==(r=e.ownerDocument)?void 0:r.body),a=t(o),s=i?[a].concat(a.visualViewport||[],v(o)?o:[]):o,f=n.concat(s);return i?f:f.concat(w(b(s)))}function O(e){return["table","td","th"].indexOf(l(e))>=0}function j(e){return r(e)&&"fixed"!==m(e).position?e.offsetParent:null}function E(e){for(var n=t(e),i=j(e);i&&O(i)&&"static"===m(i).position;)i=j(i);return i&&("html"===l(i)||"body"===l(i)&&"static"===m(i).position)?n:i||function(e){var t=/firefox/i.test(f());if(/Trident/i.test(f())&&r(e)&&"fixed"===m(e).position)return null;var n=b(e);for(o(n)&&(n=n.host);r(n)&&["html","body"].indexOf(l(n))<0;){var i=m(n);if("none"!==i.transform||"none"!==i.perspective||"paint"===i.contain||-1!==["transform","perspective"].indexOf(i.willChange)||t&&"filter"===i.willChange||t&&i.filter&&"none"!==i.filter)return n;n=n.parentNode}return null}(e)||n}var D="top",A="bottom",L="right",P="left",M="auto",k=[D,A,L,P],W="start",B="end",H="viewport",T="popper",R=k.reduce((function(e,t){return e.concat([t+"-"+W,t+"-"+B])}),[]),S=[].concat(k,[M]).reduce((function(e,t){return e.concat([t,t+"-"+W,t+"-"+B])}),[]),V=["beforeRead","read","afterRead","beforeMain","main","afterMain","beforeWrite","write","afterWrite"];function q(e){var t=new Map,n=new Set,r=[];function o(e){n.add(e.name),[].concat(e.requires||[],e.requiresIfExists||[]).forEach((function(e){if(!n.has(e)){var r=t.get(e);r&&o(r)}})),r.push(e)}return e.forEach((function(e){t.set(e.name,e)})),e.forEach((function(e){n.has(e.name)||o(e)})),r}function C(e){return e.split("-")[0]}function N(e,t){var n=t.getRootNode&&t.getRootNode();if(e.contains(t))return!0;if(n&&o(n)){var r=t;do{if(r&&e.isSameNode(r))return!0;r=r.parentNode||r.host}while(r)}return!1}function I(e){return Object.assign({},e,{left:e.x,top:e.y,right:e.x+e.width,bottom:e.y+e.height})}function _(e,r,o){return r===H?I(function(e,n){var r=t(e),o=d(e),i=r.visualViewport,a=o.clientWidth,s=o.clientHeight,f=0,p=0;if(i){a=i.width,s=i.height;var u=c();(u||!u&&"fixed"===n)&&(f=i.offsetLeft,p=i.offsetTop)}return{width:a,height:s,x:f+h(e),y:p}}(e,o)):n(r)?function(e,t){var n=p(e,!1,"fixed"===t);return n.top=n.top+e.clientTop,n.left=n.left+e.clientLeft,n.bottom=n.top+e.clientHeight,n.right=n.left+e.clientWidth,n.width=e.clientWidth,n.height=e.clientHeight,n.x=n.left,n.y=n.top,n}(r,o):I(function(e){var t,n=d(e),r=u(e),o=null==(t=e.ownerDocument)?void 0:t.body,a=i(n.scrollWidth,n.clientWidth,o?o.scrollWidth:0,o?o.clientWidth:0),s=i(n.scrollHeight,n.clientHeight,o?o.scrollHeight:0,o?o.clientHeight:0),f=-r.scrollLeft+h(e),c=-r.scrollTop;return"rtl"===m(o||n).direction&&(f+=i(n.clientWidth,o?o.clientWidth:0)-a),{width:a,height:s,x:f,y:c}}(d(e)))}function F(e,t,o,s){var f="clippingParents"===t?function(e){var t=w(b(e)),o=["absolute","fixed"].indexOf(m(e).position)>=0&&r(e)?E(e):e;return n(o)?t.filter((function(e){return n(e)&&N(e,o)&&"body"!==l(e)})):[]}(e):[].concat(t),c=[].concat(f,[o]),p=c[0],u=c.reduce((function(t,n){var r=_(e,n,s);return t.top=i(r.top,t.top),t.right=a(r.right,t.right),t.bottom=a(r.bottom,t.bottom),t.left=i(r.left,t.left),t}),_(e,p,s));return u.width=u.right-u.left,u.height=u.bottom-u.top,u.x=u.left,u.y=u.top,u}function U(e){return e.split("-")[1]}function z(e){return["top","bottom"].indexOf(e)>=0?"x":"y"}function X(e){var t,n=e.reference,r=e.element,o=e.placement,i=o?C(o):null,a=o?U(o):null,s=n.x+n.width/2-r.width/2,f=n.y+n.height/2-r.height/2;switch(i){case D:t={x:s,y:n.y-r.height};break;case A:t={x:s,y:n.y+n.height};break;case L:t={x:n.x+n.width,y:f};break;case P:t={x:n.x-r.width,y:f};break;default:t={x:n.x,y:n.y}}var c=i?z(i):null;if(null!=c){var p="y"===c?"height":"width";switch(a){case W:t[c]=t[c]-(n[p]/2-r[p]/2);break;case B:t[c]=t[c]+(n[p]/2-r[p]/2)}}return t}function Y(e){return Object.assign({},{top:0,right:0,bottom:0,left:0},e)}function G(e,t){return t.reduce((function(t,n){return t[n]=e,t}),{})}function J(e,t){void 0===t&&(t={});var r=t,o=r.placement,i=void 0===o?e.placement:o,a=r.strategy,s=void 0===a?e.strategy:a,f=r.boundary,c=void 0===f?"clippingParents":f,u=r.rootBoundary,l=void 0===u?H:u,h=r.elementContext,m=void 0===h?T:h,v=r.altBoundary,y=void 0!==v&&v,g=r.padding,b=void 0===g?0:g,x=Y("number"!=typeof b?b:G(b,k)),w=m===T?"reference":T,O=e.rects.popper,j=e.elements[y?w:m],E=F(n(j)?j:j.contextElement||d(e.elements.popper),c,l,s),P=p(e.elements.reference),M=X({reference:P,element:O,strategy:"absolute",placement:i}),W=I(Object.assign({},O,M)),B=m===T?W:P,R={top:E.top-B.top+x.top,bottom:B.bottom-E.bottom+x.bottom,left:E.left-B.left+x.left,right:B.right-E.right+x.right},S=e.modifiersData.offset;if(m===T&&S){var V=S[i];Object.keys(R).forEach((function(e){var t=[L,A].indexOf(e)>=0?1:-1,n=[D,A].indexOf(e)>=0?"y":"x";R[e]+=V[n]*t}))}return R}var K={placement:"bottom",modifiers:[],strategy:"absolute"};function Q(){for(var e=arguments.length,t=new Array(e),n=0;n=0?-1:1,i="function"==typeof n?n(Object.assign({},t,{placement:e})):n,a=i[0],s=i[1];return a=a||0,s=(s||0)*o,[P,L].indexOf(r)>=0?{x:s,y:a}:{x:a,y:s}}(n,t.rects,i),e}),{}),s=a[t.placement],f=s.x,c=s.y;null!=t.modifiersData.popperOffsets&&(t.modifiersData.popperOffsets.x+=f,t.modifiersData.popperOffsets.y+=c),t.modifiersData[r]=a}},se={left:"right",right:"left",bottom:"top",top:"bottom"};function fe(e){return e.replace(/left|right|bottom|top/g,(function(e){return se[e]}))}var ce={start:"end",end:"start"};function pe(e){return e.replace(/start|end/g,(function(e){return ce[e]}))}function ue(e,t){void 0===t&&(t={});var n=t,r=n.placement,o=n.boundary,i=n.rootBoundary,a=n.padding,s=n.flipVariations,f=n.allowedAutoPlacements,c=void 0===f?S:f,p=U(r),u=p?s?R:R.filter((function(e){return U(e)===p})):k,l=u.filter((function(e){return c.indexOf(e)>=0}));0===l.length&&(l=u);var d=l.reduce((function(t,n){return t[n]=J(e,{placement:n,boundary:o,rootBoundary:i,padding:a})[C(n)],t}),{});return Object.keys(d).sort((function(e,t){return d[e]-d[t]}))}var le={name:"flip",enabled:!0,phase:"main",fn:function(e){var t=e.state,n=e.options,r=e.name;if(!t.modifiersData[r]._skip){for(var o=n.mainAxis,i=void 0===o||o,a=n.altAxis,s=void 0===a||a,f=n.fallbackPlacements,c=n.padding,p=n.boundary,u=n.rootBoundary,l=n.altBoundary,d=n.flipVariations,h=void 0===d||d,m=n.allowedAutoPlacements,v=t.options.placement,y=C(v),g=f||(y===v||!h?[fe(v)]:function(e){if(C(e)===M)return[];var t=fe(e);return[pe(e),t,pe(t)]}(v)),b=[v].concat(g).reduce((function(e,n){return e.concat(C(n)===M?ue(t,{placement:n,boundary:p,rootBoundary:u,padding:c,flipVariations:h,allowedAutoPlacements:m}):n)}),[]),x=t.rects.reference,w=t.rects.popper,O=new Map,j=!0,E=b[0],k=0;k=0,S=R?"width":"height",V=J(t,{placement:B,boundary:p,rootBoundary:u,altBoundary:l,padding:c}),q=R?T?L:P:T?A:D;x[S]>w[S]&&(q=fe(q));var N=fe(q),I=[];if(i&&I.push(V[H]<=0),s&&I.push(V[q]<=0,V[N]<=0),I.every((function(e){return e}))){E=B,j=!1;break}O.set(B,I)}if(j)for(var _=function(e){var t=b.find((function(t){var n=O.get(t);if(n)return n.slice(0,e).every((function(e){return e}))}));if(t)return E=t,"break"},F=h?3:1;F>0;F--){if("break"===_(F))break}t.placement!==E&&(t.modifiersData[r]._skip=!0,t.placement=E,t.reset=!0)}},requiresIfExists:["offset"],data:{_skip:!1}};function de(e,t,n){return i(e,a(t,n))}var he={name:"preventOverflow",enabled:!0,phase:"main",fn:function(e){var t=e.state,n=e.options,r=e.name,o=n.mainAxis,s=void 0===o||o,f=n.altAxis,c=void 0!==f&&f,p=n.boundary,u=n.rootBoundary,l=n.altBoundary,d=n.padding,h=n.tether,m=void 0===h||h,v=n.tetherOffset,y=void 0===v?0:v,b=J(t,{boundary:p,rootBoundary:u,padding:d,altBoundary:l}),x=C(t.placement),w=U(t.placement),O=!w,j=z(x),M="x"===j?"y":"x",k=t.modifiersData.popperOffsets,B=t.rects.reference,H=t.rects.popper,T="function"==typeof y?y(Object.assign({},t.rects,{placement:t.placement})):y,R="number"==typeof T?{mainAxis:T,altAxis:T}:Object.assign({mainAxis:0,altAxis:0},T),S=t.modifiersData.offset?t.modifiersData.offset[t.placement]:null,V={x:0,y:0};if(k){if(s){var q,N="y"===j?D:P,I="y"===j?A:L,_="y"===j?"height":"width",F=k[j],X=F+b[N],Y=F-b[I],G=m?-H[_]/2:0,K=w===W?B[_]:H[_],Q=w===W?-H[_]:-B[_],Z=t.elements.arrow,$=m&&Z?g(Z):{width:0,height:0},ee=t.modifiersData["arrow#persistent"]?t.modifiersData["arrow#persistent"].padding:{top:0,right:0,bottom:0,left:0},te=ee[N],ne=ee[I],re=de(0,B[_],$[_]),oe=O?B[_]/2-G-re-te-R.mainAxis:K-re-te-R.mainAxis,ie=O?-B[_]/2+G+re+ne+R.mainAxis:Q+re+ne+R.mainAxis,ae=t.elements.arrow&&E(t.elements.arrow),se=ae?"y"===j?ae.clientTop||0:ae.clientLeft||0:0,fe=null!=(q=null==S?void 0:S[j])?q:0,ce=F+ie-fe,pe=de(m?a(X,F+oe-fe-se):X,F,m?i(Y,ce):Y);k[j]=pe,V[j]=pe-F}if(c){var ue,le="x"===j?D:P,he="x"===j?A:L,me=k[M],ve="y"===M?"height":"width",ye=me+b[le],ge=me-b[he],be=-1!==[D,P].indexOf(x),xe=null!=(ue=null==S?void 0:S[M])?ue:0,we=be?ye:me-B[ve]-H[ve]-xe+R.altAxis,Oe=be?me+B[ve]+H[ve]-xe-R.altAxis:ge,je=m&&be?function(e,t,n){var r=de(e,t,n);return r>n?n:r}(we,me,Oe):de(m?we:ye,me,m?Oe:ge);k[M]=je,V[M]=je-me}t.modifiersData[r]=V}},requiresIfExists:["offset"]};var me={name:"arrow",enabled:!0,phase:"main",fn:function(e){var t,n=e.state,r=e.name,o=e.options,i=n.elements.arrow,a=n.modifiersData.popperOffsets,s=C(n.placement),f=z(s),c=[P,L].indexOf(s)>=0?"height":"width";if(i&&a){var p=function(e,t){return Y("number"!=typeof(e="function"==typeof e?e(Object.assign({},t.rects,{placement:t.placement})):e)?e:G(e,k))}(o.padding,n),u=g(i),l="y"===f?D:P,d="y"===f?A:L,h=n.rects.reference[c]+n.rects.reference[f]-a[f]-n.rects.popper[c],m=a[f]-n.rects.reference[f],v=E(i),y=v?"y"===f?v.clientHeight||0:v.clientWidth||0:0,b=h/2-m/2,x=p[l],w=y-u[c]-p[d],O=y/2-u[c]/2+b,j=de(x,O,w),M=f;n.modifiersData[r]=((t={})[M]=j,t.centerOffset=j-O,t)}},effect:function(e){var t=e.state,n=e.options.element,r=void 0===n?"[data-popper-arrow]":n;null!=r&&("string"!=typeof r||(r=t.elements.popper.querySelector(r)))&&N(t.elements.popper,r)&&(t.elements.arrow=r)},requires:["popperOffsets"],requiresIfExists:["preventOverflow"]};function ve(e,t,n){return void 0===n&&(n={x:0,y:0}),{top:e.top-t.height-n.y,right:e.right-t.width+n.x,bottom:e.bottom-t.height+n.y,left:e.left-t.width-n.x}}function ye(e){return[D,L,A,P].some((function(t){return e[t]>=0}))}var ge={name:"hide",enabled:!0,phase:"main",requiresIfExists:["preventOverflow"],fn:function(e){var t=e.state,n=e.name,r=t.rects.reference,o=t.rects.popper,i=t.modifiersData.preventOverflow,a=J(t,{elementContext:"reference"}),s=J(t,{altBoundary:!0}),f=ve(a,r),c=ve(s,o,i),p=ye(f),u=ye(c);t.modifiersData[n]={referenceClippingOffsets:f,popperEscapeOffsets:c,isReferenceHidden:p,hasPopperEscaped:u},t.attributes.popper=Object.assign({},t.attributes.popper,{"data-popper-reference-hidden":p,"data-popper-escaped":u})}},be=Z({defaultModifiers:[ee,te,oe,ie]}),xe=[ee,te,oe,ie,ae,le,he,me,ge],we=Z({defaultModifiers:xe});e.applyStyles=ie,e.arrow=me,e.computeStyles=oe,e.createPopper=we,e.createPopperLite=be,e.defaultModifiers=xe,e.detectOverflow=J,e.eventListeners=ee,e.flip=le,e.hide=ge,e.offset=ae,e.popperGenerator=Z,e.popperOffsets=te,e.preventOverflow=he,Object.defineProperty(e,"__esModule",{value:!0})})); - diff --git a/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/uncertainty_files/libs/quarto-html/quarto-syntax-highlighting.css b/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/uncertainty_files/libs/quarto-html/quarto-syntax-highlighting.css deleted file mode 100644 index b30ce5766..000000000 --- a/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/uncertainty_files/libs/quarto-html/quarto-syntax-highlighting.css +++ /dev/null @@ -1,205 +0,0 @@ -/* quarto syntax highlight colors */ -:root { - --quarto-hl-ot-color: #003B4F; - --quarto-hl-at-color: #657422; - --quarto-hl-ss-color: #20794D; - --quarto-hl-an-color: #5E5E5E; - --quarto-hl-fu-color: #4758AB; - --quarto-hl-st-color: #20794D; - --quarto-hl-cf-color: #003B4F; - --quarto-hl-op-color: #5E5E5E; - --quarto-hl-er-color: #AD0000; - --quarto-hl-bn-color: #AD0000; - --quarto-hl-al-color: #AD0000; - --quarto-hl-va-color: #111111; - --quarto-hl-bu-color: inherit; - --quarto-hl-ex-color: inherit; - --quarto-hl-pp-color: #AD0000; - --quarto-hl-in-color: #5E5E5E; - --quarto-hl-vs-color: #20794D; - --quarto-hl-wa-color: #5E5E5E; - --quarto-hl-do-color: #5E5E5E; - --quarto-hl-im-color: #00769E; - --quarto-hl-ch-color: #20794D; - --quarto-hl-dt-color: #AD0000; - --quarto-hl-fl-color: #AD0000; - --quarto-hl-co-color: #5E5E5E; - --quarto-hl-cv-color: #5E5E5E; - --quarto-hl-cn-color: #8f5902; - --quarto-hl-sc-color: #5E5E5E; - --quarto-hl-dv-color: #AD0000; - --quarto-hl-kw-color: #003B4F; -} - -/* other quarto variables */ -:root { - --quarto-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; -} - -pre > code.sourceCode > span { - color: #003B4F; -} - -code span { - color: #003B4F; -} - -code.sourceCode > span { - color: #003B4F; -} - -div.sourceCode, -div.sourceCode pre.sourceCode { - color: #003B4F; -} - -code span.ot { - color: #003B4F; - font-style: inherit; -} - -code span.at { - color: #657422; - font-style: inherit; -} - -code span.ss { - color: #20794D; - font-style: inherit; -} - -code span.an { - color: #5E5E5E; - font-style: inherit; -} - -code span.fu { - color: #4758AB; - font-style: inherit; -} - -code span.st { - color: #20794D; - font-style: inherit; -} - -code span.cf { - color: #003B4F; - font-weight: bold; - font-style: inherit; -} - -code span.op { - color: #5E5E5E; - font-style: inherit; -} - -code span.er { - color: #AD0000; - font-style: inherit; -} - -code span.bn { - color: #AD0000; - font-style: inherit; -} - -code span.al { - color: #AD0000; - font-style: inherit; -} - -code span.va { - color: #111111; - font-style: inherit; -} - -code span.bu { - font-style: inherit; -} - -code span.ex { - font-style: inherit; -} - -code span.pp { - color: #AD0000; - font-style: inherit; -} - -code span.in { - color: #5E5E5E; - font-style: inherit; -} - -code span.vs { - color: #20794D; - font-style: inherit; -} - -code span.wa { - color: #5E5E5E; - font-style: italic; -} - -code span.do { - color: #5E5E5E; - font-style: italic; -} - -code span.im { - color: #00769E; - font-style: inherit; -} - -code span.ch { - color: #20794D; - font-style: inherit; -} - -code span.dt { - color: #AD0000; - font-style: inherit; -} - -code span.fl { - color: #AD0000; - font-style: inherit; -} - -code span.co { - color: #5E5E5E; - font-style: inherit; -} - -code span.cv { - color: #5E5E5E; - font-style: italic; -} - -code span.cn { - color: #8f5902; - font-style: inherit; -} - -code span.sc { - color: #5E5E5E; - font-style: inherit; -} - -code span.dv { - color: #AD0000; - font-style: inherit; -} - -code span.kw { - color: #003B4F; - font-weight: bold; - font-style: inherit; -} - -.prevent-inlining { - content: " { - // Find any conflicting margin elements and add margins to the - // top to prevent overlap - const marginChildren = window.document.querySelectorAll( - ".column-margin.column-container > *, .margin-caption, .aside" - ); - - let lastBottom = 0; - for (const marginChild of marginChildren) { - if (marginChild.offsetParent !== null) { - // clear the top margin so we recompute it - marginChild.style.marginTop = null; - const top = marginChild.getBoundingClientRect().top + window.scrollY; - if (top < lastBottom) { - const marginChildStyle = window.getComputedStyle(marginChild); - const marginBottom = parseFloat(marginChildStyle["marginBottom"]); - const margin = lastBottom - top + marginBottom; - marginChild.style.marginTop = `${margin}px`; - } - const styles = window.getComputedStyle(marginChild); - const marginTop = parseFloat(styles["marginTop"]); - lastBottom = top + marginChild.getBoundingClientRect().height + marginTop; - } - } -}; - -window.document.addEventListener("DOMContentLoaded", function (_event) { - // Recompute the position of margin elements anytime the body size changes - if (window.ResizeObserver) { - const resizeObserver = new window.ResizeObserver( - throttle(() => { - layoutMarginEls(); - if ( - window.document.body.getBoundingClientRect().width < 990 && - isReaderMode() - ) { - quartoToggleReader(); - } - }, 50) - ); - resizeObserver.observe(window.document.body); - } - - const tocEl = window.document.querySelector('nav.toc-active[role="doc-toc"]'); - const sidebarEl = window.document.getElementById("quarto-sidebar"); - const leftTocEl = window.document.getElementById("quarto-sidebar-toc-left"); - const marginSidebarEl = window.document.getElementById( - "quarto-margin-sidebar" - ); - // function to determine whether the element has a previous sibling that is active - const prevSiblingIsActiveLink = (el) => { - const sibling = el.previousElementSibling; - if (sibling && sibling.tagName === "A") { - return sibling.classList.contains("active"); - } else { - return false; - } - }; - - // fire slideEnter for bootstrap tab activations (for htmlwidget resize behavior) - function fireSlideEnter(e) { - const event = window.document.createEvent("Event"); - event.initEvent("slideenter", true, true); - window.document.dispatchEvent(event); - } - const tabs = window.document.querySelectorAll('a[data-bs-toggle="tab"]'); - tabs.forEach((tab) => { - tab.addEventListener("shown.bs.tab", fireSlideEnter); - }); - - // fire slideEnter for tabby tab activations (for htmlwidget resize behavior) - document.addEventListener("tabby", fireSlideEnter, false); - - // Track scrolling and mark TOC links as active - // get table of contents and sidebar (bail if we don't have at least one) - const tocLinks = tocEl - ? [...tocEl.querySelectorAll("a[data-scroll-target]")] - : []; - const makeActive = (link) => tocLinks[link].classList.add("active"); - const removeActive = (link) => tocLinks[link].classList.remove("active"); - const removeAllActive = () => - [...Array(tocLinks.length).keys()].forEach((link) => removeActive(link)); - - // activate the anchor for a section associated with this TOC entry - tocLinks.forEach((link) => { - link.addEventListener("click", () => { - if (link.href.indexOf("#") !== -1) { - const anchor = link.href.split("#")[1]; - const heading = window.document.querySelector( - `[data-anchor-id="${anchor}"]` - ); - if (heading) { - // Add the class - heading.classList.add("reveal-anchorjs-link"); - - // function to show the anchor - const handleMouseout = () => { - heading.classList.remove("reveal-anchorjs-link"); - heading.removeEventListener("mouseout", handleMouseout); - }; - - // add a function to clear the anchor when the user mouses out of it - heading.addEventListener("mouseout", handleMouseout); - } - } - }); - }); - - const sections = tocLinks.map((link) => { - const target = link.getAttribute("data-scroll-target"); - if (target.startsWith("#")) { - return window.document.getElementById(decodeURI(`${target.slice(1)}`)); - } else { - return window.document.querySelector(decodeURI(`${target}`)); - } - }); - - const sectionMargin = 200; - let currentActive = 0; - // track whether we've initialized state the first time - let init = false; - - const updateActiveLink = () => { - // The index from bottom to top (e.g. reversed list) - let sectionIndex = -1; - if ( - window.innerHeight + window.pageYOffset >= - window.document.body.offsetHeight - ) { - // This is the no-scroll case where last section should be the active one - sectionIndex = 0; - } else { - // This finds the last section visible on screen that should be made active - sectionIndex = [...sections].reverse().findIndex((section) => { - if (section) { - return window.pageYOffset >= section.offsetTop - sectionMargin; - } else { - return false; - } - }); - } - if (sectionIndex > -1) { - const current = sections.length - sectionIndex - 1; - if (current !== currentActive) { - removeAllActive(); - currentActive = current; - makeActive(current); - if (init) { - window.dispatchEvent(sectionChanged); - } - init = true; - } - } - }; - - const inHiddenRegion = (top, bottom, hiddenRegions) => { - for (const region of hiddenRegions) { - if (top <= region.bottom && bottom >= region.top) { - return true; - } - } - return false; - }; - - const categorySelector = "header.quarto-title-block .quarto-category"; - const activateCategories = (href) => { - // Find any categories - // Surround them with a link pointing back to: - // #category=Authoring - try { - const categoryEls = window.document.querySelectorAll(categorySelector); - for (const categoryEl of categoryEls) { - const categoryText = categoryEl.textContent; - if (categoryText) { - const link = `${href}#category=${encodeURIComponent(categoryText)}`; - const linkEl = window.document.createElement("a"); - linkEl.setAttribute("href", link); - for (const child of categoryEl.childNodes) { - linkEl.append(child); - } - categoryEl.appendChild(linkEl); - } - } - } catch { - // Ignore errors - } - }; - function hasTitleCategories() { - return window.document.querySelector(categorySelector) !== null; - } - - function offsetRelativeUrl(url) { - const offset = getMeta("quarto:offset"); - return offset ? offset + url : url; - } - - function offsetAbsoluteUrl(url) { - const offset = getMeta("quarto:offset"); - const baseUrl = new URL(offset, window.location); - - const projRelativeUrl = url.replace(baseUrl, ""); - if (projRelativeUrl.startsWith("/")) { - return projRelativeUrl; - } else { - return "/" + projRelativeUrl; - } - } - - // read a meta tag value - function getMeta(metaName) { - const metas = window.document.getElementsByTagName("meta"); - for (let i = 0; i < metas.length; i++) { - if (metas[i].getAttribute("name") === metaName) { - return metas[i].getAttribute("content"); - } - } - return ""; - } - - async function findAndActivateCategories() { - const currentPagePath = offsetAbsoluteUrl(window.location.href); - const response = await fetch(offsetRelativeUrl("listings.json")); - if (response.status == 200) { - return response.json().then(function (listingPaths) { - const listingHrefs = []; - for (const listingPath of listingPaths) { - const pathWithoutLeadingSlash = listingPath.listing.substring(1); - for (const item of listingPath.items) { - if ( - item === currentPagePath || - item === currentPagePath + "index.html" - ) { - // Resolve this path against the offset to be sure - // we already are using the correct path to the listing - // (this adjusts the listing urls to be rooted against - // whatever root the page is actually running against) - const relative = offsetRelativeUrl(pathWithoutLeadingSlash); - const baseUrl = window.location; - const resolvedPath = new URL(relative, baseUrl); - listingHrefs.push(resolvedPath.pathname); - break; - } - } - } - - // Look up the tree for a nearby linting and use that if we find one - const nearestListing = findNearestParentListing( - offsetAbsoluteUrl(window.location.pathname), - listingHrefs - ); - if (nearestListing) { - activateCategories(nearestListing); - } else { - // See if the referrer is a listing page for this item - const referredRelativePath = offsetAbsoluteUrl(document.referrer); - const referrerListing = listingHrefs.find((listingHref) => { - const isListingReferrer = - listingHref === referredRelativePath || - listingHref === referredRelativePath + "index.html"; - return isListingReferrer; - }); - - if (referrerListing) { - // Try to use the referrer if possible - activateCategories(referrerListing); - } else if (listingHrefs.length > 0) { - // Otherwise, just fall back to the first listing - activateCategories(listingHrefs[0]); - } - } - }); - } - } - if (hasTitleCategories()) { - findAndActivateCategories(); - } - - const findNearestParentListing = (href, listingHrefs) => { - if (!href || !listingHrefs) { - return undefined; - } - // Look up the tree for a nearby linting and use that if we find one - const relativeParts = href.substring(1).split("/"); - while (relativeParts.length > 0) { - const path = relativeParts.join("/"); - for (const listingHref of listingHrefs) { - if (listingHref.startsWith(path)) { - return listingHref; - } - } - relativeParts.pop(); - } - - return undefined; - }; - - const manageSidebarVisiblity = (el, placeholderDescriptor) => { - let isVisible = true; - let elRect; - - return (hiddenRegions) => { - if (el === null) { - return; - } - - // Find the last element of the TOC - const lastChildEl = el.lastElementChild; - - if (lastChildEl) { - // Converts the sidebar to a menu - const convertToMenu = () => { - for (const child of el.children) { - child.style.opacity = 0; - child.style.overflow = "hidden"; - child.style.pointerEvents = "none"; - } - - nexttick(() => { - const toggleContainer = window.document.createElement("div"); - toggleContainer.style.width = "100%"; - toggleContainer.classList.add("zindex-over-content"); - toggleContainer.classList.add("quarto-sidebar-toggle"); - toggleContainer.classList.add("headroom-target"); // Marks this to be managed by headeroom - toggleContainer.id = placeholderDescriptor.id; - toggleContainer.style.position = "fixed"; - - const toggleIcon = window.document.createElement("i"); - toggleIcon.classList.add("quarto-sidebar-toggle-icon"); - toggleIcon.classList.add("bi"); - toggleIcon.classList.add("bi-caret-down-fill"); - - const toggleTitle = window.document.createElement("div"); - const titleEl = window.document.body.querySelector( - placeholderDescriptor.titleSelector - ); - if (titleEl) { - toggleTitle.append( - titleEl.textContent || titleEl.innerText, - toggleIcon - ); - } - toggleTitle.classList.add("zindex-over-content"); - toggleTitle.classList.add("quarto-sidebar-toggle-title"); - toggleContainer.append(toggleTitle); - - const toggleContents = window.document.createElement("div"); - toggleContents.classList = el.classList; - toggleContents.classList.add("zindex-over-content"); - toggleContents.classList.add("quarto-sidebar-toggle-contents"); - for (const child of el.children) { - if (child.id === "toc-title") { - continue; - } - - const clone = child.cloneNode(true); - clone.style.opacity = 1; - clone.style.pointerEvents = null; - clone.style.display = null; - toggleContents.append(clone); - } - toggleContents.style.height = "0px"; - const positionToggle = () => { - // position the element (top left of parent, same width as parent) - if (!elRect) { - elRect = el.getBoundingClientRect(); - } - toggleContainer.style.left = `${elRect.left}px`; - toggleContainer.style.top = `${elRect.top}px`; - toggleContainer.style.width = `${elRect.width}px`; - }; - positionToggle(); - - toggleContainer.append(toggleContents); - el.parentElement.prepend(toggleContainer); - - // Process clicks - let tocShowing = false; - // Allow the caller to control whether this is dismissed - // when it is clicked (e.g. sidebar navigation supports - // opening and closing the nav tree, so don't dismiss on click) - const clickEl = placeholderDescriptor.dismissOnClick - ? toggleContainer - : toggleTitle; - - const closeToggle = () => { - if (tocShowing) { - toggleContainer.classList.remove("expanded"); - toggleContents.style.height = "0px"; - tocShowing = false; - } - }; - - // Get rid of any expanded toggle if the user scrolls - window.document.addEventListener( - "scroll", - throttle(() => { - closeToggle(); - }, 50) - ); - - // Handle positioning of the toggle - window.addEventListener( - "resize", - throttle(() => { - elRect = undefined; - positionToggle(); - }, 50) - ); - - window.addEventListener("quarto-hrChanged", () => { - elRect = undefined; - }); - - // Process the click - clickEl.onclick = () => { - if (!tocShowing) { - toggleContainer.classList.add("expanded"); - toggleContents.style.height = null; - tocShowing = true; - } else { - closeToggle(); - } - }; - }); - }; - - // Converts a sidebar from a menu back to a sidebar - const convertToSidebar = () => { - for (const child of el.children) { - child.style.opacity = 1; - child.style.overflow = null; - child.style.pointerEvents = null; - } - - const placeholderEl = window.document.getElementById( - placeholderDescriptor.id - ); - if (placeholderEl) { - placeholderEl.remove(); - } - - el.classList.remove("rollup"); - }; - - if (isReaderMode()) { - convertToMenu(); - isVisible = false; - } else { - // Find the top and bottom o the element that is being managed - const elTop = el.offsetTop; - const elBottom = - elTop + lastChildEl.offsetTop + lastChildEl.offsetHeight; - - if (!isVisible) { - // If the element is current not visible reveal if there are - // no conflicts with overlay regions - if (!inHiddenRegion(elTop, elBottom, hiddenRegions)) { - convertToSidebar(); - isVisible = true; - } - } else { - // If the element is visible, hide it if it conflicts with overlay regions - // and insert a placeholder toggle (or if we're in reader mode) - if (inHiddenRegion(elTop, elBottom, hiddenRegions)) { - convertToMenu(); - isVisible = false; - } - } - } - } - }; - }; - - const tabEls = document.querySelectorAll('a[data-bs-toggle="tab"]'); - for (const tabEl of tabEls) { - const id = tabEl.getAttribute("data-bs-target"); - if (id) { - const columnEl = document.querySelector( - `${id} .column-margin, .tabset-margin-content` - ); - if (columnEl) - tabEl.addEventListener("shown.bs.tab", function (event) { - const el = event.srcElement; - if (el) { - const visibleCls = `${el.id}-margin-content`; - // walk up until we find a parent tabset - let panelTabsetEl = el.parentElement; - while (panelTabsetEl) { - if (panelTabsetEl.classList.contains("panel-tabset")) { - break; - } - panelTabsetEl = panelTabsetEl.parentElement; - } - - if (panelTabsetEl) { - const prevSib = panelTabsetEl.previousElementSibling; - if ( - prevSib && - prevSib.classList.contains("tabset-margin-container") - ) { - const childNodes = prevSib.querySelectorAll( - ".tabset-margin-content" - ); - for (const childEl of childNodes) { - if (childEl.classList.contains(visibleCls)) { - childEl.classList.remove("collapse"); - } else { - childEl.classList.add("collapse"); - } - } - } - } - } - - layoutMarginEls(); - }); - } - } - - // Manage the visibility of the toc and the sidebar - const marginScrollVisibility = manageSidebarVisiblity(marginSidebarEl, { - id: "quarto-toc-toggle", - titleSelector: "#toc-title", - dismissOnClick: true, - }); - const sidebarScrollVisiblity = manageSidebarVisiblity(sidebarEl, { - id: "quarto-sidebarnav-toggle", - titleSelector: ".title", - dismissOnClick: false, - }); - let tocLeftScrollVisibility; - if (leftTocEl) { - tocLeftScrollVisibility = manageSidebarVisiblity(leftTocEl, { - id: "quarto-lefttoc-toggle", - titleSelector: "#toc-title", - dismissOnClick: true, - }); - } - - // Find the first element that uses formatting in special columns - const conflictingEls = window.document.body.querySelectorAll( - '[class^="column-"], [class*=" column-"], aside, [class*="margin-caption"], [class*=" margin-caption"], [class*="margin-ref"], [class*=" margin-ref"]' - ); - - // Filter all the possibly conflicting elements into ones - // the do conflict on the left or ride side - const arrConflictingEls = Array.from(conflictingEls); - const leftSideConflictEls = arrConflictingEls.filter((el) => { - if (el.tagName === "ASIDE") { - return false; - } - return Array.from(el.classList).find((className) => { - return ( - className !== "column-body" && - className.startsWith("column-") && - !className.endsWith("right") && - !className.endsWith("container") && - className !== "column-margin" - ); - }); - }); - const rightSideConflictEls = arrConflictingEls.filter((el) => { - if (el.tagName === "ASIDE") { - return true; - } - - const hasMarginCaption = Array.from(el.classList).find((className) => { - return className == "margin-caption"; - }); - if (hasMarginCaption) { - return true; - } - - return Array.from(el.classList).find((className) => { - return ( - className !== "column-body" && - !className.endsWith("container") && - className.startsWith("column-") && - !className.endsWith("left") - ); - }); - }); - - const kOverlapPaddingSize = 10; - function toRegions(els) { - return els.map((el) => { - const boundRect = el.getBoundingClientRect(); - const top = - boundRect.top + - document.documentElement.scrollTop - - kOverlapPaddingSize; - return { - top, - bottom: top + el.scrollHeight + 2 * kOverlapPaddingSize, - }; - }); - } - - let hasObserved = false; - const visibleItemObserver = (els) => { - let visibleElements = [...els]; - const intersectionObserver = new IntersectionObserver( - (entries, _observer) => { - entries.forEach((entry) => { - if (entry.isIntersecting) { - if (visibleElements.indexOf(entry.target) === -1) { - visibleElements.push(entry.target); - } - } else { - visibleElements = visibleElements.filter((visibleEntry) => { - return visibleEntry !== entry; - }); - } - }); - - if (!hasObserved) { - hideOverlappedSidebars(); - } - hasObserved = true; - }, - {} - ); - els.forEach((el) => { - intersectionObserver.observe(el); - }); - - return { - getVisibleEntries: () => { - return visibleElements; - }, - }; - }; - - const rightElementObserver = visibleItemObserver(rightSideConflictEls); - const leftElementObserver = visibleItemObserver(leftSideConflictEls); - - const hideOverlappedSidebars = () => { - marginScrollVisibility(toRegions(rightElementObserver.getVisibleEntries())); - sidebarScrollVisiblity(toRegions(leftElementObserver.getVisibleEntries())); - if (tocLeftScrollVisibility) { - tocLeftScrollVisibility( - toRegions(leftElementObserver.getVisibleEntries()) - ); - } - }; - - window.quartoToggleReader = () => { - // Applies a slow class (or removes it) - // to update the transition speed - const slowTransition = (slow) => { - const manageTransition = (id, slow) => { - const el = document.getElementById(id); - if (el) { - if (slow) { - el.classList.add("slow"); - } else { - el.classList.remove("slow"); - } - } - }; - - manageTransition("TOC", slow); - manageTransition("quarto-sidebar", slow); - }; - const readerMode = !isReaderMode(); - setReaderModeValue(readerMode); - - // If we're entering reader mode, slow the transition - if (readerMode) { - slowTransition(readerMode); - } - highlightReaderToggle(readerMode); - hideOverlappedSidebars(); - - // If we're exiting reader mode, restore the non-slow transition - if (!readerMode) { - slowTransition(!readerMode); - } - }; - - const highlightReaderToggle = (readerMode) => { - const els = document.querySelectorAll(".quarto-reader-toggle"); - if (els) { - els.forEach((el) => { - if (readerMode) { - el.classList.add("reader"); - } else { - el.classList.remove("reader"); - } - }); - } - }; - - const setReaderModeValue = (val) => { - if (window.location.protocol !== "file:") { - window.localStorage.setItem("quarto-reader-mode", val); - } else { - localReaderMode = val; - } - }; - - const isReaderMode = () => { - if (window.location.protocol !== "file:") { - return window.localStorage.getItem("quarto-reader-mode") === "true"; - } else { - return localReaderMode; - } - }; - let localReaderMode = null; - - const tocOpenDepthStr = tocEl?.getAttribute("data-toc-expanded"); - const tocOpenDepth = tocOpenDepthStr ? Number(tocOpenDepthStr) : 1; - - // Walk the TOC and collapse/expand nodes - // Nodes are expanded if: - // - they are top level - // - they have children that are 'active' links - // - they are directly below an link that is 'active' - const walk = (el, depth) => { - // Tick depth when we enter a UL - if (el.tagName === "UL") { - depth = depth + 1; - } - - // It this is active link - let isActiveNode = false; - if (el.tagName === "A" && el.classList.contains("active")) { - isActiveNode = true; - } - - // See if there is an active child to this element - let hasActiveChild = false; - for (child of el.children) { - hasActiveChild = walk(child, depth) || hasActiveChild; - } - - // Process the collapse state if this is an UL - if (el.tagName === "UL") { - if (tocOpenDepth === -1 && depth > 1) { - // toc-expand: false - el.classList.add("collapse"); - } else if ( - depth <= tocOpenDepth || - hasActiveChild || - prevSiblingIsActiveLink(el) - ) { - el.classList.remove("collapse"); - } else { - el.classList.add("collapse"); - } - - // untick depth when we leave a UL - depth = depth - 1; - } - return hasActiveChild || isActiveNode; - }; - - // walk the TOC and expand / collapse any items that should be shown - if (tocEl) { - updateActiveLink(); - walk(tocEl, 0); - } - - // Throttle the scroll event and walk peridiocally - window.document.addEventListener( - "scroll", - throttle(() => { - if (tocEl) { - updateActiveLink(); - walk(tocEl, 0); - } - if (!isReaderMode()) { - hideOverlappedSidebars(); - } - }, 5) - ); - window.addEventListener( - "resize", - throttle(() => { - if (tocEl) { - updateActiveLink(); - walk(tocEl, 0); - } - if (!isReaderMode()) { - hideOverlappedSidebars(); - } - }, 10) - ); - hideOverlappedSidebars(); - highlightReaderToggle(isReaderMode()); -}); - -// grouped tabsets -window.addEventListener("pageshow", (_event) => { - function getTabSettings() { - const data = localStorage.getItem("quarto-persistent-tabsets-data"); - if (!data) { - localStorage.setItem("quarto-persistent-tabsets-data", "{}"); - return {}; - } - if (data) { - return JSON.parse(data); - } - } - - function setTabSettings(data) { - localStorage.setItem( - "quarto-persistent-tabsets-data", - JSON.stringify(data) - ); - } - - function setTabState(groupName, groupValue) { - const data = getTabSettings(); - data[groupName] = groupValue; - setTabSettings(data); - } - - function toggleTab(tab, active) { - const tabPanelId = tab.getAttribute("aria-controls"); - const tabPanel = document.getElementById(tabPanelId); - if (active) { - tab.classList.add("active"); - tabPanel.classList.add("active"); - } else { - tab.classList.remove("active"); - tabPanel.classList.remove("active"); - } - } - - function toggleAll(selectedGroup, selectorsToSync) { - for (const [thisGroup, tabs] of Object.entries(selectorsToSync)) { - const active = selectedGroup === thisGroup; - for (const tab of tabs) { - toggleTab(tab, active); - } - } - } - - function findSelectorsToSyncByLanguage() { - const result = {}; - const tabs = Array.from( - document.querySelectorAll(`div[data-group] a[id^='tabset-']`) - ); - for (const item of tabs) { - const div = item.parentElement.parentElement.parentElement; - const group = div.getAttribute("data-group"); - if (!result[group]) { - result[group] = {}; - } - const selectorsToSync = result[group]; - const value = item.innerHTML; - if (!selectorsToSync[value]) { - selectorsToSync[value] = []; - } - selectorsToSync[value].push(item); - } - return result; - } - - function setupSelectorSync() { - const selectorsToSync = findSelectorsToSyncByLanguage(); - Object.entries(selectorsToSync).forEach(([group, tabSetsByValue]) => { - Object.entries(tabSetsByValue).forEach(([value, items]) => { - items.forEach((item) => { - item.addEventListener("click", (_event) => { - setTabState(group, value); - toggleAll(value, selectorsToSync[group]); - }); - }); - }); - }); - return selectorsToSync; - } - - const selectorsToSync = setupSelectorSync(); - for (const [group, selectedName] of Object.entries(getTabSettings())) { - const selectors = selectorsToSync[group]; - // it's possible that stale state gives us empty selections, so we explicitly check here. - if (selectors) { - toggleAll(selectedName, selectors); - } - } -}); - -function throttle(func, wait) { - let waiting = false; - return function () { - if (!waiting) { - func.apply(this, arguments); - waiting = true; - setTimeout(function () { - waiting = false; - }, wait); - } - }; -} - -function nexttick(func) { - return setTimeout(func, 0); -} diff --git a/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/uncertainty_files/libs/quarto-html/tippy.css b/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/uncertainty_files/libs/quarto-html/tippy.css deleted file mode 100644 index e6ae635cb..000000000 --- a/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/uncertainty_files/libs/quarto-html/tippy.css +++ /dev/null @@ -1 +0,0 @@ -.tippy-box[data-animation=fade][data-state=hidden]{opacity:0}[data-tippy-root]{max-width:calc(100vw - 10px)}.tippy-box{position:relative;background-color:#333;color:#fff;border-radius:4px;font-size:14px;line-height:1.4;white-space:normal;outline:0;transition-property:transform,visibility,opacity}.tippy-box[data-placement^=top]>.tippy-arrow{bottom:0}.tippy-box[data-placement^=top]>.tippy-arrow:before{bottom:-7px;left:0;border-width:8px 8px 0;border-top-color:initial;transform-origin:center top}.tippy-box[data-placement^=bottom]>.tippy-arrow{top:0}.tippy-box[data-placement^=bottom]>.tippy-arrow:before{top:-7px;left:0;border-width:0 8px 8px;border-bottom-color:initial;transform-origin:center bottom}.tippy-box[data-placement^=left]>.tippy-arrow{right:0}.tippy-box[data-placement^=left]>.tippy-arrow:before{border-width:8px 0 8px 8px;border-left-color:initial;right:-7px;transform-origin:center left}.tippy-box[data-placement^=right]>.tippy-arrow{left:0}.tippy-box[data-placement^=right]>.tippy-arrow:before{left:-7px;border-width:8px 8px 8px 0;border-right-color:initial;transform-origin:center right}.tippy-box[data-inertia][data-state=visible]{transition-timing-function:cubic-bezier(.54,1.5,.38,1.11)}.tippy-arrow{width:16px;height:16px;color:#333}.tippy-arrow:before{content:"";position:absolute;border-color:transparent;border-style:solid}.tippy-content{position:relative;padding:5px 9px;z-index:1} \ No newline at end of file diff --git a/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/uncertainty_files/libs/quarto-html/tippy.umd.min.js b/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/uncertainty_files/libs/quarto-html/tippy.umd.min.js deleted file mode 100644 index ca292be32..000000000 --- a/pr-3700-469d3b1a95e3fac1450966d59fefc3932d20f4fa/rendered-demo-notebooks/uncertainty_files/libs/quarto-html/tippy.umd.min.js +++ /dev/null @@ -1,2 +0,0 @@ -!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t(require("@popperjs/core")):"function"==typeof define&&define.amd?define(["@popperjs/core"],t):(e=e||self).tippy=t(e.Popper)}(this,(function(e){"use strict";var t={passive:!0,capture:!0},n=function(){return document.body};function r(e,t,n){if(Array.isArray(e)){var r=e[t];return null==r?Array.isArray(n)?n[t]:n:r}return e}function o(e,t){var n={}.toString.call(e);return 0===n.indexOf("[object")&&n.indexOf(t+"]")>-1}function i(e,t){return"function"==typeof e?e.apply(void 0,t):e}function a(e,t){return 0===t?e:function(r){clearTimeout(n),n=setTimeout((function(){e(r)}),t)};var n}function s(e,t){var n=Object.assign({},e);return t.forEach((function(e){delete n[e]})),n}function u(e){return[].concat(e)}function c(e,t){-1===e.indexOf(t)&&e.push(t)}function p(e){return e.split("-")[0]}function f(e){return[].slice.call(e)}function l(e){return Object.keys(e).reduce((function(t,n){return void 0!==e[n]&&(t[n]=e[n]),t}),{})}function d(){return document.createElement("div")}function v(e){return["Element","Fragment"].some((function(t){return o(e,t)}))}function m(e){return o(e,"MouseEvent")}function g(e){return!(!e||!e._tippy||e._tippy.reference!==e)}function h(e){return v(e)?[e]:function(e){return o(e,"NodeList")}(e)?f(e):Array.isArray(e)?e:f(document.querySelectorAll(e))}function b(e,t){e.forEach((function(e){e&&(e.style.transitionDuration=t+"ms")}))}function y(e,t){e.forEach((function(e){e&&e.setAttribute("data-state",t)}))}function w(e){var t,n=u(e)[0];return null!=n&&null!=(t=n.ownerDocument)&&t.body?n.ownerDocument:document}function E(e,t,n){var r=t+"EventListener";["transitionend","webkitTransitionEnd"].forEach((function(t){e[r](t,n)}))}function O(e,t){for(var n=t;n;){var r;if(e.contains(n))return!0;n=null==n.getRootNode||null==(r=n.getRootNode())?void 0:r.host}return!1}var x={isTouch:!1},C=0;function T(){x.isTouch||(x.isTouch=!0,window.performance&&document.addEventListener("mousemove",A))}function A(){var e=performance.now();e-C<20&&(x.isTouch=!1,document.removeEventListener("mousemove",A)),C=e}function L(){var e=document.activeElement;if(g(e)){var t=e._tippy;e.blur&&!t.state.isVisible&&e.blur()}}var D=!!("undefined"!=typeof window&&"undefined"!=typeof document)&&!!window.msCrypto,R=Object.assign({appendTo:n,aria:{content:"auto",expanded:"auto"},delay:0,duration:[300,250],getReferenceClientRect:null,hideOnClick:!0,ignoreAttributes:!1,interactive:!1,interactiveBorder:2,interactiveDebounce:0,moveTransition:"",offset:[0,10],onAfterUpdate:function(){},onBeforeUpdate:function(){},onCreate:function(){},onDestroy:function(){},onHidden:function(){},onHide:function(){},onMount:function(){},onShow:function(){},onShown:function(){},onTrigger:function(){},onUntrigger:function(){},onClickOutside:function(){},placement:"top",plugins:[],popperOptions:{},render:null,showOnCreate:!1,touch:!0,trigger:"mouseenter focus",triggerTarget:null},{animateFill:!1,followCursor:!1,inlinePositioning:!1,sticky:!1},{allowHTML:!1,animation:"fade",arrow:!0,content:"",inertia:!1,maxWidth:350,role:"tooltip",theme:"",zIndex:9999}),k=Object.keys(R);function P(e){var t=(e.plugins||[]).reduce((function(t,n){var r,o=n.name,i=n.defaultValue;o&&(t[o]=void 0!==e[o]?e[o]:null!=(r=R[o])?r:i);return t}),{});return Object.assign({},e,t)}function j(e,t){var n=Object.assign({},t,{content:i(t.content,[e])},t.ignoreAttributes?{}:function(e,t){return(t?Object.keys(P(Object.assign({},R,{plugins:t}))):k).reduce((function(t,n){var r=(e.getAttribute("data-tippy-"+n)||"").trim();if(!r)return t;if("content"===n)t[n]=r;else try{t[n]=JSON.parse(r)}catch(e){t[n]=r}return t}),{})}(e,t.plugins));return n.aria=Object.assign({},R.aria,n.aria),n.aria={expanded:"auto"===n.aria.expanded?t.interactive:n.aria.expanded,content:"auto"===n.aria.content?t.interactive?null:"describedby":n.aria.content},n}function M(e,t){e.innerHTML=t}function V(e){var t=d();return!0===e?t.className="tippy-arrow":(t.className="tippy-svg-arrow",v(e)?t.appendChild(e):M(t,e)),t}function I(e,t){v(t.content)?(M(e,""),e.appendChild(t.content)):"function"!=typeof t.content&&(t.allowHTML?M(e,t.content):e.textContent=t.content)}function S(e){var t=e.firstElementChild,n=f(t.children);return{box:t,content:n.find((function(e){return e.classList.contains("tippy-content")})),arrow:n.find((function(e){return e.classList.contains("tippy-arrow")||e.classList.contains("tippy-svg-arrow")})),backdrop:n.find((function(e){return e.classList.contains("tippy-backdrop")}))}}function N(e){var t=d(),n=d();n.className="tippy-box",n.setAttribute("data-state","hidden"),n.setAttribute("tabindex","-1");var r=d();function o(n,r){var o=S(t),i=o.box,a=o.content,s=o.arrow;r.theme?i.setAttribute("data-theme",r.theme):i.removeAttribute("data-theme"),"string"==typeof r.animation?i.setAttribute("data-animation",r.animation):i.removeAttribute("data-animation"),r.inertia?i.setAttribute("data-inertia",""):i.removeAttribute("data-inertia"),i.style.maxWidth="number"==typeof r.maxWidth?r.maxWidth+"px":r.maxWidth,r.role?i.setAttribute("role",r.role):i.removeAttribute("role"),n.content===r.content&&n.allowHTML===r.allowHTML||I(a,e.props),r.arrow?s?n.arrow!==r.arrow&&(i.removeChild(s),i.appendChild(V(r.arrow))):i.appendChild(V(r.arrow)):s&&i.removeChild(s)}return r.className="tippy-content",r.setAttribute("data-state","hidden"),I(r,e.props),t.appendChild(n),n.appendChild(r),o(e.props,e.props),{popper:t,onUpdate:o}}N.$$tippy=!0;var B=1,H=[],U=[];function _(o,s){var v,g,h,C,T,A,L,k,M=j(o,Object.assign({},R,P(l(s)))),V=!1,I=!1,N=!1,_=!1,F=[],W=a(we,M.interactiveDebounce),X=B++,Y=(k=M.plugins).filter((function(e,t){return k.indexOf(e)===t})),$={id:X,reference:o,popper:d(),popperInstance:null,props:M,state:{isEnabled:!0,isVisible:!1,isDestroyed:!1,isMounted:!1,isShown:!1},plugins:Y,clearDelayTimeouts:function(){clearTimeout(v),clearTimeout(g),cancelAnimationFrame(h)},setProps:function(e){if($.state.isDestroyed)return;ae("onBeforeUpdate",[$,e]),be();var t=$.props,n=j(o,Object.assign({},t,l(e),{ignoreAttributes:!0}));$.props=n,he(),t.interactiveDebounce!==n.interactiveDebounce&&(ce(),W=a(we,n.interactiveDebounce));t.triggerTarget&&!n.triggerTarget?u(t.triggerTarget).forEach((function(e){e.removeAttribute("aria-expanded")})):n.triggerTarget&&o.removeAttribute("aria-expanded");ue(),ie(),J&&J(t,n);$.popperInstance&&(Ce(),Ae().forEach((function(e){requestAnimationFrame(e._tippy.popperInstance.forceUpdate)})));ae("onAfterUpdate",[$,e])},setContent:function(e){$.setProps({content:e})},show:function(){var e=$.state.isVisible,t=$.state.isDestroyed,o=!$.state.isEnabled,a=x.isTouch&&!$.props.touch,s=r($.props.duration,0,R.duration);if(e||t||o||a)return;if(te().hasAttribute("disabled"))return;if(ae("onShow",[$],!1),!1===$.props.onShow($))return;$.state.isVisible=!0,ee()&&(z.style.visibility="visible");ie(),de(),$.state.isMounted||(z.style.transition="none");if(ee()){var u=re(),p=u.box,f=u.content;b([p,f],0)}A=function(){var e;if($.state.isVisible&&!_){if(_=!0,z.offsetHeight,z.style.transition=$.props.moveTransition,ee()&&$.props.animation){var t=re(),n=t.box,r=t.content;b([n,r],s),y([n,r],"visible")}se(),ue(),c(U,$),null==(e=$.popperInstance)||e.forceUpdate(),ae("onMount",[$]),$.props.animation&&ee()&&function(e,t){me(e,t)}(s,(function(){$.state.isShown=!0,ae("onShown",[$])}))}},function(){var e,t=$.props.appendTo,r=te();e=$.props.interactive&&t===n||"parent"===t?r.parentNode:i(t,[r]);e.contains(z)||e.appendChild(z);$.state.isMounted=!0,Ce()}()},hide:function(){var e=!$.state.isVisible,t=$.state.isDestroyed,n=!$.state.isEnabled,o=r($.props.duration,1,R.duration);if(e||t||n)return;if(ae("onHide",[$],!1),!1===$.props.onHide($))return;$.state.isVisible=!1,$.state.isShown=!1,_=!1,V=!1,ee()&&(z.style.visibility="hidden");if(ce(),ve(),ie(!0),ee()){var i=re(),a=i.box,s=i.content;$.props.animation&&(b([a,s],o),y([a,s],"hidden"))}se(),ue(),$.props.animation?ee()&&function(e,t){me(e,(function(){!$.state.isVisible&&z.parentNode&&z.parentNode.contains(z)&&t()}))}(o,$.unmount):$.unmount()},hideWithInteractivity:function(e){ne().addEventListener("mousemove",W),c(H,W),W(e)},enable:function(){$.state.isEnabled=!0},disable:function(){$.hide(),$.state.isEnabled=!1},unmount:function(){$.state.isVisible&&$.hide();if(!$.state.isMounted)return;Te(),Ae().forEach((function(e){e._tippy.unmount()})),z.parentNode&&z.parentNode.removeChild(z);U=U.filter((function(e){return e!==$})),$.state.isMounted=!1,ae("onHidden",[$])},destroy:function(){if($.state.isDestroyed)return;$.clearDelayTimeouts(),$.unmount(),be(),delete o._tippy,$.state.isDestroyed=!0,ae("onDestroy",[$])}};if(!M.render)return $;var q=M.render($),z=q.popper,J=q.onUpdate;z.setAttribute("data-tippy-root",""),z.id="tippy-"+$.id,$.popper=z,o._tippy=$,z._tippy=$;var G=Y.map((function(e){return e.fn($)})),K=o.hasAttribute("aria-expanded");return he(),ue(),ie(),ae("onCreate",[$]),M.showOnCreate&&Le(),z.addEventListener("mouseenter",(function(){$.props.interactive&&$.state.isVisible&&$.clearDelayTimeouts()})),z.addEventListener("mouseleave",(function(){$.props.interactive&&$.props.trigger.indexOf("mouseenter")>=0&&ne().addEventListener("mousemove",W)})),$;function Q(){var e=$.props.touch;return Array.isArray(e)?e:[e,0]}function Z(){return"hold"===Q()[0]}function ee(){var e;return!(null==(e=$.props.render)||!e.$$tippy)}function te(){return L||o}function ne(){var e=te().parentNode;return e?w(e):document}function re(){return S(z)}function oe(e){return $.state.isMounted&&!$.state.isVisible||x.isTouch||C&&"focus"===C.type?0:r($.props.delay,e?0:1,R.delay)}function ie(e){void 0===e&&(e=!1),z.style.pointerEvents=$.props.interactive&&!e?"":"none",z.style.zIndex=""+$.props.zIndex}function ae(e,t,n){var r;(void 0===n&&(n=!0),G.forEach((function(n){n[e]&&n[e].apply(n,t)})),n)&&(r=$.props)[e].apply(r,t)}function se(){var e=$.props.aria;if(e.content){var t="aria-"+e.content,n=z.id;u($.props.triggerTarget||o).forEach((function(e){var r=e.getAttribute(t);if($.state.isVisible)e.setAttribute(t,r?r+" "+n:n);else{var o=r&&r.replace(n,"").trim();o?e.setAttribute(t,o):e.removeAttribute(t)}}))}}function ue(){!K&&$.props.aria.expanded&&u($.props.triggerTarget||o).forEach((function(e){$.props.interactive?e.setAttribute("aria-expanded",$.state.isVisible&&e===te()?"true":"false"):e.removeAttribute("aria-expanded")}))}function ce(){ne().removeEventListener("mousemove",W),H=H.filter((function(e){return e!==W}))}function pe(e){if(!x.isTouch||!N&&"mousedown"!==e.type){var t=e.composedPath&&e.composedPath()[0]||e.target;if(!$.props.interactive||!O(z,t)){if(u($.props.triggerTarget||o).some((function(e){return O(e,t)}))){if(x.isTouch)return;if($.state.isVisible&&$.props.trigger.indexOf("click")>=0)return}else ae("onClickOutside",[$,e]);!0===$.props.hideOnClick&&($.clearDelayTimeouts(),$.hide(),I=!0,setTimeout((function(){I=!1})),$.state.isMounted||ve())}}}function fe(){N=!0}function le(){N=!1}function de(){var e=ne();e.addEventListener("mousedown",pe,!0),e.addEventListener("touchend",pe,t),e.addEventListener("touchstart",le,t),e.addEventListener("touchmove",fe,t)}function ve(){var e=ne();e.removeEventListener("mousedown",pe,!0),e.removeEventListener("touchend",pe,t),e.removeEventListener("touchstart",le,t),e.removeEventListener("touchmove",fe,t)}function me(e,t){var n=re().box;function r(e){e.target===n&&(E(n,"remove",r),t())}if(0===e)return t();E(n,"remove",T),E(n,"add",r),T=r}function ge(e,t,n){void 0===n&&(n=!1),u($.props.triggerTarget||o).forEach((function(r){r.addEventListener(e,t,n),F.push({node:r,eventType:e,handler:t,options:n})}))}function he(){var e;Z()&&(ge("touchstart",ye,{passive:!0}),ge("touchend",Ee,{passive:!0})),(e=$.props.trigger,e.split(/\s+/).filter(Boolean)).forEach((function(e){if("manual"!==e)switch(ge(e,ye),e){case"mouseenter":ge("mouseleave",Ee);break;case"focus":ge(D?"focusout":"blur",Oe);break;case"focusin":ge("focusout",Oe)}}))}function be(){F.forEach((function(e){var t=e.node,n=e.eventType,r=e.handler,o=e.options;t.removeEventListener(n,r,o)})),F=[]}function ye(e){var t,n=!1;if($.state.isEnabled&&!xe(e)&&!I){var r="focus"===(null==(t=C)?void 0:t.type);C=e,L=e.currentTarget,ue(),!$.state.isVisible&&m(e)&&H.forEach((function(t){return t(e)})),"click"===e.type&&($.props.trigger.indexOf("mouseenter")<0||V)&&!1!==$.props.hideOnClick&&$.state.isVisible?n=!0:Le(e),"click"===e.type&&(V=!n),n&&!r&&De(e)}}function we(e){var t=e.target,n=te().contains(t)||z.contains(t);"mousemove"===e.type&&n||function(e,t){var n=t.clientX,r=t.clientY;return e.every((function(e){var t=e.popperRect,o=e.popperState,i=e.props.interactiveBorder,a=p(o.placement),s=o.modifiersData.offset;if(!s)return!0;var u="bottom"===a?s.top.y:0,c="top"===a?s.bottom.y:0,f="right"===a?s.left.x:0,l="left"===a?s.right.x:0,d=t.top-r+u>i,v=r-t.bottom-c>i,m=t.left-n+f>i,g=n-t.right-l>i;return d||v||m||g}))}(Ae().concat(z).map((function(e){var t,n=null==(t=e._tippy.popperInstance)?void 0:t.state;return n?{popperRect:e.getBoundingClientRect(),popperState:n,props:M}:null})).filter(Boolean),e)&&(ce(),De(e))}function Ee(e){xe(e)||$.props.trigger.indexOf("click")>=0&&V||($.props.interactive?$.hideWithInteractivity(e):De(e))}function Oe(e){$.props.trigger.indexOf("focusin")<0&&e.target!==te()||$.props.interactive&&e.relatedTarget&&z.contains(e.relatedTarget)||De(e)}function xe(e){return!!x.isTouch&&Z()!==e.type.indexOf("touch")>=0}function Ce(){Te();var t=$.props,n=t.popperOptions,r=t.placement,i=t.offset,a=t.getReferenceClientRect,s=t.moveTransition,u=ee()?S(z).arrow:null,c=a?{getBoundingClientRect:a,contextElement:a.contextElement||te()}:o,p=[{name:"offset",options:{offset:i}},{name:"preventOverflow",options:{padding:{top:2,bottom:2,left:5,right:5}}},{name:"flip",options:{padding:5}},{name:"computeStyles",options:{adaptive:!s}},{name:"$$tippy",enabled:!0,phase:"beforeWrite",requires:["computeStyles"],fn:function(e){var t=e.state;if(ee()){var n=re().box;["placement","reference-hidden","escaped"].forEach((function(e){"placement"===e?n.setAttribute("data-placement",t.placement):t.attributes.popper["data-popper-"+e]?n.setAttribute("data-"+e,""):n.removeAttribute("data-"+e)})),t.attributes.popper={}}}}];ee()&&u&&p.push({name:"arrow",options:{element:u,padding:3}}),p.push.apply(p,(null==n?void 0:n.modifiers)||[]),$.popperInstance=e.createPopper(c,z,Object.assign({},n,{placement:r,onFirstUpdate:A,modifiers:p}))}function Te(){$.popperInstance&&($.popperInstance.destroy(),$.popperInstance=null)}function Ae(){return f(z.querySelectorAll("[data-tippy-root]"))}function Le(e){$.clearDelayTimeouts(),e&&ae("onTrigger",[$,e]),de();var t=oe(!0),n=Q(),r=n[0],o=n[1];x.isTouch&&"hold"===r&&o&&(t=o),t?v=setTimeout((function(){$.show()}),t):$.show()}function De(e){if($.clearDelayTimeouts(),ae("onUntrigger",[$,e]),$.state.isVisible){if(!($.props.trigger.indexOf("mouseenter")>=0&&$.props.trigger.indexOf("click")>=0&&["mouseleave","mousemove"].indexOf(e.type)>=0&&V)){var t=oe(!1);t?g=setTimeout((function(){$.state.isVisible&&$.hide()}),t):h=requestAnimationFrame((function(){$.hide()}))}}else ve()}}function F(e,n){void 0===n&&(n={});var r=R.plugins.concat(n.plugins||[]);document.addEventListener("touchstart",T,t),window.addEventListener("blur",L);var o=Object.assign({},n,{plugins:r}),i=h(e).reduce((function(e,t){var n=t&&_(t,o);return n&&e.push(n),e}),[]);return v(e)?i[0]:i}F.defaultProps=R,F.setDefaultProps=function(e){Object.keys(e).forEach((function(t){R[t]=e[t]}))},F.currentInput=x;var W=Object.assign({},e.applyStyles,{effect:function(e){var t=e.state,n={popper:{position:t.options.strategy,left:"0",top:"0",margin:"0"},arrow:{position:"absolute"},reference:{}};Object.assign(t.elements.popper.style,n.popper),t.styles=n,t.elements.arrow&&Object.assign(t.elements.arrow.style,n.arrow)}}),X={mouseover:"mouseenter",focusin:"focus",click:"click"};var Y={name:"animateFill",defaultValue:!1,fn:function(e){var t;if(null==(t=e.props.render)||!t.$$tippy)return{};var n=S(e.popper),r=n.box,o=n.content,i=e.props.animateFill?function(){var e=d();return e.className="tippy-backdrop",y([e],"hidden"),e}():null;return{onCreate:function(){i&&(r.insertBefore(i,r.firstElementChild),r.setAttribute("data-animatefill",""),r.style.overflow="hidden",e.setProps({arrow:!1,animation:"shift-away"}))},onMount:function(){if(i){var e=r.style.transitionDuration,t=Number(e.replace("ms",""));o.style.transitionDelay=Math.round(t/10)+"ms",i.style.transitionDuration=e,y([i],"visible")}},onShow:function(){i&&(i.style.transitionDuration="0ms")},onHide:function(){i&&y([i],"hidden")}}}};var $={clientX:0,clientY:0},q=[];function z(e){var t=e.clientX,n=e.clientY;$={clientX:t,clientY:n}}var J={name:"followCursor",defaultValue:!1,fn:function(e){var t=e.reference,n=w(e.props.triggerTarget||t),r=!1,o=!1,i=!0,a=e.props;function s(){return"initial"===e.props.followCursor&&e.state.isVisible}function u(){n.addEventListener("mousemove",f)}function c(){n.removeEventListener("mousemove",f)}function p(){r=!0,e.setProps({getReferenceClientRect:null}),r=!1}function f(n){var r=!n.target||t.contains(n.target),o=e.props.followCursor,i=n.clientX,a=n.clientY,s=t.getBoundingClientRect(),u=i-s.left,c=a-s.top;!r&&e.props.interactive||e.setProps({getReferenceClientRect:function(){var e=t.getBoundingClientRect(),n=i,r=a;"initial"===o&&(n=e.left+u,r=e.top+c);var s="horizontal"===o?e.top:r,p="vertical"===o?e.right:n,f="horizontal"===o?e.bottom:r,l="vertical"===o?e.left:n;return{width:p-l,height:f-s,top:s,right:p,bottom:f,left:l}}})}function l(){e.props.followCursor&&(q.push({instance:e,doc:n}),function(e){e.addEventListener("mousemove",z)}(n))}function d(){0===(q=q.filter((function(t){return t.instance!==e}))).filter((function(e){return e.doc===n})).length&&function(e){e.removeEventListener("mousemove",z)}(n)}return{onCreate:l,onDestroy:d,onBeforeUpdate:function(){a=e.props},onAfterUpdate:function(t,n){var i=n.followCursor;r||void 0!==i&&a.followCursor!==i&&(d(),i?(l(),!e.state.isMounted||o||s()||u()):(c(),p()))},onMount:function(){e.props.followCursor&&!o&&(i&&(f($),i=!1),s()||u())},onTrigger:function(e,t){m(t)&&($={clientX:t.clientX,clientY:t.clientY}),o="focus"===t.type},onHidden:function(){e.props.followCursor&&(p(),c(),i=!0)}}}};var G={name:"inlinePositioning",defaultValue:!1,fn:function(e){var t,n=e.reference;var r=-1,o=!1,i=[],a={name:"tippyInlinePositioning",enabled:!0,phase:"afterWrite",fn:function(o){var a=o.state;e.props.inlinePositioning&&(-1!==i.indexOf(a.placement)&&(i=[]),t!==a.placement&&-1===i.indexOf(a.placement)&&(i.push(a.placement),e.setProps({getReferenceClientRect:function(){return function(e){return function(e,t,n,r){if(n.length<2||null===e)return t;if(2===n.length&&r>=0&&n[0].left>n[1].right)return n[r]||t;switch(e){case"top":case"bottom":var o=n[0],i=n[n.length-1],a="top"===e,s=o.top,u=i.bottom,c=a?o.left:i.left,p=a?o.right:i.right;return{top:s,bottom:u,left:c,right:p,width:p-c,height:u-s};case"left":case"right":var f=Math.min.apply(Math,n.map((function(e){return e.left}))),l=Math.max.apply(Math,n.map((function(e){return e.right}))),d=n.filter((function(t){return"left"===e?t.left===f:t.right===l})),v=d[0].top,m=d[d.length-1].bottom;return{top:v,bottom:m,left:f,right:l,width:l-f,height:m-v};default:return t}}(p(e),n.getBoundingClientRect(),f(n.getClientRects()),r)}(a.placement)}})),t=a.placement)}};function s(){var t;o||(t=function(e,t){var n;return{popperOptions:Object.assign({},e.popperOptions,{modifiers:[].concat(((null==(n=e.popperOptions)?void 0:n.modifiers)||[]).filter((function(e){return e.name!==t.name})),[t])})}}(e.props,a),o=!0,e.setProps(t),o=!1)}return{onCreate:s,onAfterUpdate:s,onTrigger:function(t,n){if(m(n)){var o=f(e.reference.getClientRects()),i=o.find((function(e){return e.left-2<=n.clientX&&e.right+2>=n.clientX&&e.top-2<=n.clientY&&e.bottom+2>=n.clientY})),a=o.indexOf(i);r=a>-1?a:r}},onHidden:function(){r=-1}}}};var K={name:"sticky",defaultValue:!1,fn:function(e){var t=e.reference,n=e.popper;function r(t){return!0===e.props.sticky||e.props.sticky===t}var o=null,i=null;function a(){var s=r("reference")?(e.popperInstance?e.popperInstance.state.elements.reference:t).getBoundingClientRect():null,u=r("popper")?n.getBoundingClientRect():null;(s&&Q(o,s)||u&&Q(i,u))&&e.popperInstance&&e.popperInstance.update(),o=s,i=u,e.state.isMounted&&requestAnimationFrame(a)}return{onMount:function(){e.props.sticky&&a()}}}};function Q(e,t){return!e||!t||(e.top!==t.top||e.right!==t.right||e.bottom!==t.bottom||e.left!==t.left)}return F.setDefaultProps({plugins:[Y,J,G,K],render:N}),F.createSingleton=function(e,t){var n;void 0===t&&(t={});var r,o=e,i=[],a=[],c=t.overrides,p=[],f=!1;function l(){a=o.map((function(e){return u(e.props.triggerTarget||e.reference)})).reduce((function(e,t){return e.concat(t)}),[])}function v(){i=o.map((function(e){return e.reference}))}function m(e){o.forEach((function(t){e?t.enable():t.disable()}))}function g(e){return o.map((function(t){var n=t.setProps;return t.setProps=function(o){n(o),t.reference===r&&e.setProps(o)},function(){t.setProps=n}}))}function h(e,t){var n=a.indexOf(t);if(t!==r){r=t;var s=(c||[]).concat("content").reduce((function(e,t){return e[t]=o[n].props[t],e}),{});e.setProps(Object.assign({},s,{getReferenceClientRect:"function"==typeof s.getReferenceClientRect?s.getReferenceClientRect:function(){var e;return null==(e=i[n])?void 0:e.getBoundingClientRect()}}))}}m(!1),v(),l();var b={fn:function(){return{onDestroy:function(){m(!0)},onHidden:function(){r=null},onClickOutside:function(e){e.props.showOnCreate&&!f&&(f=!0,r=null)},onShow:function(e){e.props.showOnCreate&&!f&&(f=!0,h(e,i[0]))},onTrigger:function(e,t){h(e,t.currentTarget)}}}},y=F(d(),Object.assign({},s(t,["overrides"]),{plugins:[b].concat(t.plugins||[]),triggerTarget:a,popperOptions:Object.assign({},t.popperOptions,{modifiers:[].concat((null==(n=t.popperOptions)?void 0:n.modifiers)||[],[W])})})),w=y.show;y.show=function(e){if(w(),!r&&null==e)return h(y,i[0]);if(!r||null!=e){if("number"==typeof e)return i[e]&&h(y,i[e]);if(o.indexOf(e)>=0){var t=e.reference;return h(y,t)}return i.indexOf(e)>=0?h(y,e):void 0}},y.showNext=function(){var e=i[0];if(!r)return y.show(0);var t=i.indexOf(r);y.show(i[t+1]||e)},y.showPrevious=function(){var e=i[i.length-1];if(!r)return y.show(e);var t=i.indexOf(r),n=i[t-1]||e;y.show(n)};var E=y.setProps;return y.setProps=function(e){c=e.overrides||c,E(e)},y.setInstances=function(e){m(!0),p.forEach((function(e){return e()})),o=e,m(!1),v(),l(),p=g(y),y.setProps({triggerTarget:a})},p=g(y),y},F.delegate=function(e,n){var r=[],o=[],i=!1,a=n.target,c=s(n,["target"]),p=Object.assign({},c,{trigger:"manual",touch:!1}),f=Object.assign({touch:R.touch},c,{showOnCreate:!0}),l=F(e,p);function d(e){if(e.target&&!i){var t=e.target.closest(a);if(t){var r=t.getAttribute("data-tippy-trigger")||n.trigger||R.trigger;if(!t._tippy&&!("touchstart"===e.type&&"boolean"==typeof f.touch||"touchstart"!==e.type&&r.indexOf(X[e.type])<0)){var s=F(t,f);s&&(o=o.concat(s))}}}}function v(e,t,n,o){void 0===o&&(o=!1),e.addEventListener(t,n,o),r.push({node:e,eventType:t,handler:n,options:o})}return u(l).forEach((function(e){var n=e.destroy,a=e.enable,s=e.disable;e.destroy=function(e){void 0===e&&(e=!0),e&&o.forEach((function(e){e.destroy()})),o=[],r.forEach((function(e){var t=e.node,n=e.eventType,r=e.handler,o=e.options;t.removeEventListener(n,r,o)})),r=[],n()},e.enable=function(){a(),o.forEach((function(e){return e.enable()})),i=!1},e.disable=function(){s(),o.forEach((function(e){return e.disable()})),i=!0},function(e){var n=e.reference;v(n,"touchstart",d,t),v(n,"mouseover",d),v(n,"focusin",d),v(n,"click",d)}(e)})),l},F.hideAll=function(e){var t=void 0===e?{}:e,n=t.exclude,r=t.duration;U.forEach((function(e){var t=!1;if(n&&(t=g(n)?e.reference===n:e.popper===n.popper),!t){var o=e.props.duration;e.setProps({duration:r}),e.hide(),e.state.isDestroyed||e.setProps({duration:o})}}))},F.roundArrow='',F})); - diff --git a/tutorials/01_Demo_Basic_Run/execstatus.jpg b/tutorials/01_Demo_Basic_Run/execstatus.jpg deleted file mode 100644 index ebf7c2e67..000000000 Binary files a/tutorials/01_Demo_Basic_Run/execstatus.jpg and /dev/null differ diff --git a/tutorials/01_Demo_Basic_Run/mapmodel.png b/tutorials/01_Demo_Basic_Run/mapmodel.png deleted file mode 100644 index 505cb02cb..000000000 Binary files a/tutorials/01_Demo_Basic_Run/mapmodel.png and /dev/null differ diff --git a/tutorials/01_Demo_Basic_Run/runspec.png b/tutorials/01_Demo_Basic_Run/runspec.png deleted file mode 100644 index 8b7069692..000000000 Binary files a/tutorials/01_Demo_Basic_Run/runspec.png and /dev/null differ diff --git a/tutorials/01_Demo_Basic_Run/startpecan.jpg b/tutorials/01_Demo_Basic_Run/startpecan.jpg deleted file mode 100644 index 6428f668e..000000000 Binary files a/tutorials/01_Demo_Basic_Run/startpecan.jpg and /dev/null differ diff --git a/tutorials/01_Demo_Basic_Run/workflowshiny.png b/tutorials/01_Demo_Basic_Run/workflowshiny.png deleted file mode 100644 index f591a69b9..000000000 Binary files a/tutorials/01_Demo_Basic_Run/workflowshiny.png and /dev/null differ diff --git a/tutorials/Demo01.html b/tutorials/Demo01.html deleted file mode 100644 index 6c1a3e782..000000000 --- a/tutorials/Demo01.html +++ /dev/null @@ -1,589 +0,0 @@ - - - - - - - - - - - - - -Demo01.utf8 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - -
-

Demo 01: Basic Run PEcAn

-
-

Objective

-

We will begin by exploring a set of web-based tools that are designed to run single-site model runs. A lot of the detail about what’s going on under the hood, and all the outputs that PEcAn produces, are left to Demo 2. This demo will also demonstrate how to use PEcAn outputs in additional analyses outside of PEcAn.

-
-
-

PEcAn URL

-

In the following demo, URL is the web address of a PEcAn server and will refer to one of the following:

-
    -
  • If you are doing a live demo with the PEcAn team, URL was provided
  • -
  • If you are running the PEcAn virtual machine: URL = localhost:6480
  • -
  • If you are running PEcAn using Amazon Web Services (AWS), URL is the Public IP
  • -
  • If you are running PEcAn using Docker, URL is localhost:8000/pecan/ (trailing backslash is important!)
  • -
  • If you followed instructions found in [Install PEcAn by hand], URL is your server’s IP
  • -
-
-
-

Start PEcAn:

-
    -
  1. Enter URL in your web browser
  2. -
  3. Click “Run Models”
  4. -
  5. Click the ‘Next’ button to move to the “Site Selection” page.
  6. -
-

-
-
-

Site Selection

-

-
-
-

Host

-

Select the local machine “pecan”. Other options exist if you’ve read and followed instructions found in [Remote execution with PEcAn].

-
-
-

Mode

-

Select SIPNET (r136) from the available models because it is quick & simple. Reference material can be found in [Models in PEcAn]

-
-
-

Site Group

-

To filter sites, you can select a specific group of sites. For this tutorial we will use Ameriflux.

-
-
-

Conversion:

-

Select the conversion check box, to show all sites that PEcAn is capable of generating model drivers for automatically. By default (unchecked), PEcAn only displays sites where model drivers already exist in the system database

-
-
-

Site:

-

For this tutorial, type US-NR1 in the search box to display the Niwot Ridge Ameriflux site (US-NR1), and then click on the pin icon. When you click on a site’s flag on the map, it will give you the name and location of the site and put that site in the “Site:” box on the left hand site, indicating your current selection.

-

Once you are finished with the above steps, click “Next”.

-
-
-

Run Specification

-

-

Next we will specify settings required to run the model. Be aware that the inputs required for any particular model may vary somewhat so there may be addition optional or required input selections available for other models.

-
-
-

PFT (Plant Functional Type):

-

Niwot Ridge is temperate coniferous. Available PFTs will vary by model and some models allow multiple competing PFTs to be selected. Also select soil to control the soil parameters

-
-
-

Start/End Date:

-

Select 2003/01/01 to 2006/12/31. In general, be careful to select dates for which there is available driver data.

-
-
-

Weather Data:

-

Select “Use AmerifluxLBL” from the [Available Meteorological Drivers].

-
-
-

Optional Settings:

-

Leave all blank for demo run

-
    -
  1. Email sends a message when the run is complete.
  2. -
  3. Use Brown Dog will use the Brown Dog web services in order to do input file conversions. (Note: Required if you select Use NARR for Weather Data)
  4. -
  5. Edit pecan.xml allows you to configure advanced settings via the PEcAn settings file
  6. -
  7. Edit model config pauses the workflow after PEcAn has written all model specific settings but before the model runs are called and allows users to configure any additional settings internal to the model.
  8. -
  9. Advanced Setup controls ensemble and sensitivity run settings discussed in Demo 2.
  10. -
-

Finally, click “Next” to start the model run.

-
-
-

Data Use Policies

-

The last step before the run starts is to read and agree to AmeriFlux’s data policy and give a valid username. If you don’t already have an Ameriflux username, click “register here” and create one. If you selected a different data source, this step may or may not be needed: you will need to agree to a data policy if your source has one, but if it doesn’t then the run will start immediately.

-
-
-

If you get an error in your run

-

If you get an error in your run as part of a live demo or class activity, it is probably simplest to start over and try changing options and re-running (e.g. with a different site or PFT), as time does not permit detailed debugging. If the source of the error is not immediately obvious, you may want to take a look at the workflow.Rout to see the log of the PEcAn workflow or the logfile.txt to see the model execution output log and then refer to the Documentation or the Chat Room for help.

-
-
-

Model Run Workflow

-

-
-
-

MET Process:

-

First, PEcAn will download meteorological data based on the type of the Weather Data you chose, and process it into the specific format for the chosen model

-
-
-

TRAIT / META:

-

PEcAn then estimates model parameters by performing a meta-analysis of the available trait data for a PFT. TRAIT will extract relevant trait data from the database. META performs a hierarchical Bayes meta-analysis of available trait data. The output of this analysis is a probability distribution for each model parameter. PEcAn selects the median value of this parameter as the default, but in Demo 2 we will see how PEcAn can use this parameter uncertainty to make probabilistic forecasts and assess model sensitivity and uncertainty. Errors at this stage usually indicate errors in the trait database or incorrectly specified PFTs (e.g. defining a variable twice).

-
-
-

CONFIG:

-

writes model-specific settings and parameter files

-
-
-

MODEL:

-

runs model.

-
-
-

OUTPUT:

-

All model outputs are converted to standard netCDF format

-
-
-

ENSEMBLE & SENSITIVITY:

-

If enabled post-process output for these analyses

-

If at any point a Stage Name has the Status “ERROR” please notify the PEcAn team member that is administering the demo or feel free to do any of the following:

-
    -
  • Refer to the PEcAn Documentation for documentation
  • -
  • Post the end of your workflow log on our Slack Channel chat
  • -
  • Post an issue on Github.
  • -
-

The entire PEcAn team welcomes any questions you may have!

-

If the Finished Stage has a Status of “DONE”, congratulations! If you got this far, you have managed to run an ecosystem model without ever touching a line of code! Now it’s time to look at the results click Finished.

-

FYI, adding a new model to PEcAn does not require modification of the model’s code, just the implementation of a wrapper function.

-
-
-

Output and Visualization

-

For now focus on graphs, we will explore all of PEcAn’s outputs in more detail in Demo 02.

-
-
-

Graphs

-
    -
  1. Select a Year and Y-axis Variable, and then click ‘Plot run/year/variable’. Initially leave the X-axis as time.
  2. -
  3. Within this figure the points indicate the daily mean for the variable while the envelope encompasses the diurnal variability (max and min).
  4. -
  5. Variable names and units are based on a standard netCDF format.
  6. -
  7. Try looking at a number of different output variables over different years.
  8. -
  9. Try changing the X-axis to look at bivariate plots of how different output variables are related to one another. Be aware that PEcAn currently runs a moving min/mean/max through bivariate plots, just as it does with time series plots. In some cases this makes more sense than others.
  10. -
-
-
-

Alternative Visualization: R Shiny

-
    -
  1. Click on Open SHINY, which will open a new browser window. The shiny app will automatically access your run’s output files and allow you to visualize all output variables as a function of time.
  2. -
-

-
    -
  1. Use the pull down menu under Variable Name to choose whichever output variable you wish to plot.
  2. -
-
-
-

Model Run Archive

-

Return to the output window and Click on the HISTORY button. Click on any previous run in the “ID” column to go to the current state of that run’s execution – you can always return to old runs and runs in-progress this way. The run you just did should be the more recent entry in the table. For the next analysis, make note of the ID number from your run.

-
-
-

Next steps

-
-
Analyzing model output
-

Follow this tutorial, [Analyze Output] to learn how to open model output in R and compare to observed data

-
-
-
-

DEMO 02

-

[Demo 02: Sensitivity and Uncertainty Analysis] will show how to perform Ensemble & Sensitivity Analyses through the web interface and explore the PEcAn outputs in greater detail, including the trait meta-analysis

-
-
- - - - -
- - - - - - - - - - - - - - - diff --git a/tutorials/Demo02.html b/tutorials/Demo02.html deleted file mode 100644 index 2b575d877..000000000 --- a/tutorials/Demo02.html +++ /dev/null @@ -1,551 +0,0 @@ - - - - - - - - - - - - - -Demo02.utf8 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - -
-

Demo 02: Sensitivity and Uncertainty Analysis

-

In Demo 2 we will be looking at how PEcAn can use information about parameter uncertainty to perform three automated analyses:

-
    -
  • Ensemble Analysis: Repeat numerous model runs, each sampling from the parameter uncertainty, to generate a probability distribution of model projections. Allows us to put a confidence interval on the model
  • -
  • Sensitivity Analysis: Repeats numerous model runs to assess how changes in model parameters will affect model outputs. Allows us to identify which parameters the model is most sensitive to.
  • -
  • Uncertainty Analysis: Combines information about model sensitivity with information about parameter uncertainty to determine the contribution of each model parameter to the uncertainty in model outputs. Allow us to identify which parameters are driving model uncertainty.
  • -
-
-

Run Specification

-
    -
  1. Return to the main menu for the PEcAn web interface: URL > Run Models

  2. -
  3. Repeat the steps for site selection and run specification from Demo 01, but also click on “Advanced setup”, then click Next.

  4. -
  5. By clicking Advanced setup, PEcAn will first show an Analysis Menu, where we are going to specify new settings.

  6. -
-
    -
  • For an ensemble analysis, increase the number of runs in the ensemble, in this case set Runs to 50. In practice you would want to use a larger ensemble size (100-5000) than we are using in the demo. The ensemble analysis samples parameters from their posterior distributions to propagate this uncertainty into the model output.

  • -
  • PEcAn’s sensitivity analysis holds all parameters at their median value and then varies each parameter one-at-a-time based on the quantiles of the posterior distribution. PEcAn also includes a handy shortcut, which is the default behavior for the web interface, that converts a specified standard deviation into its Normal quantile equivalent (e.g. 1 and -1 are converted to 0.157 and 0.841). In this example set Sensitivity to -2,-1,1,2 (the median value, 0, occurs by default).

  • -
  • We also can tell PEcAn which variable to run the sensitivity on. Here, set Variables to NEE, so we can compare against flux tower NEE observations.

  • -
-

Click Next

-
-
-

Additional Outputs:

-

The PEcAn workflow will take considerably longer to complete since we have just asked for over a hundred model runs. Once the runs are complete you will return to the output visualization page were there will be a few new outputs to explore, as well as outputs that were present earlier that we’ll explore in greater details:

-
-
-

Run ID:

-

While the sensitivity and ensemble analyses synthesize across runs, you can also select individual runs from the Run ID menu. You can use the Graphs menu to visualize each individual run, or open individual runs in Shiny

-
-
-

Inputs:

-

This menu shows the contents of /run which lets you look at and download:

-
    -
  1. A summary file (README.txt) describing each run: location, run ID, model, dates, whether it was in the sensitivity or ensemble analysis, variables modifed, etc.
  2. -
  3. The model-specific input files fed into the model
  4. -
  5. The jobs.sh file used to submit the model run
  6. -
-
-
-

Outputs:

-

This menu shows the contents of /out. A number of files generated by the underlying ecosystem model are archived and available for download. These include:

-
    -
  1. Output files in the standardized netCDF ([year].nc) that can be downloaded for visualization and analysis (R, Matlab, ncview, panoply, etc)
  2. -
  3. Raw model output in model-specific format (e.g. sipnet.out).
  4. -
  5. Logfile.txt contains job.sh & model error, warning, and informational messages
  6. -
-
-
-

PFTs:

-

This menu shows the contents of /pft. There is a wide array of outputs available that are related to the process of estimating the model parameters and running sensitivity/uncertainty analyses for a specific Plant Functional Type.

-
    -
  1. TRAITS: The Rdata files trait.data.Rdata and madata.Rdata are, respectively, the available trait data extracted from the database that was used to estimate the model parameters and that same data cleaned and formatted for the statistical code. The list of variables that are queried is determined by what variables have priors associated with them in the definition of the PFTs. Priors are output into prior.distns.Rdata. Likewise, the list of species that are associated with a PFT determines what subset of data is extracted out of all data matching a given variable name. Demo 3 will demonstrate how a PFT can be created or modified. To look at these files in RStudio click on these files to load them into your workspace. You can further examine them in the Environment window or accessing them at the command line. For example, try typing names(trait.data) as this will tell you what variables were extracted, names(trait.data$Amax) will tell you the names of the columns in the Amax table, and summary(trait.data$Amax) will give you summary data about the Amax values.
  2. -
  3. META-ANALYSIS:
  4. -
-
    -
  • *.bug: The evaluation of the meta-analysis is done using a Bayesian statistical software package called JAGS that is called by the R code. For each trait, the R code will generate a [trait].model.bug file that is the JAGS code for the meta-analysis itself. This code is generated on the fly, with PEcAn adding or subtracting the site, treatment, and greenhouse terms depending upon the presence of these effects in the data itself. If the <random.effects> tag is set to FALSE then all random effects will be turned off even if there are multiple sites.
  • -
  • meta-analysis.log contains a number of diagnostics, including the summary statistics of the model, an assessment of whether the posterior is consistent with the prior, and the status of the Gelman-Brooks-Rubin convergence statistic (which is ideally 1.0 but should be less than 1.1).
  • -
  • ma.summaryplots.*.pdf are collections of diagnostic plots produced in R after the above JAGS code is run that are useful in assessing the statistical model. Open up one of these pdfs to evaluate the shape of the posterior distributions (they should generally be unimodal), the convergence of the MCMC chains (all chains should be mixing well from the same distribution), and the autocorrelation of the samples (should be low).
  • -
  • traits.mcmc.Rdata contains the raw output from the statistical code. This includes samples from all of the parameters in the meta-analysis model, not just those that feed forward to the ecosystem, but also the variances, fixed effects, and random effects.
  • -
  • post.distns.Rdata stores a simple tables of the posterior distributions for all model parameters in terms of the name of the distribution and its parameters.
  • -
  • posteriors.pdf provides graphics showing, for each model parameter, the prior distribution, the data, the smoothed histogram of the posterior distribution (labeled post), and the best-fit analytical approximation to that smoothed histogram (labeled approx). Open posteriors.pdf and compare the posteriors to the priors and data
  • -
-
    -
  1. SENSITIVITY ANALYSIS
  2. -
-
    -
  • sensitivity.analysis.[RunID].[Variable].[StartYear].[EndYear].pdf shows the raw data points from univariate one-at-a-time analyses and spline fits through the points. Open this file to determine which parameters are most and least sensitive
  • -
-
    -
  1. UNCERTAINTY ANALYSIS
  2. -
-
    -
  • variance.decomposition.[RunID].[Variable].[StartYear].[EndYear].pdf, contains three columns, the coefficient of variation (normalized posterior variance), the elasticity (normalized sensitivity), and the partial standard deviation of each model parameter. Open this file for BOTH the soil and conifer PFTS and answer the following questions:
  • -
  • The Variance Decomposition graph is sorted by the variable explaining the largest amount of variability in the model output (right hand column). From this graph identify the top-tier parameters that you would target for future constraint.
    -
  • -
  • A parameter can be important because it is highly sensitive, because it is highly uncertain, or both. Identify parameters in your output that meet each of these criteria. Additionally, identify parameters that are highly uncertain but unimportant (due to low sensitivity) and those that are highly sensitive but unimportant (due to low uncertainty).
  • -
  • Parameter constraints could come from further literature synthesis, from direct measurement of the trait, or from data assimilation. Choose the parameter that you think provides the most efficient means of reducing model uncertainty and propose how you might best reduce uncertainty in this process. In making this choice remember that not all processes in models can be directly observed, and that the cost-per-sample for different measurements can vary tremendously (and thus the parameter you measure next is not always the one contributing the most to model variability). Also consider the role of parameter uncertainty versus model sensitivity in justifying your choice of what parameters to constrain.
  • -
-
-
-

PEcAn Files:

-

This menu shows the contents of the root workflow folder that are not in one of the folders indicated above. It mostly contains log files from the PEcAn workflow that are useful if the workflow generates an error, and as metadata & provenance (a detailed record of how data was generated).

-
    -
  1. STATUS gives a summary of the steps of the workflow, the time they took, and whether they were successful
  2. -
  3. pecan.*.xml are PEcAn settings files
  4. -
  5. workflow.R is the workflow script
  6. -
  7. workflow.Rout is the corresponding log file
  8. -
  9. samples.Rdata contains the parameter values used in the runs. This file contains two data objects, sa.samples and ensemble.samples, that are the parameter values for the sensitivity analysis and ensemble runs respectively
  10. -
  11. sensitivity.output.[RunID].[Variable].[StartYear].[EndYear].Rdata contains the object sensitivity.output which is the model outputs corresponding to the parameter values in sa.samples.
  12. -
  13. ENSEMBLE ANALYSIS
  14. -
-
    -
  • ensemble.Rdata contains contains the object ensemble.output, which is the model predictions at the parameter values given in ensemble.samples.
  • -
  • ensemble.analysis.[RunID].[Variable].[StarYear].[EndYear].pdf contains the ensemble prediction as both a histogram and a boxplot.
  • -
  • ensemble.ts.[RunID].[Variable].[StartYear].[EndYear].pdf contains a time-series plot of the ensemble mean, median, and 95% CI
  • -
-
-
-

Global Sensitivity: Shiny

-

Navigate to URL/shiny/global-sensitivity.

-

This app uses the output from the ENSEMBLE runs to perform a global Monte Carlo sensitivity analysis. There are three modes controlled by Output type:

-
    -
  1. Pairwise looks at the relationship between a specific parameter (X) and output (Y)
  2. -
  3. All parameters looks at how all parameters affect a specific output (Y)
  4. -
  5. All variables looks at how all outputs are affected by a specific parameter(X)
  6. -
-

In all of these analyses, the app also fits a linear regression to these scatterplots and reports a number of summary statistics. Among these, the slope is an indicator of global sensitivity and the R2 is an indicator of the contribution to global uncertainty

-
-
-

Next Steps

-

The next set of tutorials will focus on the process of data assimilation and parameter estimation. The next two steps are in “.Rmd” files which can be viewed online.

-
-
-

Assimilation ‘by hand’

-

Explore how model error changes as a function of parameter value (i.e. data assimilation ‘by hand’)

-
-
-

MCMC Concepts

-

Explore Bayesian MCMC concepts using the photosynthesis module

-
-
-

More info about tools, analyses, and specific tasks…

-

Additional information about specific tasks (adding sites, models, data; software updates; etc.) and analyses (e.g. data assimilation) can be found in the PEcAn documentation

-

If you encounter a problem with PEcAn that’s not covered in the documentation, or if PEcAn is missing functionality you need, please search known bugs and issues, submit a bug report, or ask a question in our chat room. Additional questions can be directed to the project manager

-
-
- - - - -
- - - - - - - - - - - - - - -